elasticsearch源碼分析及插件開發


ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分布式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並作為Apache許可條款下的開放源碼發布,是當前流行的企業級搜索引擎。ES能提供強大的索引能力,很大一方面原因是由多個分布在不同機器的es實例組成集群對外提供服務,這種可以橫向擴展的機制可以極大提升服務能力。每一個es實例都是基於Lucene的獨立服務,負責本地分片上數據的索引和查詢,如果掌握了ES的是實現細節,就會對es所具有的特性有一個本質的認識。

我們會先基於ES2.3.2源碼來理清楚ES的啟動流程,然后介紹下ES節點(Node)的內部結構,最后再分析下ES插件機制並舉一個安全插件的開發示例。

1.ES節點啟動流程

org.elasticsearch.Elasticsearch.main
org.elasticsearch.bootstrap
{
    啟動用戶線程keepAliveThread
    導入環境變量和配置參數
    創建pid文件
    檢查(jvm環境,安全、等等)
    nodeBuilder.build()
    node.start();
    keepAliveThread.start();
}

2.Node啟動

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加載各個模塊,啟動各個服務。

先說一下插件加載過程。每個node在加載各個模塊前,會首先加載所需要的插件,如果有些插件加載不成功node會啟動失敗。這里會加載三類插件:首先是配置插件,配置到節點配置文件中插件,如分詞插件等;然后查找classpath中能找到的插件,這些插件一般防止在plugin文件夾中;最后是加載site插件,site插件是不涉及java代碼的純網站式插件,如監控插件head,bigdesk等。任何使用者都可以開發自己需要的插件,只要按着elasticsearch相關版本的插件開發規范來實現即可。接下來首先說一下啟動各個模塊的過程。elasticsearch各個功能模塊實現的非常好,解耦非常完美,很多模塊都實現了生命周期接口,只有啟動它才能夠對外提供服務,它的啟動過程也是功能模塊初始化的過程。因此,node節點的啟動過程也就是這些模塊初始化的過程。

@2.1 構造pluginsService並動態加載plugin

依次調用各插件的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());
}
 

 @2.2啟動各項服務

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();

@2.3 用於集群內節點間通信的引擎

基於netty實現的tcp引擎 NettyTransport 來構造客戶端BootStrap,用於和其它ES節點間的通信。如果是server模式,還要啟動ServerBootstrap用於接收其它客戶端發來的請求

public class NettyTransport extends AbstractLifecycleComponent<Transport> implements Transport

 

@2.4 發現功能

發現功能主要用於節點啟動后發現集群,master向所有節點發布集群狀態,選舉master節點並引發集群節點變得事件

@2.5 對外提供http服務的引擎

使用netty實現的 http 引擎 
public class NettyHttpServerTransport extends AbstractLifecycleComponent<HttpServerTransport> implements HttpServerTransport

 

 

 3.ES實例退出

shutdownhook觸發
node.close,停止各種服務、插件、腳本、線程池
CountDownLatch減一,keepAliveThread退出
刪除pid文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM