Solr Cloud を Vagrant で構築した

いよいよ Solr Cloud を構築します.
Solr Cloud を構築するには,Solr はもちろん ZooKeeper も必要です.
これまで Vagrant で Solr を Standalone で構築したり,ZooKeeper を Ensemble で構築してきたのもこのためでした.

Solr Cloud

イメージはこんな感じです.

  • ZooKeeper : 3
  • Solr node: 4
  • shard : 2
  • replica : 2

Zookeeper 3 個,Solr node 4 個の計 7 個の VM を構築します.

f:id:mt9116:20190611154658p:plain

構成

構成を以下に示します.

D:\vagrant\solrcloud
┣Vagrantfile
┣create_zkensemble.sh
┗create_solrnode.sh

Vagrantfile

Zookeeper 3 個,Solr node 4 個の計 7 個の VM を構築します.
Solr を Cloud モードで起動する際に ZooKeeper の接続先を指定する必要があるので Vagrantfile で接続先文字列を用意するのがポイントです.

# ZooKeeper 数
zk_cnt = 3
# Solr node 数
node_cnt = 4

Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"

  #--- proxy 設定 ---#
  no_proxy_address = "localhost,127.0.0.1"
  (1..zk_cnt).each do |i|
    no_proxy_address += ",zk#{i},192.168.33.1#{i}"
  end
  (1..node_cnt).each do |i|
    no_proxy_address += ",node#{i},192.168.33.2#{i}"
  end
  config.proxy.enabled  = true
  config.proxy.http     = "http://user_id:password@proxy_address:proxy_port"
  config.proxy.https    = "http://user_id:password@proxy_address:proxy_port"
  config.proxy.no_proxy = no_proxy_address
  #--- /proxy 設定 ---#
  
  #--- ZooKeeper アンサンブル構築 ---#
  (1..zk_cnt).each do |i|
    config.vm.define "zk#{i}" do | zk |
      zk.vm.hostname = "zk#{i}"
      zk.vm.network "private_network", ip: "192.168.33.1#{i}"
      zk.vm.provision :hosts, :sync_hosts => true
      zk.vm.provision :shell, path: "./create_zkensemble.sh", args: "#{i} #{zk_cnt}"
    end
  end
  #--- /ZooKeeper アンサンブル構築 ---#

  #--- ZooKeeper アンサンブルの接続先文字列 ---#
  zkensemble = ""
  (1..zk_cnt).each do |i|
    zkensemble += "192.168.33.1#{i}:2181,"
  end
  zkensemble.slice!(/,$/)
  #--- /ZooKeeper アンサンブルの接続先文字列 ---#

  #--- Solr Cloud 構築 ---#
  (1..node_cnt).each do |i|
    config.vm.define "node#{i}" do | node |
      node.vm.provider :virtualbox do |vb|
          # Solr node だけメモリ増やしてます
          vb.customize ["modifyvm", :id, "--memory", "2048"]
          vb.customize ["modifyvm", :id, "--cpus", "2"]
      end
      node.vm.hostname = "node#{i}"
      node.vm.network "private_network", ip: "192.168.33.2#{i}"
      node.vm.provision :hosts, :sync_hosts => true
      node.vm.provision :shell, path: "./create_solrcloud.sh", args: "192.168.33.2#{i} #{zkensemble}"
    end
  end
  #--- /Solr Cloud 構築 ---#

end

create_zkensemble.sh

ZooKeeper Ensemble を構築したときと同じです.

# Java をインストールする
yum install -y java-1.8.0-openjdk

# ZooKeeper を構築する
cd /var/tmp
yum install -y wget
wget http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
tar xvf zookeeper-3.4.14.tar.gz
cp -ar zookeeper-3.4.14 /opt/
ln -s /opt/zookeeper-3.4.14 /opt/zookeeper

