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