SolrCloud配置

1、簡介html

Apache Solr是基於Lucene的全文搜索引擎。如何讓Solr具備容錯性和高可用性,SolrCloud能夠幫助咱們搭建集羣,提供分佈式索引,以及自動備份。SolrCloud是Solr的一種分佈式部署方式。它使用Zookeeper做爲集羣的配置信息中心,進行節點的管理。在建立索引時,Solr將索引分散存儲在集羣中,以及備份服務器中。當須要檢索信息時,Solr將查詢的最終結果返回給客戶端。java

SolrCloud具備如下特性:node

  • Solr的整個集羣具備一個配置中心
  • 可以自動進行負載平衡和故障查詢
  • 集成Zookeeper進行集羣的協調和配置

 

2、SolrCloud的基本概念web

SolrCloud包括的核心概念有:Cluster、Node、Collection、Shard、Replica、Core等。apache

一、Cluster集羣json

從邏輯上講,一個Cluster包括一個或者多個Solr Collection;從物理上講,一個Cluster由一個或者多個Solr Nodes。整個集羣必須使用同一套schema和SolrCongfig。windows

二、Node節點api

運行Solr的JVM實例,其中包括了一個或者多個Core。服務器

三、Collectionapp

從邏輯上講,Collection是一個完整的索引,它被劃分紅一個或者多個Shard。若是Shard數量是一個以上的話,那麼使用的索引方案則是分佈式索引。這些Shard使用同一個configset。使用SolrCloud方式部署時,客戶端發送請求時,使用Collection名稱進行操做。這樣客戶端在分佈式檢索時,不用關心相關的Shard參數。

四、Shard分片

Shard是Collection的邏輯分片。一個Shard包含了一個或者以上的Replica。

五、Replica

在Solr文檔中描述:Each Core in a Cluster is a physical Replica for a logical Shard。能夠理解爲,一個Replica就是一個core。一個Shard中有一個或者以上的Replica,當有多個Replica時,zookeeper會選舉一個Replica成爲Leader。當進行檢索時,SolrCloud會將請求發送到Shard對應的Leader,Leader再將請求分到達Shard中的其餘Replica,用以備份。Leader的選舉一般是在Solr的某一個實例發生故障時纔會觸發。

六、Core

在Solr中,一個Core就是一個完整的索引,能夠獨立的提供索引和檢索功能,其配置文件在相應的Core文件夾配置目錄中。在SolrCloud中,一個Core就是一個Replica,其使用的配置都在zookeeper中。

七、Zookeeper

Zookeeper是分佈式服務框架,主要解決分佈式集羣中應用系統的一致性問題,它具備集羣管理、分佈式應用配置配置項的管理、統一命名服務、狀態同步等功能。在SolrCloud中,可使用內嵌的Zookeeper,也能夠用獨立的Zookeeper運行。在搭建Zookeeper集羣時,最好搭建三個以上的奇數個實例。這是由於Zookeeper大多數的操做都是以投票進行。當且僅當一半以上的節點在線時,這個集羣才能保持運行。例如,Zookeeper總共有4個節點,若是保持運行,最多隻能一個節點出現故障。若是總共有3個節點,保持運行,最多也是一個節點出現故障。

【SolrCloud中的Collection圖】

 

 3、SolrCloud配置(zookeeper-3.4.6,solr-5.4.0)

(一)Zookeeper集羣搭建

 一、修改zookeeper的配置文件(<ZOOKEEPER_HOME>/conf/zoo.cfg),添加如下信息:

tickTime=2000

dataDir=D:\\solrcloud\\zookeeper3\\data
clientPort=2181

initLimit=5