# ZooKeeper 用のユーザを作成する
groupadd zookeeper
useradd -g zookeeper -d /opt/zookeeper -s /sbin/nologin zookeeper
chown -R zookeeper.zookeeper /opt/zookeeper/*

# ZooKeeperの設定ファイルを用意する
cd /opt/zookeeper/conf
cp zoo_sample.cfg zoo.cfg

# dataDir を tmp から var に変更する
mkdir /var/lib/zookeeper
chown zookeeper.zookeeper /var/lib/zookeeper
cd /opt/zookeeper/conf
sed -i -e 's#dataDir=.*$#dataDir=/var/lib/zookeeper#' zoo.cfg

# ZooKeeper アンサンブルの設定を追記する
# $1 : ZooKeeper のノードID
# $2 : ZooKeeper アンサンブルの構成ノード数
echo "# ZooKeeper Ensemble" >> /opt/zookeeper/conf/zoo.cfg
for i in `seq 1 $2`
do
  if [ $i = $1 ] ; then
    # ノードIDが自分のものと一致する場合は 0.0.0.0 とする.
    echo "server.${i}=0.0.0.0:2888:3888" >> /opt/zookeeper/conf/zoo.cfg
  else
    echo "server.${i}=192.168.33.1${i}:2888:3888" >> /opt/zookeeper/conf/zoo.cfg
  fi
done
# dataDir にノードIDが記載された myid ファイルを用意する必要がある
echo $1 >> /var/lib/zookeeper/myid

# ZooKeeper を起動する
cd /opt/zookeeper
bin/zkServer.sh start

# Port を開放する
systemctl enable firewalld.service
systemctl start firewalld.service
firewall-cmd --zone=public --add-port=2181/tcp --add-port=2888/tcp --add-port=3888/tcp --permanent
firewall-cmd --reload

# ZooKeeper の状態を確認する
cd /opt/zookeeper
bin/zkServer.sh status
yum install -y nc
echo ruok | nc localhost 2181

# 終了ステータスが 0 でない場合に Vagrant が異常終了とみなし VM が連続生成されないことがあるので明示する
exit 0

create_solrcloud.sh

Solr を Cloud モードで起動します.

# Java をインストールする
yum install -y java-1.8.0-openjdk

# Solr を構築する
cd /usr/local/src/
yum install -y wget
wget http://ftp.jaist.ac.jp/pub/apache/lucene/solr/8.1.1/solr-8.1.1.tgz
tar xzf solr-8.1.1.tgz
./solr-8.1.1/bin/install_solr_service.sh solr-8.1.1.tgz

# Solr を Cloud モードで起動する
# $1 : Solr node の IPアドレス
# $2 : ZooKeeper アンサンブルの接続先文字列
sudo -u solr /opt/solr/bin/solr stop
sudo -u solr /opt/solr/bin/solr start -cloud -s /var/solr/data -p 8983 -z $2 -h $1

# Port を開放する
systemctl enable firewalld.service
systemctl start firewalld.service
firewall-cmd --zone=public --add-port=8983/tcp --permanent
firewall-cmd --reload

# 終了ステータスが 0 でない場合に Vagrant が異常終了とみなし VM が連続生成されないことがあるので明示する
exit 0

Solr Cloud を構築する

cd D:\vagrant\solrcloud
vagrant up
# Solr を停止する
vagrant ssh node1 -c "sudo -u solr /opt/solr/bin/solr stop"
vagrant ssh node2 -c "sudo -u solr /opt/solr/bin/solr stop"
vagrant ssh node3 -c "sudo -u solr /opt/solr/bin/solr stop"
vagrant ssh node4 -c "sudo -u solr /opt/solr/bin/solr stop"
# Solr を Cloud モードで起動する
vagrant ssh node1 -c "sudo -u solr /opt/solr/bin/solr restart -cloud -s /var/solr/data -p 8983 -z 192.168.33.11:2181,192.168.33.12:2181,192.168.33.13:2181 -h 192.168.33.21"
vagrant ssh node2 -c "sudo -u solr /opt/solr/bin/solr restart -cloud -s /var/solr/data -p 8983 -z 192.168.33.11:2181,192.168.33.12:2181,192.168.33.13:2181 -h 192.168.33.22"
vagrant ssh node3 -c "sudo -u solr /opt/solr/bin/solr restart -cloud -s /var/solr/data -p 8983 -z 192.168.33.11:2181,192.168.33.12:2181,192.168.33.13:2181 -h 192.168.33.23"
vagrant ssh node4 -c "sudo -u solr /opt/solr/bin/solr restart -cloud -s /var/solr/data -p 8983 -z 192.168.33.11:2181,192.168.33.12:2181,192.168.33.13:2181 -h 192.168.33.24"
-->

http://192.168.33.21:8983/solr/#/ にアクセスすると Cloud という項目が追加されていることがわかります.

f:id:mt9116:20190611154730p:plain

Cloud をクリックすると node が一覧に表示されます.
4個 node を作成したので4個表示されています.
まだ collection を作成していないので Collections,Replicas は空です.

f:id:mt9116:20190611154741p:plain

ZK Status をクリックすると ZooKeeper が一覧に表示されます.
3個 ZooKeeper を作成したので3個でアンサンブルが構成されています.
今回は 192.168.33.12 が leader に選出されたようです.

f:id:mt9116:20190611154758p:plain

Graph をクリックすると Solr Cloud の構成が可視化されます.
まだ collection を作成していないので何も表示されません.

f:id:mt9116:20190611154813p:plain

collection を作成する

早速 collection を作ります.

vagrant ssh node1 -c "sudo -u solr /opt/solr/bin/solr create_collection -c examplecollection -p 8983 -shards 2 -replicationFactor 2"

Dashboard を見ると collection が追加されていることがわかります.

images/solr_dashborad_collection.png

collection を選択すると shard 2 replication 2 で構成されていることがわかります.

images/solr_collection_overview.png

Cloud の Graph を見ると collection の shard に各 node が割り当てられていることがわかります.

images/solr_cloud_graph_collection_created.png

インデクシング(文書登録)する

collection にインデクシングをおこないます.

vagrant ssh node1 -c "sudo -u solr /opt/solr/bin/post -c examplecollection -p 8983 /opt/solr/example/exampledocs/*.xml"

検索してみます.

$ curl -X GET "http://192.168.33.21:8983/solr/examplecollection/select?q=*:*&fl=id&sort=id%20asc&wt=json&indent=on" --noproxy 192.168.33.21                
{                                                                                                                                                          
  "responseHeader":{                                                                                                                                       
    "zkConnected":true,                                                                                                                                    
    "status":0,                                                                                                                                            
    "QTime":7,                                                                                                                                             
    "params":{                                                                                                                                             
      "q":"*:*",                                                                                                                                           
      "indent":"on",                                                                                                                                       
      "fl":"id",                                                                                                                                           
      "sort":"id asc",                                                                                                                                     
      "wt":"json"}},                                                                                                                                       
  "response":{"numFound":32,"start":0,"docs":[                                                                                                             
      {                                                                                                                                                    
        "id":"0579B002"},                                                                                                                                  
      {                                                                                                                                                    
        "id":"100-435805"},                                                                                                                                
      {                                                                                                                                                    
        "id":"3007WFP"},                                                                                                                                   
      {                                                                                                                                                    
        "id":"6H500F0"},                                                                                                                                   
      {                                                                                                                                                    
        "id":"9885A004"},                                                                                                                                  
      {                                                                                                                                                    
        "id":"EN7800GTX/2DHTV/256M"},                                                                                                                      
      {                                                                                                                                                    
        "id":"EUR"},                                                                                                                                       
      {                                                                                                                                                    
        "id":"F8V7067-APL-KIT"},                                                                                                                           
      {                                                                                                                                                    
        "id":"GB18030TEST"},                                                                                                                               
      {                                                                                                                                                    
        "id":"GBP"}]                                                                                                                                       
  }}                                                                                                                                                       

32件ヒットしました.
rows を指定していないので id は 10 件のみの表示となっています.
これで構築が完了しました.

shard を指定した検索

まずは shard1 を指定して検索します.

$ curl -X GET "http://192.168.33.21:8983/solr/examplecollection/select?q=*:*&fl=id&shards=shard1&sort=id%20asc&wt=json&indent=on" --noproxy 192.168.33.21    
{                                                                                                                                                            
  "responseHeader":{                                                                                                                                         
    "zkConnected":true,                                                                                                                                      
    "status":0,                                                                                                                                              
    "QTime":4,                                                                                                                                               
    "params":{                                                                                                                                               
      "q":"*:*",                                                                                                                                             
      "shards":"shard1",                                                                                                                                     
      "indent":"on",                                                                                                                                         
      "fl":"id",                                                                                                                                             
      "sort":"id asc",                                                                                                                                       
      "wt":"json"}},                                                                                                                                         
  "response":{"numFound":14,"start":0,"docs":[                                                                                                               
      {                                                                                                                                                      
        "id":"3007WFP"},                                                                                                                                     
      {                                                                                                                                                      
        "id":"EN7800GTX/2DHTV/256M"},                                                                                                                        
      {                                                                                                                                                      
        "id":"GB18030TEST"},                                                                                                                                 
      {                                                                                                                                                      
        "id":"GBP"},                                                                                                                                         
      {                                                                                                                                                      
        "id":"IW-02"},                                                                                                                                       
      {                                                                                                                                                      
        "id":"MA147LL/A"},                                                                                                                                   
      {                                                                                                                                                      
        "id":"TWINX2048-3200PRO"},                                                                                                                           
      {                                                                                                                                                      
        "id":"USD"},                                                                                                                                         
      {                                                                                                                                                      
        "id":"VDBDB1A16"},                                                                                                                                   
      {                                                                                                                                                      
        "id":"VS1GB400C3"}]                                                                                                                                  
  }}                                                                                                                                                         

14件ヒットしました.
次に shard2 を指定して検索します.

$ curl -X GET "http://192.168.33.21:8983/solr/examplecollection/select?q=*:*&fl=id&shards=shard2&sort=id%20asc&wt=json&indent=on" --noproxy 192.168.33.21
{
  "responseHeader":{
    "zkConnected":true,
    "status":0,
    "QTime":0,
    "params":{
      "q":"*:*",
      "shards":"shard2",
      "indent":"on",
      "fl":"id",
      "sort":"id asc",
      "wt":"json"}},
  "response":{"numFound":18,"start":0,"docs":[
      {
        "id":"0579B002"},
      {
        "id":"100-435805"},
      {
        "id":"6H500F0"},
      {
        "id":"9885A004"},
      {
        "id":"EUR"},
      {
        "id":"F8V7067-APL-KIT"},
      {
        "id":"NOK"},
      {
        "id":"SOLR1000"},
      {
        "id":"SP2514N"},
      {
        "id":"UTF8TEST"}]
  }}

18件ヒットしました.
各 shard から異なる結果が得られたことから,文書を登録すると自動で各 shard に文書が登録されることがわかりました.
今度は shard1 と shard2 両方指定して検索します.

$ curl -X GET "http://192.168.33.21:8983/solr/examplecollection/select?q=*:*&fl=id&shards=shard1,shard2&sort=id%20asc&wt=json&indent=on" --noproxy 192.168.33.21                                
{                                                                                                                                                                                               
  "responseHeader":{                                                                                                                                                                            
    "zkConnected":true,                                                                                                                                                                         
    "status":0,                                                                                                                                                                                 
    "QTime":17,                                                                                                                                                                                 
    "params":{                                                                                                                                                                                  
      "q":"*:*",                                                                                                                                                                                
      "shards":"shard1,shard2",                                                                                                                                                                 
      "indent":"on",                                                                                                                                                                            
      "fl":"id",                                                                                                                                                                                
      "sort":"id asc",                                                                                                                                                                          
      "wt":"json"}},                                                                                                                                                                            
  "response":{"numFound":32,"start":0,"docs":[                                                                                                                                                  
      {                                                                                                                                                                                         
        "id":"0579B002"},                                                                                                                                                                       
      {                                                                                                                                                                                         
        "id":"100-435805"},                                                                                                                                                                     
      {                                                                                                                                                                                         
        "id":"3007WFP"},                                                                                                                                                                        
      {                                                                                                                                                                                         
        "id":"6H500F0"},                                                                                                                                                                        
      {                                                                                                                                                                                         
        "id":"9885A004"},                                                                                                                                                                       
      {                                                                                                                                                                                         
        "id":"EN7800GTX/2DHTV/256M"},                                                                                                                                                           
      {                                                                                                                                                                                         
        "id":"EUR"},                                                                                                                                                                            
      {                                                                                                                                                                                         
        "id":"F8V7067-APL-KIT"},                                                                                                                                                                
      {                                                                                                                                                                                         
        "id":"GB18030TEST"},                                                                                                                                                                    
      {                                                                                                                                                                                         
        "id":"GBP"}]                                                                                                                                                                            
  }}                                                                                                                                                                                            

shard を指定しない場合と同じ結果になりました.
つまりクエリで shard を全て指定しなくても全ての shard から検索することがわかりました.

まとめ

  • collection を作成すると shard に各 node が自動で割り当てられます.
  • Solr Cloud の collection に文書を登録すると自動で各 shard に文書が登録されます.
  • Solr Cloud の collection を検索する際に shard を指定しなくても全 shard から検索されます.