1. 程式人生 > >170825、SolrCloud 分布式集群部署步驟

170825、SolrCloud 分布式集群部署步驟

where enc dns解析 分享圖片 setquery 圖片 args tco msh

安裝軟件包準備

  • apache-tomcat-7.0.54
  • jdk1.7
  • solr-4.8.1
  • zookeeper-3.4.5

註:以上軟件都是基於 Linux 環境的 64位 軟件,以上軟件請到各自的官網下載。

服務器準備

為搭建這個集群,準備三臺服務器,分別為

192.168.0.2 -- master 角色
192.168.0.3 -- slave 角色
192.168.0.4 -- slave 角色

搭建基礎環境

  1. 安裝 jdk1.7 - 這個大家都會安裝,就不費鍵盤了。

  2. 配置主機 /etc/hosts 文件 - 當然,如果內部有內部DNS解析,就不需要配置 hosts文件了。在 3 臺服務器的 /etc/hosts

    中添加以下記錄

192.168.0.2 SOLR-CLOUD-001
192.168.0.3 SOLR-CLOUD-002
192.168.0.4 SOLR-CLOUD-003

zookeeper 部署

Zookeeper 分布式服務框架是 Apache Hadoop 的一個子項目,它主要是用來解決分布式應用中經常遇到的一些數據管理問題,如:統一命名服務、狀態同步服務、集群管理、分布式應用配置項的管理等。

註:Zookeeper集群的機器個數推薦是奇數臺,半數機器掛掉,服務是可以正常提供的