syncLimit=2
server.1=localhost:2888:3888 server.2=localhost:2889:3889 server.3=localhost:2890:3890
  • tickTime:這個時間是做爲 Zookeeper 服務器之間維持心跳的時間間隔(以毫秒爲單位),也就是每一個 tickTime 時間就會發送一個心跳。
  • dataDir:Zookeeper存放數據的目錄。在默認狀況下,這個目錄也是Zookeeper保存寫數據的日誌文件。在搭建Zookeeper集羣時,這個目錄也是存放節點ID文件(myid)的地方。
  • clientPort:客戶端鏈接Zookeeper服務器的端口,Zookeeper會監聽這個端口,接受客戶端的訪問請求。
  • initLimit:初始化鏈接時最長能忍受的的心跳時間間隔數。例如:在本例中,當超過5個心跳時間(總時間:5*2000=10s),若Zookeeper集羣中的Leader服務器尚未收到Follower服務器的返回信息,則代表鏈接失敗。
  • syncLimit:Leader和Follower之間通訊的時間長度不能超過2個心跳時間(總時間:2*2000=4s)
  • server.A=B:C:D:

    A:表示Zookeeper服務器編號(Id)。注意,此Id與myid文件中的編號要一致,Id的範圍是1-255的整數myid文件放在【dataDir】下。

    B:服務器ip地址

    C:這個服務器與集羣中的Leader服務器交換信息的端口

    D:選舉Leader服務器時的通訊端口。若是Leader服務器發生故障掛了,新Leader的選舉在這個端口進行。

    (本文中,搭建的是僞集羣,所以B是相同的,通訊端口不能同樣。)

分別在zookeeper的其餘兩個實例中,按照上述配置修改zoo.cfg文件。

二、分別運行服務。

cd <ZOOKEEPER1_HOME>
bin\zkServer.cmd

cd <ZOOKEEPER2_HOME>
bin\zkServer.cmd

cd <ZOOKEEPER3_HOME>
bin\zkServer.cmd

當這些配置項配置好後,你如今就能夠啓動 Zookeeper 了,啓動後要檢查 Zookeeper 是否已經在服務,能夠經過 netstat – ano 命令查看是否有你配置的 clientPort 端口號在監聽服務。

還能夠經過「bin/zkServer.sh status」命令查看狀態,不過在windows上,zkServer.cmd跟參數時會報錯,只能在Linux的環境上操做了。

(二)SolrCloud配置

一、建立節點

建立節點目錄。例如<SOLR_HOME>/example/cloud/node1/solr。一種方式是:在該目錄下,添加solr.xml文件。

另外一種是將solr.xml上傳至zookeeper服務器方式:使用solr-core裏的ZkCLI工具。

