ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分佈式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並做爲Apache許可條款下的開放源碼發佈,是當前流行的企業級搜索引擎。ES能提供強大的索引能力,很大一方面緣由是由多個分佈在不一樣機器的es實例組成集羣對外提供服務,這種能夠橫向擴展的機制能夠極大提高服務能力。每個es實例都是基於Lucene的獨立服務,負責本地分片上數據的索引和查詢,若是掌握了ES的是實現細節,就會對es所具備的特性有一個本質的認識。java
咱們會先基於ES2.3.2源碼來理清楚ES的啓動流程,而後介紹下ES節點(Node)的內部結構,最後再分析下ES插件機制並舉一個安全插件的開發示例。node
org.elasticsearch.Elasticsearch.main
org.elasticsearch.bootstrap
{
啓動用戶線程keepAliveThread
導入環境變量和配置參數
建立pid文件
檢查(jvm環境,安全、等等)
nodeBuilder.build()
node.start();
keepAliveThread.start();
}
Node() { 更新setting和environment 構造pluginsService並動態加載plugin @2.1 加載並初始化modules(PluginsModule/ClusterModule/RestModule/TransportModule/ActionModule等) 使用guice構造各modules 構造client對象(performing actions/operations against the cluster } Node start() { 構造services和plugins實例。 @2.2 TransportService啓動 @2.3 DiscoveryService啓動 @2.4 HttpServerTransport綁定地址,開始監聽 @2.5 }
能夠看到node的初始化過程主要包括三部分,第一是配置node環境,第二是啓動插件服務(es提供了插件功能來進行擴展功能,這也是它的一個亮點),加載須要的插件,最後就是經過guice加載各個模塊,啓動各個服務。web
先說一下插件加載過程。每一個node在加載各個模塊前,會首先加載所須要的插件,若是有些插件加載不成功node會啓動失敗。這裏會加載三類插件:首先是配置插件,配置到節點配置文件中插件,如分詞插件等;而後查找classpath中能找到的插件,這些插件通常防止在plugin文件夾中;最後是加載site插件,site插件是不涉及java代碼的純網站式插件,如監控插件head,bigdesk等。任何使用者均可以開發本身須要的插件,只要按着elasticsearch相關版本的插件開發規範來實現便可。接下來首先說一下啓動各個模塊的過程。elasticsearch各個功能模塊實現的很是好,解耦很是完美,不少模塊都實現了生命週期接口,只有啓動它纔可以對外提供服務,它的啓動過程也是功能模塊初始化的過程。所以,node節點的啓動過程也就是這些模塊初始化的過程。bootstrap
依次調用各插件的OnModule方法。在OnModule方法內部能夠針對多種model來依次操做,好比下面的添加過濾器或者替換TransportService。安全
爲RestModule添加一個過濾器; public void onModule(RestModule module) {module.addRestAction(AuthorityRestFilter.class);}
爲actionModels添加自定義過濾器AuthorityActionFilter; public void onModule(final ActionModule module) {module.registerFilter(AuthorityActionFilter.class);}
使用自定義AuthorityTransportService來代替默認的TransportService; public void onModule(final TransportModule module) { module.setTransportService(AuthorityTransportService.class, name()); }
for (Class<? extends LifecycleComponent> plugin : pluginsService.nodeServices()) { injector.getInstance(plugin).start();// 加載插件中的自定義服務並啓動 } //經過guice獲取各個模塊的service接口並啓動 injector.getInstance(MappingUpdatedAction.class).setClient(client); injector.getInstance(IndicesService.class).start(); injector.getInstance(IndexingMemoryController.class).start(); injector.getInstance(IndicesClusterStateService.class).start(); injector.getInstance(IndicesTTLService.class).start(); injector.getInstance(SnapshotsService.class).start(); injector.getInstance(SnapshotShardsService.class).start(); injector.getInstance(RoutingService.class).start(); injector.getInstance(SearchService.class).start(); injector.getInstance(MonitorService.class).start(); injector.getInstance(RestController.class).start(); // TODO hack around circular dependencies problems injector.getInstance(GatewayAllocator.class).setReallocation(injector.getInstance(ClusterService.class), injector.getInstance(RoutingService.class)); injector.getInstance(ResourceWatcherService.class).start(); injector.getInstance(GatewayService.class).start();
基於netty實現的tcp引擎 NettyTransport 來構造客戶端BootStrap,用於和其它ES節點間的通訊。若是是server模式,還要啓動ServerBootstrap用於接收其它客戶端發來的請求服務器
public class NettyTransport extends AbstractLifecycleComponent<Transport> implements Transport
發現功能主要用於節點啓動後發現集羣,master向全部節點發布集羣狀態,選舉master節點並引起集羣節點變得事件app
使用netty實現的 http 引擎
public class NettyHttpServerTransport extends AbstractLifecycleComponent<HttpServerTransport> implements HttpServerTransport
shutdownhook觸發 node.close,中止各類服務、插件、腳本、線程池 CountDownLatch減一,keepAliveThread退出 刪除pid文件