- A+
elasticsearch 启动流程
启动脚本执行:
org.elasticsearch.bootstrap.Elasticsearch start
如果有-d参数,添加: <&- & 关闭标准输入并后台运行。
主线程执行的启动流程大概做了三部分工作:加载配置、检查外部环境和内部环境、初始化内部资源。最后启动各个子模块和keepalive线程
解析配置
包括命令行参数、主配置文件,log配置文件
启动keepAive线程,初始化运行环境
主线程执行完启动流程后会退出,keepalive线程是唯一的用户线程,作用是保持进程运行,java程序当没有用户线程是进程会退出。
初始化运行环境包括根据解析的配置准备各资源路径,初始化日志系统,创建pid文件,检查es.max-open-files
JVM检测
JVM运行模式检查:client、server,ES对效率要求较高,建议使用server模式,否则打印警告;
JVM版本的检查:如果是Oracle,检查版本对应JVM_OPTS必要参数,如果是IBM,版本要求2.8以上。
系统相关初始化
是否root权限启动:可以调整配置文件运行以root权限启动,但是不建议.
是否使用seccomp模式:linux 2.6.23之后支持的sandboxing机制,让进程运行在“安全模式”,只能执行四种系统调用:read,write,exit,sigreturn,只能使用已打开的fd,如果尝试其他系统调用,内核会使用SIGKILL终止进程。
是否启用mlockall:避免使用swap,建议开启
内部初始化
初始化两种probes:ProcessProbe和OsProbe,提供进程和OS层面的信息
添加shutdown hook,当JVM关闭时调用node.close
jar hell检测:类重复校验
构建node实例:根据设置构建node
ModulesBuilder modules = new ModulesBuilder();
modules.add(new XXXModule(this.settings));
启动系统
调用node.start()启动节点,调用keepAliveThread.start()启动用户线程
加入集群流程
获取集群node列表
在UnicastZenPing构造函数中,向discovery.zen.ping.unicast.hosts配置的节点列表发送请求,获取到DiscoveryNode列表
findMaster
通过UnicastZenPing发送ping,从response信息中找到master,如果没有master,进入选主流程
不同角色执行不同任务
nodeFD是一个Runnable(一个任务),被选为master的时候启动:
onElectedAsMaster()->nodesFD.updateNodesAndPing(state);
masterFD在第一次收到master的cluster state信息的时候启动:
handleNewClusterStateFromMaster()->masterFD.restart();
Transport模块启动流程
节点之间通讯、节点与客户端之间通讯(包括java api和rest api)等所有网络数据传输默认都是transport模块实现的。
transport模块分为LocalTransport和NettyTransport两种,默认是第二种,底层用的是Netty:基于NIO的客户、服务器端编程框架
总体架构:
TransportRequest层有五种类型的请求,在节点之间的TCP长连接上传输,默认情况下,每个节点都会与集群的其他节点保持13个TCP连接,每个连接根据不同类型的业务用作固定的用途。这13个连接分别是:
- recovery 数据恢复使用,默认:2
- bulk 批量请求使用,默认:3
- reg ,默认类型,如:请求加入集群,集群数据同步。默认:6
- state ClusterState信息等,默认:1
- ping ,用作nodeFD或masterFD的ping,默认:1
配置加载
从解析的配置文件中获取:
workerCount
工作线程数,serverBootstrap和clientBootstrap都会创建大小为workerCount的线程池,默认为CPU数量x2,ES5.1之后的版本 限制为最大32.因为在CPU核心数很多的机器上占用非常多内存。
connectionsPerNode
每种请求的连接数
receiveBufferSizePredictorFactory
确定接收缓冲大小。默认最大512k,根据配置的transport.netty.receive_predictor_min和transport.netty.receive_predictor_max确定使用固定大小还是动态大小
启动
根据配置(IP、端口、socket选项等)创建一个ClientBootstrap和若干个ServerBootstrap(都是Netty中的)。然后分别设置各自的PipelineFactory。
PipelineFactory是Netty中的概念,Netty中,Channel是通讯的载体(一个连接),ChannelHandle负责Channel中的处理逻辑,ChannlePipeline可以理解成ChannleHandler的容器,一个Channel包含一个ChannelPipeline,所有ChannelHandler都会注册到ChannelPipeline中。
ServerBootstrap默认构建1个,监听127.0.0.1:9300,可以根据不同请求类型绑定不同地址端口:
节点之间的通讯
transport.profiles.default.port transport.profiles.default.bind_host
client到节点直接的通讯
transport.profiles.client.port transport.profiles.client.bind_host
自动发现数据通讯
transport.profiles.dmz.port transport.profiles.dmz.bind_host
主要流程如下图:
建立到集群其他节点的链接
TCP服务已监听,有哪些客户端会连接进来取决于运行时逻辑。
TCP客户端已准备好,本节点启动过程中,探测到集群的节点信息后, 调用
transportService.connectToNode()->NettyTransport.ConnectToNodes()
连接到其他node,一个连接就是一个Netty中的Channel:
nodeChannels = new NodeChannels(new Channel[connectionsPerNodeRecovery], new Channel[connectionsPerNodeBulk], new Channel[connectionsPerNodeReg], new Channel[connectionsPerNodeState], new Channel[connectionsPerNodePing]);
发送request
sendRequest封装了向节点发送数据的流程。首先根据目标节点和type(上面五种之一)选择一个连接(channle),根据选项看情况压缩数据,通过CompressorFactory.defaultCompressor().streamOutput创建一个带压缩的StreamOutput,写入version和action,写入request,转换成ChannelBuffer,调用targetChannel.write(buffer);发送数据
消息处理
如果某个模块需要监听收到的消息进行处理,他需要调用transportService.registerRequestHandler为不同的action注册不同的handle;如果一个模块要发送请求,他也需要提供一个handle准备处理Response。在NettyTransport类中,依据Netty的ChannelHandle处理机制,两个处理类被注册到Netty的ChannelPipeline中:
SizeHeaderFrameDecoder 负责处理消息头,检查非法请求,去掉头部数据
MessageChannelHandler 负责处理消息体,在messageReceived函数中判断是否需要解压,根据是否request调用handleRequest或handleResponse进行处理。
总体流程:
handleRequest过程:
从收到的数据中解析出action,根据action获取对应的 handle,handle在TransportService.requestHandlers中注册。交给对应的handle处理
handleResponse过程:
根据requestId获取handle,handle在TransportService.clientHandlers中注册。
- 安卓客户端下载
- 微信扫一扫
- 微信公众号
- 微信公众号扫一扫