Elasticsearch
elasticsearch集群搭建
elasticsearch集群使用docker 搭建
1.修改系统配置文件
#修改线程数
#单个进程中的最大线程数
vim /etc/sysctl.conf
vm.max_map_count=262144
# 刷新配置 使其立即生效配置
2.创建elasticsearch配置文件
创建三个节点,即三个文件夹都放入elasticsearch.yml ;jvm.options配置文件
elasticsearch配置文件elasticsearch.yml参数详细说明
/wz/elasticsearch/es-cluster/node01
/wz/elasticsearch/es-cluster/node02/data2
/wz/elasticsearch/es-cluster/node03
#顺便都创建一个data文件夹存放elasticsearch的数据
madir /wz/elasticsearch/es-cluster/node01/data1
madir /wz/elasticsearch/es-cluster/node01/data1
madir /wz/elasticsearch/es-cluster/node01/data1
在各个文件夹下放入对应的elasticsearch.yml ;jvm.options 文件
node1配置
cd /wz/elasticsearch/es-cluster/node01
vim elasticsearch.yml
# node1(master) 的yml配置文件
cluster.name: es-tanhua-cluster #集群名称,相同网络下相同的集群名的节点为一个集群
node.name: es-node01 #节点名称,若未指定,将随机分配
#cluster.initial_master_nodes: es-node1
network.bind_host: 0.0.0.0 #设置绑定的ip地址,可以是ipv4或ipv6的,默认为0.0.0.0。
network.publish_host: 自己的ip #设置与其他节点通信的地址,如果不指定,其将自动生成.这个地址必须是实际的IP地址
node.master: true #是否指定当前节点为master节点
transport.tcp.port: 9301 #端口
node.data: true #是否允许该节 点存储数据
network.host: 自己的ip #这个参数是用来同时设置bind_host和publish_host上面两个参数。
http.port: 9201 #设置对外服务的http端口,默认为9200
discovery.zen.ping.unicast.hosts: ["ip"] #设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。
discovery.zen.minimum_master_nodes: 2 #设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)
http.cors.enabled: true
http.cors.allow-origin: "*"
jvm.options
-Xms129m
-Xmx128m
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+AlwaysPreTouch
-Xss1m
-Djava.awt.headless=true
-Dfile.encoding=UTF-8
-Djna.nosys=true
-XX:-OmitStackTraceInFastThrow
-Dio.netty.noUnsafe=true
-Dio.netty.noKeySetOptimization=true
-Dio.netty.recycler.maxCapacityPerThread=0
-Dlog4j.shutdownHookEnabled=false
-Dlog4j2.disable.jmx=true
-Djava.io.tmpdir=${ES_TMPDIR}
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data
-XX:ErrorFile=logs/hs_err_pid%p.log
8:-XX:+PrintGCDetails
8:-XX:+PrintGCDateStamps
8:-XX:+PrintTenuringDistribution
8:-XX:+PrintGCApplicationStoppedTime
8:-Xloggc:logs/gc.log
8:-XX:+UseGCLogFileRotation
8:-XX:NumberOfGCLogFiles=32
node1节点完成
node2,node3 节点步骤同上 但是elasticsearch.yml 配置文件不同
node2配置
node2.elasticsearch.yml
cluster.name: es-tanhua-cluster
node.name: es-node02
# cluster.initial_master_nodes: es-node1
network.bind_host: 0.0.0.0
transport.tcp.port: 9302
node.master: true
node.data: true
network.host: 自己的ip
http.port: 9202
discovery.zen.ping.unicast.hosts: ["masterIp"]
discovery.zen.minimum_master_nodes: 2
http.cors.enabled: true
http.cors.allow-origin: "*"
node.max_local_storage_nodes: 256
jvm.options
-Xms129m
-Xmx128m
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+AlwaysPreTouch
-Xss1m
-Djava.awt.headless=true
-Dfile.encoding=UTF-8
-Djna.nosys=true
-XX:-OmitStackTraceInFastThrow
-Dio.netty.noUnsafe=true
-Dio.netty.noKeySetOptimization=true
-Dio.netty.recycler.maxCapacityPerThread=0
-Dlog4j.shutdownHookEnabled=false
-Dlog4j2.disable.jmx=true
-Djava.io.tmpdir=${ES_TMPDIR}
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data
-XX:ErrorFile=logs/hs_err_pid%p.log
8:-XX:+PrintGCDetails
8:-XX:+PrintGCDateStamps
8:-XX:+PrintTenuringDistribution
8:-XX:+PrintGCApplicationStoppedTime
8:-Xloggc:logs/gc.log
8:-XX:+UseGCLogFileRotation
8:-XX:NumberOfGCLogFiles=32
node3配置
node3.elasticsearch.yml
cluster.name: es-tanhua-cluster
#cluster.initial_master_nodes: es-node1
node.name: es-node03
node.master: true
node.data: true
network.bind_host: 0.0.0.0
network.host: 自己的ip
http.port: 9203
discovery.zen.ping.unicast.hosts: ["node1的ip:9301","node2的ip:9302","node3的ip:9303"]
discovery.zen.minimum_master_nodes: 2
http.cors.enabled: true
http.cors.allow-origin: "*"
jvm.options
-Xms129m
-Xmx128m
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+AlwaysPreTouch
-Xss1m
-Djava.awt.headless=true
-Dfile.encoding=UTF-8
-Djna.nosys=true
-XX:-OmitStackTraceInFastThrow
-Dio.netty.noUnsafe=true
-Dio.netty.noKeySetOptimization=true
-Dio.netty.recycler.maxCapacityPerThread=0
-Dlog4j.shutdownHookEnabled=false
-Dlog4j2.disable.jmx=true
-Djava.io.tmpdir=${ES_TMPDIR}
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=data
-XX:ErrorFile=logs/hs_err_pid%p.log
8:-XX:+PrintGCDetails
8:-XX:+PrintGCDateStamps
8:-XX:+PrintTenuringDistribution
8:-XX:+PrintGCApplicationStoppedTime
8:-Xloggc:logs/gc.log
8:-XX:+UseGCLogFileRotation
8:-XX:NumberOfGCLogFiles=32
三个节点的配置配件准备完毕!
3.拉取docker elasticsearch镜像
# docker pull elasticsearch : 版本
docker pull elasticsearch : 6.5.4
# 查看
docker images
4.创建容器
#node1
docker create --name es-node01 --net host -v /wz/elasticsearch/es-cluster/node01/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /wz/elasticsearch/es-cluster/node01/jvm.options:/usr/share/elasticsearch/config/jvm.options -v /wz/elasticsearch/es-cluster/node01/data1:/usr/share/elasticsearch/data elasticsearch:6.5.4
#node2
docker create --name es-node02 --net host -v /wz/elasticsearch/es-cluster/node02/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /wz/elasticsearch/es-cluster/node02/jvm.options:/usr/share/elasticsearch/config/jvm.options -v /wz/elasticsearch/es-cluster/node02/data2:/usr/share/elasticsearch/data elasticsearch:6.5.4
#node3
docker create --name es-node03 --net host -v /wz/elasticsearch/es-cluster/node03/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /wz/elasticsearch/es-cluster/node03/jvm.options:/usr/share/elasticsearch/config/jvm.options -v /wz/elasticsearch/es-cluster/node03/data3:/usr/share/elasticsearch/data elasticsearch:6.5.4
docker 挂载参数解释
docker create --name 容器名 --net host -v 配置文件elasticsearch.yml的地址:/usr/share/elasticsearch/config/elasticsearch.yml -v jvm.options文件的地址:/usr/share/elasticsearch/config/jvm.options -v 数据存放data文件夹地址:/usr/share/elasticsearch/data 拉取的elasticsearch及版本(如果多个不同版本的elasticsearch可以用image id代替)
5.启动容器
集群启动
#三个节点一起启动容器
docker start es-node01 es-node02 es-node03
# 查看容器日志
#docker logs 容器名/imges id
docker logs es-node1
单节点启动
#或单个启动并查看日志
docker start es-node01 && docker logs -f es-node01
docker start es-node02 && docker logs -f es-node02
docker start es-node03 && docker logs -f es-node03
6.验证
1.查看 elasticsearch 各个节点
elasticsearch进行外部访问的端口为 92xx(自己在elasticsearch.yml绑定的)没有默认为 9200,elasticsearch内部通信的端口为:93xx (自己在elasticsearch.yml绑定的)没有默认为 9300可以在浏览器上各个节点进行ip+端口(92xx的端口)进行访问
验证elasticsearch集群,在浏览器输入http://es ip地址:端口/_cat/nodes?pretty,就可以看到集群启动成功了:
例如:http://192.168.2.223:9202/_cat/nodes?pretty
无论集群的哪个几点下访问都行,如图:
如果如上图则elasticsearch集群搭建完毕!
elasticsearch集成spring boot
1.添加依赖
注意:elasticsearch 的版本要和spring boot 保持一致 推荐使用maven给的版本,冲突几率小
如果是项目中 还集成了 redis 三者(elasticsearch,boot ,redsi)应保持同一版本
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
2.配置yml
data:
elasticsearch:
cluster-name: es-tanhua-cluster #elasticsearch集群名
cluster-nodes: 1.15.134.32:9301,1.15.134.32:9302,1.15.134.32:9303 #elasticsearch集群各个节点
repositories:
enabled: false #是否本地存储数据
3.使用
实体类使用
service 使用
@Slf4j
@Service(version = "2.6.4",interfaceClass = UserLocationApi.class)
public class UserLocationApiImpl implements UserLocationApi {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
//初始化索引库
@PostConstruct
public void initIndex() {
// System.setProperty("es.set.netty.runtime.available.processors","false");
String indexName = "tanhua";
//判断索引库是否存在
// boolean b = this.elasticsearchTemplate.indexExists(indexName);
// System.out.println(b);
if (!this.elasticsearchTemplate.indexExists(indexName)) {
this.elasticsearchTemplate.createIndex(UserLocation.class);
}
// boolean user_location = this.elasticsearchTemplate.typeExists(indexName, "user_location");
// System.out.println(user_location);
//判断表是否存在 如果不存在 则创建
if (!this.elasticsearchTemplate.typeExists(indexName, "user_location")) {
this.elasticsearchTemplate.putMapping(UserLocation.class);
}
}
/**
* 更新地理位置
*
* @param userId 用户id
* @param longitude 经度
* @param latitude 纬度
* @param address 地址名称
* @return
*/
@Override
public Boolean updateUserLocation(Long userId, Double longitude, Double latitude, String address) {
//首先根据id查询个人地理位置
GetQuery getQuery = new GetQuery();
getQuery.setId(Convert.toStr(userId));
UserLocation userLocation = this.elasticsearchTemplate.queryForObject(getQuery, UserLocation.class);
//如果不存在则添加 存在则更新
if (ObjectUtil.isEmpty(userLocation)) {
userLocation = new UserLocation();
userLocation.setUserId(userId);
userLocation.setAddress(address);
userLocation.setLocation(new GeoPoint(latitude, longitude));
userLocation.setCreated(System.currentTimeMillis());
userLocation.setUpdated(userLocation.getCreated());
userLocation.setLastUpdated(userLocation.getCreated());
return this.saveUserLocation(userLocation);
}else {
//更新数据
userLocation.setLocation(new GeoPoint(latitude, longitude));
userLocation.setAddress(address);
return this.updateLocation(userLocation); //更新
}
}
public boolean saveUserLocation(UserLocation user) {
IndexQuery indexQuery = new IndexQueryBuilder().withObject(user).build();
//保存数据到ES中
String index = this.elasticsearchTemplate.index(indexQuery);
if (ObjectUtil.isEmpty(index)) return false;
return true;
}
public boolean updateLocation(UserLocation user) {
if (ObjectUtil.isEmpty(user))return false;
HashMap<String, Object> map = new HashMap<>();
//更新的字段
map.put("location", user.getLocation());
map.put("updated", System.currentTimeMillis());
map.put("lastUpdated", user.getUpdated());
map.put("address", user.getAddress());
try {
UpdateRequest request = new UpdateRequest();
request.doc(map);
UpdateQuery query = new UpdateQueryBuilder().withId(Convert.toStr(user.getUserId())).withClass(UserLocation.class).withUpdateRequest(request).build();
//更新数据
this.elasticsearchTemplate.update(query);
} catch (Exception e) {
log.error("更新地理位置失败~ userId = " + user.getUserId() + ", longitude = " + user.getLocation().getLon() + ", latitude = " + user.getLocation().getLat() + ", address = " + user.getAddress(), e);
return false;
}
return true;
}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class testES {
@Autowired
private UserLocationApiImpl userLocationApi;
// 单元测试需要加这个 原因:在下面不加会报错
public testES() {
System.setProperty("es.set.netty.runtime.available.processors", "false");
}
@Test
public void testUpdateUserLocation() {
Boolean aa = this.userLocationApi.updateUserLocation(1L, 121.512253, 31.24094, "金茂大厦");
System.out.println(aa);
}
}
elasticsearch添加会返回一个id 可以访问查看
打开浏览器: http://自己的ip:端口/分区/类型/id
例如:http://192.168.2.32:9201/tanhua/user_location/1
4.可能遇到的错误
4.1创建elasticsearchClient bean失败
报错为:org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘elasticsearchClient’ defined in class path resource [org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.elasticsearch.client.transport.TransportClient]: Factory method ‘elasticsearchClient’ threw exception; nested exception is java.lang.IllegalStateException: availableProcessors is already set to [12], rejecting [12]
原因好像是 es 内置的netty冲突和redis内置的netty版本冲突导致,建议尽量版本保持一致由maven管理
解决方案:
-
创建一个配置类:
import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; @Configuration public class ESconfig { @PostConstruct // @PostConstruct是Java自带的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。 void init() { // 不要查es 的netty System.setProperty("es.set.netty.runtime.available.processors", "false"); } }
-
启动类上加
// @EnableDubbo
@SpringBootApplication//(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) //排除mongo的自动配置
public class ESApplication {
public static void main(String[] args) {
//不要查es 的netty
System.setProperty("es.set.netty.runtime.available.processors","false");
SpringApplication.run(ESApplication.class, args);
}
}