1. 什么是SolrCloud
1.1. 什么是SolrCloud
? ? ? ? ? ??SolrCloud(solr 云)是Solr提供的分布式搜索方案,當你需要大規模,容錯,分布式索引和檢索能力時使用SolrCloud。當一個系統的索引數據量少的時候是不需要使用SolrCloud的,當索引量很大,搜索請求并發很高,這時需要使用SolrCloud來滿足這些需求。
? ? ? ? SolrCloud是基于Solr和Zookeeper的分布式搜索方案,它的主要思想是使用Zookeeper作為集群的配置信息中心。
? ? ? ? 它有幾個特色功能:
? ? ? ? 1)集中式的配置信息
? ? ? ? 2)自動容錯
? ? ? ? 3)近實時搜索
? ? ? ? 4)查詢時自動負載均衡
1.1.1.??zookeeper是個什么玩意?
? ? ? ? 顧名思義zookeeper就是動物園管理員,他是用來管hadoop(大象)、Hive(蜜蜂)、pig(小豬)的管理員, Apache Hbase和 Apache Solr 的分布式集群都用到了zookeeper;Zookeeper:是一個分布式的、開源的程序協調服務,是hadoop項目下的一個子項目。
1.1.2.??Zookeeper可以干哪些事情
1、配置管理
? ? ? ?在我們的應用中除了代碼外,還有一些就是各種配置。比如數據庫連接等。一般我們都是使用配置文件的方式,在代碼中引入這些配置文件。但是當我們只有一種配置,只有一臺服務器,并且不經常修改的時候,使用配置文件是一個很好的做法,但是如果我們配置非常多,有很多服務器都需要這個配置,而且還可能是動態的話使用配置文件就不是個好主意了。這個時候往往需要尋找一種集中管理配置的方法,我們在這個集中的地方修改了配置,所有對這個配置感興趣的都可以獲得變更。比如我們可以把配置放在數據庫里,然后所有需要配置的服務都去這個數據庫讀取配置。但是,因為很多服務的正常運行都非常依賴這個配置,所以需要這個集中提供配置服務的服務具備很高的可靠性。一般我們可以用一個集群來提供這個配置服務,但是用集群提升可靠性,那如何保證配置在集群中的一致性呢?這個時候就需要使用一種實現了一致性協議的服務了。Zookeeper就是這種服務,它使用Zab這種一致性協議來提供一致性。現在有很多開源項目使用Zookeeper來維護配置,比如在HBase中,客戶端就是連接一個Zookeeper,獲得必要的HBase集群的配置信息,然后才可以進一步操作。還有在開源的消息隊列Kafka中,也使用Zookeeper來維護broker的信息。在Alibaba開源的SOA框架Dubbo中也廣泛的使用Zookeeper管理一些配置來實現服務治理。
2、名字服務
? ? ? ?名字服務這個就很好理解了。比如為了通過網絡訪問一個系統,我們得知道對方的IP地址,但是IP地址對人非常不友好,這個時候我們就需要使用域名來訪問。但是計算機是不能是別域名的。怎么辦呢?如果我們每臺機器里都備有一份域名到IP地址的映射,這個倒是能解決一部分問題,但是如果域名對應的IP發生變化了又該怎么辦呢?于是我們有了DNS這個東西。我們只需要訪問一個大家熟知的(known)的點,它就會告訴你這個域名對應的IP是什么。在我們的應用中也會存在很多這類問題,特別是在我們的服務特別多的時候,如果我們在本地保存服務的地址的時候將非常不方便,但是如果我們只需要訪問一個大家都熟知的訪問點,這里提供統一的入口,那么維護起來將方便得多了。
3、分布式鎖
? ? ? ?其實在第一篇文章中已經介紹了Zookeeper是一個分布式協調服務。這樣我們就可以利用Zookeeper來協調多個分布式進程之間的活動。比如在一個分布式環境中,為了提高可靠性,我們的集群的每臺服務器上都部署著同樣的服務。但是,一件事情如果集群中的每個服務器都進行的話,那相互之間就要協調,編程起來將非常復雜。而如果我們只讓一個服務進行操作,那又存在單點。通常還有一種做法就是使用分布式鎖,在某個時刻只讓一個服務去干活,當這臺服務出問題的時候鎖釋放,立即fail over到另外的服務。這在很多分布式系統中都是這么做,這種設計有一個更好聽的名字叫Leader Election(leader選舉)。比如HBase的Master就是采用這種機制。但要注意的是分布式鎖跟同一個進程的鎖還是有區別的,所以使用的時候要比同一個進程里的鎖更謹慎的使用。
4、集群管理
? ? ? ?在分布式的集群中,經常會由于各種原因,比如硬件故障,軟件故障,網絡問題,有些節點會進進出出。有新的節點加入進來,也有老的節點退出集群。這個時候,集群中其他機器需要感知到這種變化,然后根據這種變化做出對應的決策。比如我們是一個分布式存儲系統,有一個中央控制節點負責存儲的分配,當有新的存儲進來的時候我們要根據現在集群目前的狀態來分配存儲節點。這個時候我們就需要動態感知到集群目前的狀態。還有,比如一個分布式的SOA架構中,服務是一個集群提供的,當消費者訪問某個服務時,就需要采用某種機制發現現在有哪些節點可以提供該服務(這也稱之為服務發現,比如Alibaba開源的SOA框架Dubbo就采用了Zookeeper作為服務發現的底層機制)。還有開源的Kafka隊列就采用了Zookeeper作為Cosnumer的上下線管理。
1.2. SolrCloud結構
? ? ? ? SolrCloud為了降低單機的處理壓力,需要由多臺服務器共同來完成索引和搜索任務。實現的思路是將索引數據進行Shard(分片)拆分,每個分片由多臺的服務器共同完成,當一個索引或搜索請求過來時會分別從不同的Shard的服務器中操作索引。
? ? ? ? SolrCloud需要Solr基于Zookeeper部署,Zookeeper是一個集群管理軟件,由于SolrCloud需要由多臺服務器組成,由zookeeper來進行協調管理。
下圖是一個SolrCloud應用的例子:
對上圖進行圖解,如下:
1.2.1. 物理結構
? ? ? ?三個Solr實例( 每個實例包括兩個Core),組成一個SolrCloud。
1.2.2. 邏輯結構
? ? ? ?索引集合包括兩個Shard(shard1和shard2),shard1和shard2分別由三個Core組成,其中一個Leader兩個Replication,Leader是由zookeeper選舉產生,zookeeper控制每個shard上三個Core的索引數據一致,解決高可用問題。
? ? ? ?用戶發起索引請求分別從shard1和shard2上獲取,解決高并發問題。
1.1.1.1. ?Collection
? ? ? ?Collection在SolrCloud集群中是一個邏輯意義上的完整的索引結構。它常常被劃分為一個或多個Shard(分片),它們使用相同的配置信息。
? ? ? ? 比如:針對商品信息搜索可以創建一個collection。
? ? ? ? collection=shard1+shard2+....+shardX
1.1.1.2. ?Core
? ? ? ? 每個Core是Solr中一個獨立運行單位,提供索引和搜索服務。一個shard需要由一個Core或多個Core組成。由于collection由多個shard組成所以collection一般由多個core組成。
1.1.1.3. ?Master或Slave
? ? ? ? ?Master是master-slave結構中的主結點(通常說主服務器),Slave是master-slave結構中的從結點(通常說從服務器或備服務器)。同一個Shard下master和slave存儲的數據是一致的,這是為了達到高可用目的。
1.1.1.4. ?Shard
? ? ? ? ?Collection的邏輯分片。每個Shard被化成一個或者多個replication,通過選舉確定哪個是Leader。
2. SolrCloud搭建
? ? ? ? ?本教程的這套安裝是單機版的安裝,所以采用偽集群的方式進行安裝,如果是真正的生產環境,將偽集群的ip改下就可以了,步驟是一樣的。
SolrCloud結構圖如下:
?
2.1 環境準備
?
? ? ? ? ??CentOS-6.4-i386-bin-DVD1.iso
?????? jdk-7u72-linux-i586.tar.gz
? ? ? ?apache-tomcat-7.0.47.tar.gz
? ? ? ?zookeeper-3.4.6.tar.gz
? ? ? ?solr-4.10.3.tgz
2.2 環境安裝
2.2.1 CentOs6.4安裝
略
?
2.2.2 jdk7安裝
略
2.2.3 zookeeper集群安裝
?
第一步:解壓zookeeper,tar -zxvf zookeeper-3.4.6.tar.gz將zookeeper-3.4.6拷貝到/usr/local/solrcloud下,復制三份分別并將目錄名改為zookeeper1、zookeeper2、zookeeper3
第二步:進入zookeeper1文件夾,創建data目錄。并在data目錄中創建一個myid文件內容為“1”(echo 1 >>data/myid)。
第三步:進入conf文件夾,把zoo_sample.cfg改名為zoo.cfg
第四步:修改zoo.cfg。
修改:
dataDir=/usr/local/solrcloud/zookeeper1/data
clientPort=2181(zookeeper2中為2182、zookeeper3中為2183)
添加:
server.1=192.168.25.154:2881:3881
server.2=192.168.25.154:2882:3882
server.3=192.168.25.154:2883:3883
# The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/usr/local/solrcloud/zookeeper1/data # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1 server.1=192.168.25.154:2881:3881 server.2=192.168.25.154:2882:3882 server.3=192.168.25.154:2883:3883 |
?
第五步:對zookeeper2、3中的設置做第二步至第四步修改。
zookeeper2:
myid內容為2
dataDir=/usr/local/solrcloud/zookeeper2/data
clientPort=2182
Zookeeper3:
的myid內容為3
dataDir=/usr/local/solrcloud/zookeeper3/data
clientPort=2183
第六步:啟動三個zookeeper
/usr/local/solrcloud/zookeeper1/bin/zkServer.shstart
/usr/local/solrcloud/zookeeper2/bin/zkServer.shstart
/usr/local/solrcloud/zookeeper3/bin/zkServer.shstart
查看集群狀態:
/usr/local/solrcloud/zookeeper1/bin/zkServer.shstatus
/usr/local/solrcloud/zookeeper2/bin/zkServer.shstatus
/usr/local/solrcloud/zookeeper3/bin/zkServer.shstatus
第七步:開啟zookeeper用到的端口,或者直接關閉防火墻。
service iptables stop
2.3 tomcat安裝
第一步:將apache-tomcat-7.0.47.tar.gz解壓
? ? ? ? ? ? ? tar-zxvf apache-tomcat-7.0.47.tar.gz
第二步:把解壓后的tomcat復制到/usr/local/solrcloud/目錄下復制四份。
? ? ? ? ? ? ? /usr/local/solrcloud/tomcat1
? ? ? ? ? ? ? /usr/local/solrcloud/tomcat2
? ? ? ? ? ? ? /usr/local/solrcloud/tomcat3
? ? ? ? ? ? ? /usr/local/solrcloud/tomcat4
第三步:修改tomcat的server.xml
? ? ? ? ? ? ? vim tomcat2/conf/server.xml,把其中的端口后都加一。保證兩個tomcat可以正常運行不發生端口沖突。
2.4. SolrCloud部署
2.4.1. 啟動zookeeper
? ? ? ? solrCloud部署依賴zookeeper,需要先啟動每一臺zookeeper服務器。
2.5.2.??zookeeper管理配置文件
? ? ? ? 由于zookeeper統一管理solr的配置文件(主要是schema.xml、solrconfig.xml), solrCloud各各節點使用zookeeper管理的配置文件。
? ? ? ? 將上邊部署的solr單機的conf拷貝到/home/solr下。
? ? ? ? 執行下邊的命令將/home/solr/conf下的配置文件上傳到zookeeper(此命令為單條命令,雖然很長o(╯□╰)o)。此命令在solr-4.10.3/example/scripts/cloud-scripts/目錄下:
./zkcli.sh -zkhost 192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183 -cmd upconfig -confdir /usr/local/solrcloud/solrhome1/collection1/conf -confname myconf |
? ? ? ? 登陸zookeeper服務器查詢配置文件:
? ? ? ? cd /usr/local/zookeeper/bin/
? ? ? ? ./zkCli.sh?
2.5.3.??修改SolrCloud監控端口
修改每個solrhome的solr.xml文件。將host改成虛擬機ip地址,port改成對應的tomcat的端口號。
2.5.4.??每一臺solr和zookeeper關聯
修改每一臺solr的tomcat 的 bin目錄下catalina.sh文件中加入DzkHost指定zookeeper服務器地址:
JAVA_OPTS="-DzkHost=192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183"
(可以使用vim的查找功能查找到JAVA_OPTS的定義的位置,然后添加)
2.5.5.??啟動所有的solr服務
啟動每一臺solr的tomcat服務。
2.5.6.??訪問solrcloud
訪問任意一臺solr,左側菜單出現Cloud:
?
?
2.5.7 SolrCloud集群配置
上圖中的collection1集群只有一片,可以通過下邊的方法配置新的集群。
?
如果集群中有四個solr節點創建新集群collection2,將集群分為兩片,每片兩個副本。
http://192.168.25.154:8080/solr/admin/collections?action=CREATE&name=collection2&numShards=2&replicationFactor=2
?
?
刪除集群命令;
http://192.168.25.154:8080/solr/admin/collections?action=DELETE&name=collection1
執行后原來的collection1刪除,如下:
更多的命令請參數官方文檔:apache-solr-ref-guide-4.10.pdf
2.5.8.??啟動solrCloud注意
啟動solrCloud需要先啟動solrCloud依賴的所有zookeeper服務器,再啟動每臺solr服務器。
3.??solrJ訪問solrCloud
publicclass SolrCloudTest {// zookeeper地址privatestatic String zkHostString ="192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183";// collection默認名稱,比如我的solr服務器上的collection是collection2_shard1_replica1,就是去掉“_shard1_replica1”的名稱privatestatic String defaultCollection ="collection1";// cloudSolrServer實際private CloudSolrServercloudSolrServer;// 測試方法之前構造 CloudSolrServer@Beforepublicvoid init() {cloudSolrServer = new CloudSolrServer(zkHostString);cloudSolrServer.setDefaultCollection(defaultCollection);cloudSolrServer.connect();}// 向solrCloud上創建索引@TestpublicvoidtestCreateIndexToSolrCloud() throws SolrServerException,IOException {SolrInputDocument document =newSolrInputDocument();document.addField("id","100001");document.addField("title","李四");cloudSolrServer.add(document);cloudSolrServer.commit();}// 搜索索引@TestpublicvoidtestSearchIndexFromSolrCloud() throws Exception {SolrQuery query = new SolrQuery();query.setQuery("*:*");try {QueryResponse response =cloudSolrServer.query(query);SolrDocumentList docs =response.getResults();System.out.println("文檔個數:" +docs.getNumFound());System.out.println("查詢時間:" +response.getQTime());for (SolrDocumentdoc : docs) {ArrayList title= (ArrayList) doc.getFieldValue("title");String id = (String)doc.getFieldValue("id");System.out.println("id: " + id);System.out.println("title: " + title);System.out.println();}} catch (SolrServerException e){e.printStackTrace();} catch (Exception e) {System.out.println("Unknowned Exception!!!!");e.printStackTrace();}}// 刪除索引@TestpublicvoidtestDeleteIndexFromSolrCloud() throws SolrServerException, IOException {// 根據id刪除UpdateResponse response=cloudSolrServer.deleteById("zhangsan");// 根據多個id刪除// cloudSolrServer.deleteById(ids);// 自動查詢條件刪除// cloudSolrServer.deleteByQuery("product_keywords:教程");// 提交cloudSolrServer.commit();}
}
?