參考了 Apache Solr Reference Guide / Apache Solr Reference Guide / SolrCloud, 打算用 4 個 centos 6.3 VM 來安裝 SolrCloud. 在上述文章中可以看到 SolrCloud 的簡介.
Apache Solr includes the ability to set up a cluster of Solr servers that combines fault tolerance and high availability. Called SolrCloud, these capabilities provide distributed indexing and search capabilities, supporting the following features:
- Central configuration for the entire cluster
- Automatic load balancing and fail-over for queries
- ZooKeeper integration for cluster coordination and configuration.
SolrCloud is flexible distributed search and indexing, without a master node to allocate nodes, shards and replicas. Instead, Solr uses ZooKeeper to manage these locations, depending on configuration files and schemas. Documents can be sent to any server and ZooKeeper will figure it out.
ZooKeeper 會安裝成獨立的 server, 不會用 solr 提供的 embedded ZooKeeper. 以下是 4 個 VM 安裝的配置 :
solr1(192.168.0.11) : 安裝 ZooKeeper, solr
solr2(192.168.0.12) : 安裝 ZooKeeper, solr
solr3(192.168.0.13) : 安裝 ZooKeeper, solr
solr4(192.168.0.14) : 安裝 solr
1. solr 安裝
先在 solr1 VM 上安裝 solr, 再 scp 到其他 VM. solr 的安裝請參考
nutch 1.8 + solr 4.9.0 探討系列一 : 基礎安裝篇. 先在 4 台 VM 安裝 scp.
yum install openssh-clients
以下是在 solr1 VM 上傳 solr example/ 目錄 到 solr2, solr3, solr4, 並且 solr1 本身也 copy 一份到 local /root
cd /root/solr-4.9.0/solr
cp -r example/ /root/
scp -r example/ solr2:/root
scp -r example/ solr3:/root
scp -r example/ solr4:/root
在 4 台 VM solr1, solr2, solr3, solr4 更改目錄名.
mv /root/example/ /root/solr-node
2. ZooKeeper 安裝
在 4 台 VM solr1, solr2, solr3, solr4 執行以下指令 :
cd ~
wget http://ftp.twaren.net/Unix/Web/apache/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz
tar zxvf zookeeper-3.4.6.tar.gz
cd zookeeper-3.4.6
cp zoo_sample.cfg zoo.cfg
vi zoo.cfg
修改並儲存 :
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/root/zookeeper-3.4.6/data
# the port at which the clients will connect
clientPort=2181
server.1=solr1:2888:3888
server.2=solr2:2888:3888
server.3=solr3:2888:3888
建立 data 目錄 :
cd ..
mkdir data
solr1 VM 新增 myid 檔案 :
echo "1" >> data/myid
solr2 VM 新增 myid 檔案 :
echo "2" >> data/myid
solr3 VM 新增 myid 檔案 :
echo "3" >> data/myid
solr4 VM 新增 myid 檔案 :
echo "4" >> data/myid
3. 啟動 solr1, solr2, solr3 的 zookeeper server
cd /root/zookeeper-3.4.6
bin/zkServer.sh start
4. 啟動 solr1 的 solr
cd /root/solr-node
java -DnumShards=2 -Dbootstrap_confdir=./solr/collection1/conf \
-Dcollection.configName=myconf -DzkHost=solr1:2181,solr2:2181,solr3:2181 \
-jar start.jar
可連接以下網址查看 :
http://192.168.0.11:8983/solr/#/~cloud
可看到 :
5. 啟動 solr2, solr3, solr4 的 solr
cd /root/solr-node
java -Djetty.port=7574 -DzkHost=solr1:2181,solr2:2181,solr3:2181 \
-jar start.jar
請記得第 2, 3, 4 VM 的 jetty.port 不要和第一台一樣, 在此設為 7574.可連接以下任一網址查看, 請記得這 4 個網址都可以當做這一個 SolrCloud 的入口.
http://192.168.0.11:8983/solr/#/~cloud
or
http://192.168.0.12:7574/solr/#/~cloud
or
http://192.168.0.13:7574/solr/#/~cloud
or
http://192.168.0.14:7574/solr/#/~cloud
可看到 :
請忽略圖中灰色看不到的 端點和文字, 這是在測試過程, 啟動 server 留下的痕跡, 沒有意義.
6. SolrCloud index, query, shards, replicas, fault tolerance and high availability 測試
請注意, 此 solr 的 schema.xml 是來自 Nutch, 所以以下的資料 import 有其特殊性, 若為 solr 的 預設 schema.xml, 可參考
Updating a Solr Index with JSON. 起初以 csv 匯入, 因為測試後發現了問題, 可能是個 bug, 所以改採 json 匯入. 以下指令中的網址可使用任一個 solr node, 任一 node 都是指令入口.
curl "http://192.168.0.14:7574/solr/update" -H 'Content-type:application/json' -d '
[
{"id" : "book1",
"url" : "url1",
"title" : "A Game of Thrones",
"author" : "George R.R. Martin"
},
{"id" : "book2",
"url" : "url2",
"title" : "A Clash of Kings",
"author" : "George R.R. Martin"
},
{"id" : "book3",
"url" : "url3",
"title" : "Foundation",
"author" : "Isaac Asimov"
},
{"id" : "book4",
"url" : "url4",
"title" : "Foundation and Empire",
"author" : "Isaac Asimov"
}
]'
然後使用以下 8 個指令看回傳的結果, 其中 distrib=false 是代表只要查詢此一 shard node 上的資料, 而不是全部資料. 請記得要用 "" 括住整個網址.
curl "http://192.168.0.11:8983/solr/collection1/select?q=*:*"
curl "http://192.168.0.12:7574/solr/collection1/select?q=*:*"
curl "http://192.168.0.13:7574/solr/collection1/select?q=*:*"
curl "http://192.168.0.14:7574/solr/collection1/select?q=*:*"
curl "http://192.168.0.11:8983/solr/collection1/select?q=*:*&distrib=false"
curl "http://192.168.0.12:7574/solr/collection1/select?q=*:*&distrib=false"
curl "http://192.168.0.13:7574/solr/collection1/select?q=*:*&distrib=false"
curl "http://192.168.0.14:7574/solr/collection1/select?q=*:*&distrib=false"
接下來再依序 stop 其中 solr4, solr3, solr2 3 個 node, 並同時執行以上指令, 看會有甚麼影響.
我們從上面的 shard node 結構圖可以看出, shard1, shard2 為一個完整的資料, 整個 cluster 有 2 份資料, 自動保持同步. 所以 shard1, shard2 至少各要保持一個 node, 如果無法達成此條件, 則上述的查詢會得到 503 的錯誤訊息. Leader shard node 如果 stop 後再啟動, 因為它 stop, 所以 Leader 身份自動轉移出去. 例如:如果 stop solr1, 再啟動, 可以發現, solr1 已失去 Leader 的身份, 改為 solr4.
接下來我們來測試 ZooKeeper 的 high availability. 從 Getting Started with SolrCloud 的 Using Multiple ZooKeepers in an Ensemble 段落內容可看出, 3 台 ZooKeeper Server 至少要保持 2 台 ZooKeeper live, 才可以達到 high availability.
To truly provide high availability, we need to make sure that not only do we also have at least one shard server running at all times, but also that the cluster also has a ZooKeeper running to manage it. To do that, you can set up a cluster to use multiple ZooKeepers. This is called using a ZooKeeper ensemble.
A ZooKeeper ensemble can keep running as long as more than half of its servers are up and running, so at least two servers in a three ZooKeeper ensemble, 3 servers in a 5 server ensemble, and so on, must be running at any given time. These required servers are called a quorum.
經過測試, 任 2 台 ZooKeeper stop 時, SolrCloud 就無法使用, 所以真的必須保留一半以上的 ZooKeepers.
7. Nutch 抓取的資料給 SolrCloud 做 index
前面有說 4 個 node 都可以做 SolrCloud 的入口, 所以可以執行以下任一指令 :
bin/crawl urls crawl http://192.168.0.11:8983/solr/ 2
or
bin/crawl urls crawl http://192.168.0.12:7574/solr/ 2
or
bin/crawl urls crawl http://192.168.0.13:7574/solr/ 2
or
bin/crawl urls crawl http://192.168.0.14:7574/solr/ 2
再用上述的 query 指令, 查詢一下 Nutch 抓取的資料在各個 shard 的分布.
Nutch 的安裝請參考 nutch 1.8 + solr 4.9.0 探討系列一 : 基礎安裝篇.
8. 用 Tomcat 取代 jetty
Tomcat 的安裝, 及與 solr 的整合與設定請參考
nutch 1.8 + solr 4.9.0 探討系列一 : 基礎安裝篇 中 6~8 步驟. 先在 solr1 安裝和設定. 其中步驟 7 改成以下方式處理.
yum install unzip
unzip /root/solr-node/webapps/solr.war -d /usr/local/apache-tomcat-8.0.9/webapps/solr
vi /usr/local/apache-tomcat-8.0.9/webapps/solr/WEB-INF/web.xml
修改以下內容 :
<!--
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/put/your/solr/home/here</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
-->
成
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/root/solr-node/solr</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
修改 server.xml :
vi /usr/local/apache-tomcat-8.0.9/conf/server.xml
修改 8080 port 成 8983 :
<Connector port="8983" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
修改 cataina.sh :
vi /usr/local/apache-tomcat-8.0.9/bin/cataina.sh
加入以下內容 :
JAVA_OPTS="$JAVA_OPTS -Djetty.port=8983 -DnumShards=2 -Dbootstrap_confdir=/root/solr-node/solr/collection1/conf -Dcollection.configName=myconf -DzkHost=solr1:2181,solr2:2181,solr3:2181"
solr2, solr3, solr4 建立 /usr/local 目錄
mkdir /usr/local
solr1 設定好後, scp 到 solr2, solr3, solr4
scp -r /usr/local/apache-tomcat-8.0.9/ solr2:/usr/local/
scp -r /usr/local/apache-tomcat-8.0.9/ solr3:/usr/local/
scp -r /usr/local/apache-tomcat-8.0.9/ solr4:/usr/local/
solr2, solr3, solr4 修改 server.xml
vi /usr/local/apache-tomcat-8.0.9/conf/server.xml
修改 8983 port 成 7574 :
<Connector port="7574" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
修改 cataina.sh :
vi /usr/local/apache-tomcat-8.0.9/bin/cataina.sh
修改 jetty.port 成 7574 :
JAVA_OPTS="$JAVA_OPTS -Djetty.port=7574 -DnumShards=2 -Dbootstrap_confdir=/root/solr-node/solr/collection1/conf -Dcollection.configName=myconf -DzkHost=solr1:2181,solr2:2181,solr3:2181"
-Djetty.port=7574 也可以不指定, 而直接修改 /root/solr-node/solr/solr.xml 的 hostPort, 由 ${jetty.port:8983} 改為 7574 :
vi /root/solr-node/solr/solr.xml
修改如下 :
<solrcloud>
<str name="host">${host:}</str>
<int name="hostPort">7574</int>
<str name="hostContext">${hostContext:solr}</str>
<int name="zkClientTimeout">${zkClientTimeout:30000}</int>
<bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
</solrcloud>
請記得 solr2, solr3, solr4 的 port 要跟 solr1 不一樣. 讀者可以試試看所有 VM 的 port 都一樣的結果.
solr1, solr2, solr3, solr4 startup tomcat
cd /usr/local/apache-tomcat-8.0.9
bin/startup.sh
連上以下網址驗證 SolrCloud 是否正常
http://192.168.0.11:8983/solr/#/~cloud
or
http://192.168.0.12:7574/solr/#/~cloud
or
http://192.168.0.13:7574/solr/#/~cloud
or
http://192.168.0.14:7574/solr/#/~cloud
9. multicore 的設定
因為要改用 multicore, 所以將先前的 collection1 刪除. 否則以下的操作完成後會不正常. 在 solr1 執行以下指令 :
curl "http://192.168.0.11:8983/solr/admin/collections?action=DELETE&name=collection1"
solr1, solr2, solr3, solr4 shutdown tomcat
cd /usr/local/apache-tomcat-8.0.9
bin/shutdown.sh
SolrCloud是透過 ZooKeeper 集群來保證 conf/ 文件的變更及時同步到各個節點上,所以,需要將 conf/* 上傳到 ZooKeeper 集群中, 我們共有 core0, core1 2 個 core(以前只有 collection1):
在 solr1 上執行以下指令 :
core0 :
java -classpath .:/root/solr-node/solr-webapp/webapp/WEB-INF/lib/*:/root/solr-node/lib/ext/* \
org.apache.solr.cloud.ZkCLI -cmd upconfig -zkhost solr1:2181,solr2:2181,solr3:2181 \
-confdir /root/solr-node/multicore/core0/conf -confname conf0 \
-solrhome /root/solr-node/multicore
java -classpath .:/root/solr-node/solr-webapp/webapp/WEB-INF/lib/*:/root/solr-node/lib/ext/* \
org.apache.solr.cloud.ZkCLI -cmd linkconfig -zkhost solr1:2181,solr2:2181,solr3:2181 \
-collection core0 -confname conf0 -solrhome /root/solr-node/multicore
core1 :
java -classpath .:/root/solr-node/solr-webapp/webapp/WEB-INF/lib/*:/root/solr-node/lib/ext/* \
org.apache.solr.cloud.ZkCLI -cmd upconfig -zkhost solr1:2181,solr2:2181,solr3:2181 \
-confdir /root/solr-node/multicore/core1/conf -confname conf1 \
-solrhome /root/solr-node/multicore
java -classpath .:/root/solr-node/solr-webapp/webapp/WEB-INF/lib/*:/root/solr-node/lib/ext/* \
org.apache.solr.cloud.ZkCLI -cmd linkconfig -zkhost solr1:2181,solr2:2181,solr3:2181 \
-collection core1 -confname conf1 -solrhome /root/solr-node/multicore
上傳完成以後,我們查一下 ZooKeeper 上的儲存情況, 可以選擇 solr, solr2, solr3 任一台 VM 執行以下指令:
cd /root/zookeeper-3.4.6
bin/zkCli.sh -server solr1:2181
...
[zk: solr1:2181(CONNECTED) 0] ls /
[configs, zookeeper, clusterstate.json, aliases.json, live_nodes, overseer, overseer_elect, collections]
[zk: solr1:2181(CONNECTED) 1] ls /configs
[conf0, conf1, myconf]
[zk: solr1:2181(CONNECTED) 2] ls /configs/conf0
[admin-extra.menu-top.html, currency.xml, protwords.txt, mapping-FoldToASCII.txt, _schema_analysis_synonyms_english.json, solrconfig.xml, _schema_analysis_stopwords_english.json, stopwords.txt, lang, schema.xml.bak, spellings.txt, mapping-ISOLatin1Accent.txt, admin-extra.html, xslt, synonyms.txt, scripts.conf, update-script.js, velocity, elevate.xml, admin-extra.menu-bottom.html, schema.xml, clustering]
[zk: solr1:2181(CONNECTED) 3]quit
也可以查詢一下 solr2, solr3 的情況 :
bin/zkCli.sh -server solr2:2181
or
bin/zkCli.sh -server solr3:2181
在 solr1, solr2, solr3, solr4 修改 tomcat 的設定並重新啟動 :
cd /usr/local/apache-tomcat-8.0.9
vi bin/cataina.sh
刪除先前所輸入的 -Dbootstrap_confdir=/root/solr-node/solr/collection1/conf -Dcollection.configName=myconf
JAVA_OPTS="$JAVA_OPTS -Djetty.port=7574 -DnumShards=2 -Dbootstrap_confdir=/root/solr-node/solr/collection1/conf -Dcollection.configName=myconf -DzkHost=solr1:2181,solr2:2181,solr3:2181"
刪除之後的內容 :
JAVA_OPTS="$JAVA_OPTS -Djetty.port=7574 -DnumShards=2 -DzkHost=solr1:2181,solr2:2181,solr3:2181"
在 solr1 上的 cataina.sh 是 -Djetty.port=8983, 為了方便就不另外貼指令.
修改solr1, solr2, solr3, solr4 的各個 VM 上的 web.xml :
vi /usr/local/apache-tomcat-8.0.9/webapps/solr/WEB-INF/web.xml
修改以下內容 :
<!--
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/root/solr-node/solr</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
-->
成
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/root/solr-node/multicore</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
/root/solr-node/multicore/ 下的 core0/conf/, core1/conf/, 讀者可自行定義相關 xml, 或從 collection1/conf copy 過來再修改.
solr1, solr2, solr3, solr4 startup tomcat
bin/startup.sh
10. 參考文章