首先以 192.168.0.2 為例來搭建 zookeeper:

  1. 在軟件部署目錄下面部署 zookeeper,把下載的 zookeeper-3.4.5 解壓到軟件部署目錄 /apps/svr

    註:為了統一部署,以及以後自動化方便,必須統一軟件部署目錄,目前我這邊是以 ``/apps/svr``` 為軟件部署主目錄

  2. 建立 zookeeper 的數據、日誌以及配置文件目錄

mkdir -p /apps/data/zookeeper-data/

mkdir -p /apps/data/zookeeper-data/logs/

mkdir -p /apps/svr/zookeeper-3.4.5/conf

註: /apps/data 是定義的統一存放數據的目錄

  1. zookeeper 的 conf 目錄下面的 zoo_sample.cfg 修改成 zoo.cfg,並且對其內容做修改
cp -av /apps/svr/zookeeper-3.4.5/conf/zoo_sample.cfg /apps/svr/zookeeper-3.4.5/conf/zoo.cfg

修改 zoo.cfg 的內容,主要是修改 dataDir 、dataLogDir 和 server.1-3

# 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=/apps/data/zookeeper-data
dataLogDir=/apps/data/zookeeper-data/logs

server.1=SOLR-CLOUD-001:2888:3888
server.2=SOLR-CLOUD-002:2888:3888
server.3=SOLR-CLOUD-003:2888:3888
# the port at which the clients will connect
clientPort=2181
#
# 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

註:
tickTime:這個時間是作為 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每個 tickTime 時間就會發送一個心跳。
initLimit:這個配置項是用來配置 Zookeeper 接受客戶端(這裏所說的客戶端不是用戶連接 Zookeeper 服務器的客戶端,而是 Zookeeper服務器集群中連接到 Leader 的 Follower 服務器)初始化連接時最長能忍受多少個心跳時間間隔數。當已經超過 10 個心跳的時間(也就是tickTime)長度後 Zookeeper 服務器還沒有收到客戶端的返回信息,那麽表明這個客戶端連接失敗。總的時間長度就是52000=10秒。
syncLimit:這個配置項標識 Leader 與 Follower 之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 2
2000=4 秒
dataDir:顧名思義就是 Zookeeper 保存數據的目錄,默認情況下,Zookeeper 將寫數據的日誌文件也保存在這個目錄裏。
dataLogDir: Zookeeper的日誌文件位置。
server.A=B:C:D:其中 A 是一個數字,表示這個是第幾號服務器;B是這個服務器的 ip 地址;C 表示的是這個服務器與集群中的 Leader服務器交換信息的端口;D 表示的是萬一集群中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的 Leader,而這個端口就是用來執行選舉時服務器相互通信的端口。如果是偽集群的配置方式,由於 B 都是一樣,所以不同的 Zookeeper 實例通信端口號不能一樣,所以要給它們分配不同的端口號。
clientPort:這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。

  1. 同步 zookeeper 的配置以及相關目錄到其他兩臺服務中
scp -r /apps/svr/zookeeper-3.4.5 solr@192.168.0.3:/apps/svr
scp -r /apps/data/zookeeper-data solr@192.168.0.3:/apps/data


scp -r /apps/svr/zookeeper-3.4.5 solr@192.168.0.4:/apps/svr
scp -r /apps/data/zookeeper-data solr@192.168.0.4:/apps/data

  1. 創建 myid 文件存儲該機器的標識碼,比如 server.1 的標識碼就是 “1”,myid文件的內容就一行: 1

192.168.0.2

echo "1" >> /apps/data/zookeeper-data/myid

192.168.0.3

echo "2" >> /apps/data/zookeeper-data/myid

192.168.3

echo "3" >> /apps/data/zookeeper-data/myid
  1. 分別啟動三臺服務器的 zookeeper
cd /apps/svr/zookeeper-3.4.5/bin

./zkServer.sh start

查看 zookeeper 的狀態

[solr@SOLR-CLOUD-001 bin]$ ./zkServer.sh status
JMX enabled by default
Using config: /apps/svr/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: leader
[solr@SOLR-CLOUD-002 bin]$ ./zkServer.sh status
JMX enabled by default
Using config: /apps/svr/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: follower
[solr@SOLR-CLOUD-003 bin]$ ./zkServer.sh status
JMX enabled by default
Using config: /apps/svr/zookeeper-3.4.5/bin/../conf/zoo.cfg
Mode: follower

Solrcloud分布式集群搭建

  1. 解壓部署 tomcat - 解壓部署後的目錄為 /apps/svr/apache-tomcat-7.0.54
  2. 解壓 solr-4.8.1 的壓縮包,並且把 solr-4.8.1/example/webapps/solr.war 解壓至 /apps/svr/solr 目錄下
  3. 把 solr-4.8.1\example\lib\ext 下的 jar 包放到 solr\WEB-INF\lib 下
  4. 以 192.168.0.2 為例,創建以下目錄
mkdir -p /apps/svr/solrcloud/config-files
mkdir -p /apps/svr/solrcloud/solr-lib
  1. 把 solr/WEB-INF/lib 下的所有 jar 包拷貝到 /apps/svr/solrcloud/solr-lib 目錄
cp -av /apps/svr/solr/WEB-INF/lib/*.jar /apps/svr/solrcloud/solr-lib
  1. solr/example/solr/collection1/conf 下的所有文件拷貝到 /apps/svr/solrcloud/config-files 目錄
cp -av /apps/svr/solr/example/solr/collection1/conf/* /apps/svr/solrcloud/config-files/
  1. 將 /apps/svr/solr 目錄拷貝到 /apps/svr/apache-tomcat-7.0.54/webapps 目錄下面
cp -av /apps/svr/solr /apps/svr/apache-tomcat-7.0.54/webapps
  1. 創建 solr 的數據目錄 /apps/svr/solr-cores 並在該目錄下生成 solr.xml, 這是 solr 的核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>  
<solr persistent="true">  
<logging enabled="true">  
<watcher size="100" threshold="INFO" />  
</logging>  
<cores defaultCoreName="collection1" adminPath="/admin/cores" host="${host:}" hostPort="8080" hostContext="${hostContext:solr}" zkClientTimeout="${zkClientTimeout:15000}">
    <core numShards="3" name="test_shard1_replica1" instanceDir="test_shard1_replica1" shard="shard1" collection="test" coreNodeName="192.168.0.2:8080_solr_test_shard1_replica1"/>

    <core name="userinfo_shard1_replica3" instanceDir="userinfo_shard1_replica3" shard="shard1" collection="userinfo" coreNodeName="192.168.0.2:8080_solr_userinfo_shard1_replica3"/>

    <core name="userinfo_shard2_replica3" instanceDir="userinfo_shard2_replica3" shard="shard2" collection="userinfo" coreNodeName="192.168.0.3:8080_solr_userinfo_shard2_replica3"/>

    <core numShards="3" name="userinfo_shard3_replica1" instanceDir="userinfo_shard3_replica1" shard="shard3" collection="userinfo" coreNodeName="192.168.0.4:8080_solr_userinfo_shard3_replica1"/>
</cores>  
</solr> 

註:上面的配置文件中有 shard 的信息,那是因為我已經分片了自動生成的

原始的配置文件如下

<?xml version="1.0" encoding="UTF-8" ?>  
<solr persistent="true">  
<logging enabled="true">  
<watcher size="100" threshold="INFO" />  
</logging>  
<cores defaultCoreName="collection1" adminPath="/admin/cores" host="${host:}" hostPort="8080" hostContext="${hostContext:solr}" zkClientTimeout="${zkClientTimeout:15000}">  
</cores>  
</solr>  
  1. 創建/apps/svr/apache-tomcat-7.0.54/conf/Catalina 目錄 和 /apps/svr/apache-tomcat-7.0.54/conf/Catalina/localhost 目錄
mkdir -p /apps/svr/apache-tomcat-7.0.54/conf/Catalina
mkdir -p /apps/svr/apache-tomcat-7.0.54/conf/Catalina/localhost 
  1. 在 /apps/svr/apache-tomcat-7.0.54/conf/Catalina/localhost 下創建 solr.xml 文件,此文件為 Solr/home 的配置文件
<?xml version="1.0" encoding="UTF-8"?>  
<Context docBase="/apps/svr/tomcat-solr/webapps/solr" debug="0" crossContext="true">  
<Environment name="solr/home" type="java.lang.String" value="/apps/svr/solr-cores" override="true"/>  
</Context> 
  1. 修改 tomcat/bin/cataina.sh ,加入以下內容
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9060 -Djava.rmi.server.hostname=`/sbin/ifconfig bond0 |grep -a "inet addr:" |awk -F":" ‘{print $2}‘ |egrep -o ‘([0-9]{1,3}\.?){4}‘`"
CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
JAVA_OPTS="$JAVA_OPTS -DzkHost=GD6-SOLR-CLOUD-001:2181,GD6-SOLR-CLOUD-002:2181,GD6-SOLR-CLOUD-003:2181"
JAVA_OPTS="$JAVA_OPTS -Xmx8192m -Xms8192m -Xmn4g -Xss256k -XX:ParallelGCThreads=24 -XX:+UseConcMarkSweepGC -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintHeapAtGC -Xloggc:/apps/logs/tomcat/gc`date +%Y%m%d%H%M%S`.log -XX:ErrorFile=\"/apps/logs/tomcat/java_error.log\""
  1. 將以上配置同步到其他兩臺服務器
scp -r /apps/svr/apache-tomcat-7.0.54 solr@192.168.0.3:/apps/svr
scp -r /apps/svr/solrcloud solr@192.168.0.3:/apps/svr
scp -r /apps/svr/solr-cores solr@192.168.0.3:/apps/svr

scp -r /apps/svr/apache-tomcat-7.0.54 solr@192.168.0.4:/apps/svr
scp -r /apps/svr/solrcloud solr@192.168.0.4:/apps/svr
scp -r /apps/svr/solr-cores solr@192.168.0.4:/apps/svr

  1. SolrCloud 是通過 ZooKeeper 集群來保證配置文件的變更及時同步到各個節點上,所以,需要將配置文件上傳到 ZooKeeper 集群中:執行如下操作(以下ip均可使用域名進行操作)
java -classpath .:/apps/svr/solrcloud/solr-lib/* org.apache.solr.cloud.ZkCLI -cmd upconfig -zkhost 192.168.0.2:2181,192.168.0.3:2181,192.168.0.4:2181 -confdir /apps/svr/solrcloud/config-files/  -confname myconf
  1. 校驗 zookeeper 的配置文件
cd /apps/svr/zookeeper-3.4.5/bin
./zkCli.sh -server 192.168.0.2:2181
[zk: 192.168.01.2:2181(CONNECTED) 0] ls /  
[configs, collections, zookeeper]  
[zk: 192.168.01.2:2181(CONNECTED) 1] ls /configs  
[myconf]  
[zk: 192.168.01.2:2181(CONNECTED) 2] ls /configs/myconf  
[admin-extra.menu-top.html, currency.xml, protwords.txt, mapping-FoldToASCII.txt, solrconfig.xml, lang, stopwords.txt, spellings.txt, mapping-ISOLatin1Accent.txt, admin-extra.html, xslt, scripts.conf, synonyms.txt, update-script.js, velocity, elevate.xml, admin-extra.menu-bottom.html, schema.xml]  
[zk: 192.168.01.2:2181(CONNECTED) 3]  
  1. 啟動 tomcat ,首先啟動 master 192.168.0.2 上面的 tomcat
cd /apps/svr/apache-tomcat-7.0.54/bin
./startup.sh
  1. 啟動 192.168.0.3 和 192.168.0.4 的 tomcat
  2. 訪問 http://192.168.0.2:8080/solr 可以看到下圖
    技術分享圖片

創建 Collection 及初始 Shard

 curl ‘http://192.168.0.2:8080/solr/admin/collections?action=CREATE&name=userinfo&numShards=3&replicationFactor=1‘

 curl ‘http://192.168.0.2:8080/solr/admin/collections?action=CREATE&name=userinfo&numShards=3&replicationFactor=1‘

 curl ‘http://192.168.0.2:8080/solr/admin/collections?action=CREATE&name=userinfo&numShards=3&replicationFactor=1

技術分享圖片

對 solrcloud 做讀寫性能測試的 demo

import java.io.IOException;  
import java.util.ArrayList;  
import java.util.Collection;  

import org.apache.solr.client.solrj.SolrQuery;  
import org.apache.solr.client.solrj.SolrServer;  
import org.apache.solr.client.solrj.SolrServerException;  
import org.apache.solr.client.solrj.impl.CloudSolrServer;  
import org.apache.solr.client.solrj.response.QueryResponse;  
import org.apache.solr.common.SolrDocument;  
import org.apache.solr.common.SolrDocumentList;  
import org.apache.solr.common.SolrInputDocument;  
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;   

public class SolrCloudTest {        
        public static final Log LOG = LogFactory.getLog(SolrCloudTest.class);
        private static CloudSolrServer cloudSolrServer;    

        private  static synchronized CloudSolrServer getCloudSolrServer(final String zkHost) {    
         LOG.info("connect to :"+zkHost+"\n");
            if(cloudSolrServer == null) {    
                try {    
                    cloudSolrServer = new CloudSolrServer(zkHost);    
                }catch(Exception e) {    
                    e.printStackTrace();                    
                }    
            }                    
            return cloudSolrServer;    
        }    

        private void addIndex(SolrServer solrServer) {          
            try {
                   Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
                   for (int i = 0;i<=200;i++){
                            SolrInputDocument doc = new SolrInputDocument();
                            String key = "";
                            key = String.valueOf(i);
                            doc.addField("id", key);
                            doc.addField("test_s", key+"value");
                            docs.add(doc);                   
                   }     
                LOG.info("docs info:"+docs+"\n");
                solrServer.add(docs);               
                solrServer.commit();                    
            }catch(SolrServerException e) {    
                System.out.println("Add docs Exception !!!");    
                e.printStackTrace();            
            }catch(IOException e){    
                e.printStackTrace();    
            }catch (Exception e) {    
                System.out.println("Unknowned Exception!!!!!");    
                e.printStackTrace();    
            }                          
        }                         

        public void search(SolrServer solrServer, String Str) {          
            SolrQuery query = new SolrQuery();
            query.setRows(20);
            query.setQuery(Str);    
            try {  
                   LOG.info("query string: "+ Str);
                   System.out.println("query string: "+ Str);
                QueryResponse response = solrServer.query(query);    
                SolrDocumentList docs = response.getResults();
                System.out.println(docs);
                System.out.println(docs.size());
                System.out.println("doc num:" + docs.getNumFound());    
                System.out.println("elapse time:" + response.getQTime());            
                for (SolrDocument doc : docs) {    
                    String area = (String) doc.getFieldValue("test_s");    
                    String id = (String) doc.getFieldValue("id");    
                    System.out.println("id: " + id);    
                    System.out.println("tt_s: " + area);    
                    System.out.println();    
                }    
            } catch (SolrServerException e) {    
                e.printStackTrace();    
            } catch(Exception e) {    
                e.printStackTrace();    
            }    
        } 

        public static void main(String[] args) {      
                final String zkHost = "192.168.0.2:8080";         
                final String  defaultCollection = "userinfo";    
                final int  zkClientTimeout = 10000;    
                final int zkConnectTimeout = 10000;                      
                CloudSolrServer cloudSolrServer = getCloudSolrServer(zkHost);                     
                cloudSolrServer.setDefaultCollection(defaultCollection);    
                cloudSolrServer.setZkClientTimeout(zkClientTimeout);    
                cloudSolrServer.setZkConnectTimeout(zkConnectTimeout); 
                try{
                   cloudSolrServer.connect();
                    System.out.println("connect solr cloud zk sucess");                 
                } catch (Exception e){    
                   LOG.error("connect to collection "+defaultCollection+" error\n");
                   System.out.println("error message is:"+e);
                   e.printStackTrace();
                   System.exit(1);
                }
                SolrCloudTest solrt = new SolrCloudTest();
                try{
                   solrt.addIndex(cloudSolrServer);
                } catch(Exception e){
                   e.printStackTrace();
                }
                solrt.search(cloudSolrServer, "id:*");            ;   
                cloudSolrServer.shutdown();            
        }          
    }  

總結

最後為了快速部署,其實這個過程可以使用 fabric 來進行部署,這樣就不用每次進行重復操作,把上面的步驟整理成 fabric 腳本即可,這樣不管是搭建多少臺服務器的集群,只要幾分鐘即可搞定。

170825、SolrCloud 分布式集群部署步驟