java -classpath <SOLR_HOME>/server/solr-webapp/webapp/WEB-INF/lib/* org.apache.solr.cloud.ZkCLI -zkhost localhost:2181,localhost:2182,localhost:2183 -cmd putfile /solr.xml <SOLR_HOME>/server/solr/solr.xml

putfile後,第一個參數是:zookeeper集羣上的存儲路徑,第二個參數是:要上傳文件的本地路徑;若是zookeeper集羣中該文件已存在,則會報錯,不能覆蓋。(查詢zkcli相關參數設置:https://cwiki.apache.org/confluence/display/solr/Command+Line+Utilities)

我的更喜歡第二種方式。第一種方式,每建立一個節點,須要添加一個solr.xml文件,這樣的方式不利於集羣的管理。第二種方式是將這個文件上傳到Zookeeper中統一管理,無需多上傳。

測試搭建的是僞集羣,在【cloud】文件夾下,建立了node2, node3兩個節點

二、將建立的節點註冊到zookeeper的/live_nodes目錄下

bin\solr.cmd start -cloud -s example\cloud\node1\solr -p 8981 -z "localhost:2181,localhost:2182,localhost:2183"

bin\solr.cmd start -cloud -s example\cloud\node2\solr -p 8982 -z "localhost:2181,localhost:2182,localhost:2183"

bin\solr.cmd start -cloud -s example\cloud\node3\solr -p 8983 -z "localhost:2181,localhost:2182,localhost:2183"

當以上命令不能獲取正確的IP時(例如solr節點部署在虛擬機上等狀況),能夠在命令中加入[-h host]參數,指定ip。(查詢啓動solr的相關參數設置:bin\solr.cmd start -help

在將建立的節點註冊到zookeeper以後,本機會從zookeeper中更新集羣狀態信息,保持信息一致。zookeeper中會在overseer_elect/election中新建一個節點,爲Leader選舉作準備。若是第一個在集羣中建立的solr服務,該節點註冊以後,在zookeeper會建立/overseer_elect/leader。

在啓動Solr以後,solr cloud中的樹形目錄以下:

三、上傳configs到zookeeper

有兩種方式能夠將configs文件上傳到zookeeper,即ZkCLI工具或者SolrJ。

(1)使用solr-core裏的ZkCLI工具。

java -classpath <SOLR_HOME>/server/solr-webapp/webapp/WEB-INF/lib/* org.apache.solr.cloud.ZkCLI -zkhost localhost:2181,localhost:2182,localhost:2183 -cmd upconfig -confname my_dih_conf -confdir <SOLR_HOME>\server\solr\configsets\my_dih_configs\conf

upconfig後,第一個參數是:zookeeper集羣上的configs名稱,第二個參數是:要上傳conf的本地路徑;

(2)使用SolrJ

調用CloudSolrClient.uploadConfig方法

(ConfigSets API能夠對zookeeper服務器中的configset進行管理,API接口詳細說明:https://cwiki.apache.org/confluence/display/solr/ConfigSets+API)

solr配置文件上傳後,如圖:

(4)建立Collection

對Collection的操做能夠直接使用Solr Collections API,詳細說明:https://cwiki.apache.org/confluence/display/solr/Collections+API (也可使用SolrJ的方式)

http://localhost:8981/solr/admin/collections?action=CREATE&name=mycollection&router.name=implicit&shards=shard1,shard2&replicationFactor=3&maxShardsPerNode=3&createNodeSet=192.168.85.187:8981_solr,192.168.85.187:8982_solr,192.168.85.187:8983_solr&collection.configName=my_dih_conf

到此,solrcloud的搭建完成。經過http://localhost:8981/solr/admin/collections?action=clusterstatus&wt=json能夠查詢solr集羣的狀態。或者經過solrcloud查詢,如圖:

從圖中能夠看出,在shard1中,8983端口的solr服務爲主節點;在shard2中8981端口的solr服務爲主節點。

(5)測試

本文使用的config爲DIH的配置方式。在任意一個solr服務器上建立索引以後,都會自動同步到另外兩個solr服務器。

使用url進行數據訪問:http://localhost:8981/solr/mycollection/select?q=*%3A*&wt=json&indent=true

經過SolrJ檢索:

maven配置:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test</groupId>
    <artifactId>test</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.solr</groupId>
            <artifactId>solr-solrj</artifactId>
            <version>6.2.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

SolrJ查詢:

public static void main(String[] args) {
        CloudSolrClient client = null;
        try {
            CloudSolrClient.Builder builder = new CloudSolrClient.Builder();
            builder.withZkHost("localhost:2181,localhost:2182,localhost:2183");
            client = builder.build();
            client.setDefaultCollection("mycollection");
            client.setZkClientTimeout(20000);
            client.setZkConnectTimeout(1000);
            client.setParser(new XMLResponseParser());
            client.connect();
            System.out.println("-------------connected!");

            //Indexing(建立索引,能夠用SolrInputDocument對象或者實體類建立對象。實例中的SocialContactEntity類與業務相關,繼承BaseSolrEntity)
            String queryString = "test@1234";
            SocialContactEntity entity = new SocialContactEntity();
            entity.setUuid(UUID.randomUUID().toString());
            entity.setName("test");
            entity.setName_standard("test-standard");
            entity.setAccount(queryString);
            client.addBean(entity);
            client.commit();//提交修改
            System.out.println("-------------save success!");

            //query
            SolrQuery query = new SolrQuery();
            query.set("q", "account:" + queryString);
            QueryResponse response = client.query(query);
            SolrDocumentList list = response.getResults();
            Iterator iterator = list.iterator();
            while (iterator.hasNext()) {
                Map contactEntity = (Map) iterator.next();
                System.out.println("-------------entity:" + contactEntity.get("account"));
            }
            client.close();
            System.out.println("-----------END");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } finally {
            if (client != null) {
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

輸出結果:

 

 參考文獻:

http://josh-persistence.iteye.com/blog/2234411

http://www.cnblogs.com/shanyou/p/3221990.html

https://cwiki.apache.org/confluence/display/solr/SolrCloud

相關文章
相關標籤/搜索