1. 學習計劃 1、solr集群搭建 2、使用solrj管理solr集群 3、把搜索功能切換到集群版 4、添加商品同步索引庫。 a) Activemq b) 發送消息 c) 接收消息 2. 什麼是SolrCloud SolrCloud(solr 雲)是Solr提供的分散式搜索方案,當你需要大規模,容 ...
1. 學習計劃
1、solr集群搭建
2、使用solrj管理solr集群
3、把搜索功能切換到集群版
4、添加商品同步索引庫。
a) Activemq
b) 發送消息
c) 接收消息
2. 什麼是SolrCloud
SolrCloud(solr 雲)是Solr提供的分散式搜索方案,當你需要大規模,容錯,分散式索引和檢索能力時使用 SolrCloud。當一個系統的索引數據量少的時候是不需要使用SolrCloud的,當索引量很大,搜索請求併發很高,這時需要使用SolrCloud來滿足這些需求。
SolrCloud是基於Solr和Zookeeper的分散式搜索方案,它的主要思想是使用Zookeeper作為集群的配置信息中心。
它有幾個特色功能:
1)集中式的配置信息
2)自動容錯
3)近實時搜索
4)查詢時自動負載均衡
3. Solr集群的系統架構
3.1. 物理結構
三個Solr實例( 每個實例包括兩個Core),組成一個SolrCloud。
3.2. 邏輯結構
索引集合包括兩個Shard(shard1和shard2),shard1和shard2分別由三個Core組成,其中一個Leader兩個Replication,Leader是由zookeeper選舉產生,zookeeper控制每個shard上三個Core的索引數據一致,解決高可用問題。
用戶發起索引請求分別從shard1和shard2上獲取,解決高併發問題。
3.2.1. collection
Collection在SolrCloud集群中是一個邏輯意義上的完整的索引結構。它常常被劃分為一個或多個Shard(分片),它們使用相同的配置信息。
比如:針對商品信息搜索可以創建一個collection。
collection=shard1+shard2+....+shardX
3.2.2. Core
每個Core是Solr中一個獨立運行單位,提供 索引和搜索服務。一個shard需要由一個Core或多個Core組成。由於collection由多個shard組成所以collection一般由多個core組成。
3.2.3. Master或Slave
Master是master-slave結構中的主結點(通常說主伺服器),Slave是master-slave結構中的從結點(通常說從伺服器或備伺服器)。同一個Shard下master和slave存儲的數據是一致的,這是為了達到高可用目的。
3.2.4. Shard
Collection的邏輯分片。每個Shard被化成一個或者多個replication,通過選舉確定哪個是Leader。
3.3. 需要實現的solr集群架構
Zookeeper作為集群的管理工具。
1、集群管理:容錯、負載均衡。
2、配置文件的集中管理
3、集群的入口
需要實現zookeeper 高可用。需要搭建集群。建議是奇數節點。需要三個zookeeper伺服器。
搭建solr集群需要7台伺服器。
搭建偽分散式:
需要三個zookeeper節點
需要四個tomcat節點。
建議虛擬機的內容1G以上。
4. 環境準備
CentOS-6.5-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
5. 安裝步驟
5.1. Zookeeper集群搭建
第一步:需要安裝jdk環境。
第二步:把zookeeper的壓縮包上傳到伺服器。
第三步:解壓縮。
第四步:把zookeeper複製三份。
[root@localhost ~]# mkdir /usr/local/solr-cloud
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper01
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper02
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper03
第五步:在每個zookeeper目錄下創建一個data目錄。
第六步:在data目錄下創建一個myid文件,文件名就叫做“myid”。內容就是每個實例的id。例如1、2、3
[root@localhost data]# echo 1 >> myid
[root@localhost data]# ll
total 4
-rw-r--r--. 1 root root 2 Apr 7 18:23 myid
[root@localhost data]# cat myid
1
第七步:修改配置文件。把conf目錄下的zoo_sample.cfg文件改名為zoo.cfg
server.1=192.168.25.132:2881:3881 server.2=192.168.25.132:2882:3882 server.3=192.168.25.132:2883:3883 |
第八步:啟動每個zookeeper實例。
啟動bin/zkServer.sh start
查看zookeeper的狀態:
bin/zkServer.sh status
5.2. Solr集群的搭建
第一步:創建四個tomcat實例。每個tomcat運行在不同的埠。8180、8280、8380、8480
第二步:部署solr的war包。把單機版的solr工程複製到集群中的tomcat中。
第三步:為每個solr實例創建一個對應的solrhome。使用單機版的solrhome複製四份。
第四步:需要修改solr的web.xml文件。把solrhome關聯起來。
第五步:配置solrCloud相關的配置。每個solrhome下都有一個solr.xml,把其中的ip及埠號配置好。
第六步:讓zookeeper統一管理配置文件。需要把solrhome/collection1/conf目錄上傳到zookeeper。上傳任意solrhome中的配置文件即可。
使用工具上傳配置文件:/root/solr-4.10.3/example/scripts/cloud-scripts/zkcli.sh
./zkcli.sh -zkhost 192.168.25.132:2181,192.168.25.132:2182,192.168.25.132:2183 -cmd upconfig -confdir /usr/local/solr-cloud/solrhome01/collection1/conf -confname myconf |
查看zookeeper上的配置文件:
使用zookeeper目錄下的bin/zkCli.sh命令查看zookeeper上的配置文件:
[root@localhost bin]# ./zkCli.sh
[zk: localhost:2181(CONNECTED) 0] ls /
[configs, zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /configs
[myconf]
[zk: localhost:2181(CONNECTED) 2] ls /configs/myconf
[admin-extra.menu-top.html, currency.xml, protwords.txt, mapping-FoldToASCII.txt, _schema_analysis_synonyms_english.json, _rest_managed.json, solrconfig.xml, _schema_analysis_stopwords_english.json, stopwords.txt, lang, spellings.txt, mapping-ISOLatin1Accent.txt, admin-extra.html, xslt, synonyms.txt, scripts.conf, update-script.js, velocity, elevate.xml, admin-extra.menu-bottom.html, clustering, schema.xml]
[zk: localhost:2181(CONNECTED) 3]
退出:
[zk: localhost:2181(CONNECTED) 3] quit
使用以下命令連接指定的zookeeper服務: ./zkCli.sh -server 192.168.25.132:2183 |
第七步:修改tomcat/bin目錄下的catalina.sh 文件,關聯solr和zookeeper。
把此配置添加到配置文件中:
JAVA_OPTS="-DzkHost=192.168.25.132:2181,192.168.25.132:2182,192.168.25.132:2183"
第八步:啟動每個tomcat實例。要保證zookeeper集群是啟動狀態。
第九步:訪問集群
第十步:創建新的Collection進行分片處理。
http://192.168.25.132:8180/solr/admin/collections?action=CREATE&name=collection2&numShards=2&replicationFactor=2
第十一步:刪除不用的Collection。
http://192.168.25.132:8180/solr/admin/collections?action=DELETE&name=collection1
6. 使用solrJ管理集群
6.1. 添加文檔
使用步驟:
第一步:把solrJ相關的jar包添加到工程中。
第二步:創建一個SolrServer對象,需要使用CloudSolrServer子類。構造方法的參數是zookeeper的地址列表。
第三步:需要設置DefaultCollection屬性。
第四步:創建一SolrInputDocument對象。
第五步:向文檔對象中添加域
第六步:把文檔對象寫入索引庫。
第七步:提交。
@Test public void testSolrCloudAddDocument() throws Exception { // 第一步:把solrJ相關的jar包添加到工程中。 // 第二步:創建一個SolrServer對象,需要使用CloudSolrServer子類。構造方法的參數是zookeeper的地址列表。 //參數是zookeeper的地址列表,使用逗號分隔 CloudSolrServer solrServer = new CloudSolrServer("192.168.25.132:2181,192.168.25.132:2182,192.168.25.132:2183"); // 第三步:需要設置DefaultCollection屬性。 solrServer.setDefaultCollection("collection2"); // 第四步:創建一SolrInputDocument對象。 SolrInputDocument document = new SolrInputDocument(); // 第五步:向文檔對象中添加域 document.addField("item_title", "測試商品"); document.addField("item_price", "100"); document.addField("id", "test001"); // 第六步:把文檔對象寫入索引庫。 solrServer.add(document); // 第七步:提交。 solrServer.commit(); }
6.2. 查詢文檔
創建一個CloudSolrServer對象,其他處理和單機版一致。
7. 把搜索功能切換到集群版
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util4.2.xsd"> <!-- 單機版solr服務配置 --> <!-- <bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg name="baseURL" value="http://192.168.25.132:8080/solr"></constructor-arg> </bean> --> <!-- 集群版solr服務 --> <bean id="cloudSolrServer" class="org.apache.solr.client.solrj.impl.CloudSolrServer"> <constructor-arg name="zkHost" value="192.168.25.132:2181,192.168.25.132:2182,192.168.25.132:2183"></constructor-arg> <property name="defaultCollection" value="collection2"></property> </bean> </beans>
8. 全局異常處理
8.1. 處理思路
8.2. 創建全局異常處理器
public class GlobalExceptionReslover implements HandlerExceptionResolver { Logger logger = LoggerFactory.getLogger(GlobalExceptionReslover.class); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { //寫日誌文件 logger.error("系統發生異常", ex); //發郵件、發簡訊 //Jmail:可以查找相關的資料 //需要在購買簡訊。調用第三方介面即可。 //展示錯誤頁面 ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("message", "系統發生異常,請稍後重試"); modelAndView.setViewName("error/exception"); return modelAndView; } }
8.3. Springmvc中配置異常處理器
9. 同步索引庫分析
方案一:在taotao-manager中,添加商品的業務邏輯中,添加一個同步索引庫的業務邏輯。
缺點:業務邏輯耦合度高,業務拆分不明確
方案二:業務邏輯在taotao-search中實現,調用服務在taotao-manager實現。業務邏輯分開。
缺點:服務之間的耦合度變高。服務的啟動有先後順序。
方案三:使用消息隊列。MQ是一個消息中間件。
MQ是一個消息中間件,ActiveMQ、RabbitMQ、kafka
10. ActiveMQ
10.1. 什麼是ActiveMQ
ActiveMQ 是Apache出品,最流行的,能力強勁的開源消息匯流排。ActiveMQ 是一個完全支持JMS1.1和J2EE 1.4規範的 JMS Provider實現,儘管JMS規範出台已經是很久的事情了,但是JMS在當今的J2EE應用中間仍然扮演著特殊的地位。
主要特點:
1. 多種語言和協議編寫客戶端。語言: Java, C, C++, C#, Ruby, Perl, Python, PHP。應用協議: OpenWire,Stomp REST,WS Notification,XMPP,AMQP
2. 完全支持JMS1.1和J2EE 1.4規範 (持久化,XA消息,事務)
3. 對Spring的支持,ActiveMQ可以很容易內嵌到使用Spring的系統裡面去,而且也支持Spring2.0的特性
4. 通過了常見J2EE伺服器(如 Geronimo,JBoss 4, GlassFish,WebLogic)的測試,其中通過JCA 1.5 resource adaptors的配置,可以讓ActiveMQ可以自動的部署到任何相容J2EE 1.4 商業伺服器上
5. 支持多種傳送協議:in-VM,TCP,SSL,NIO,UDP,JGroups,JXTA
6. 支持通過JDBC和journal提供高速的消息持久化
7. 從設計上保證了高性能的集群,客戶端-伺服器,點對點
8. 支持Ajax
9. 支持與Axis的整合
10. 可以很容易得調用內嵌JMS provider,進行測試
10.2. ActiveMQ的消息形式
對於消息的傳遞有兩種類型:
一種是點對點的,即一個生產者和一個消費者一一對應;
另一種是發佈/訂閱模式,即一個生產者產生消息併進行發送後,可以由多個消費者進行接收。
JMS定義了五種不同的消息正文格式,以及調用的消息類型,允許你發送並接收以一些不同形式的數據,提供現有消息格式的一些級別的相容性。
· StreamMessage -- Java原始值的數據流
· MapMessage--一套名稱-值對
· TextMessage--一個字元串對象
· ObjectMessage--一個序列化的 Java對象
· BytesMessage--一個位元組的數據流
11. ActiveMQ的安裝
進入http://activemq.apache.org/下載ActiveMQ
使用的版本是5.12.0
11.1. 安裝環境:
1、需要jdk
2、安裝Linux系統。生產環境都是Linux系統。
11.2. 安裝步驟
第一步: 把ActiveMQ 的壓縮包上傳到Linux系統。
第二步:解壓縮。
第三步:啟動。
使用bin目錄下的activemq命令啟動:
[root@localhost bin]# ./activemq start
關閉:
[root@localhost bin]# ./activemq stop
查看狀態:
[root@localhost bin]# ./activemq status
註意:如果ActiveMQ整合spring使用不要使用activemq-all-5.12.0.jar包。建議使用5.11.2
進入管理後臺:
http://192.168.25.168:8161/admin
用戶名:admin
密碼:admin
11.3. 解決405問題:
修改hosts文件,配置機器名和127.0.0.1的映射關係。
機器名:/etc/sysconfig/network文件中定義了機器名:
Host文件的配置:
重新啟動Activemq的服務
12. ActiveMQ的使用方法
12.1. Queue
12.1.1. Producer
生產者:生產消息,發送端。
把jar包添加到工程中。使用5.11.2版本的jar包。
第一步:創建ConnectionFactory對象,需要指定服務端ip及埠號。
第二步:使用ConnectionFactory對象創建一個Connection對象。
第三步:開啟連接,調用Connection對象的start方法。
第四步:使用Connection對象創建一個Session對象。
第五步:使用Session對象創建一個Destination對象(topic、queue),此處創建一個Queue對象。
第六步:使用Session對象創建一個Producer對象。
第七步:創建一個Message對象,創建一個TextMessage對象。
第八步:使用Producer對象發送消息。
第九步:關閉資源。
@Test public void testQueueProducer() throws Exception { // 第一步:創建ConnectionFactory對象,需要指定服務端ip及埠號。 //brokerURL伺服器的ip及埠號 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616"); // 第二步:使用ConnectionFactory對象創建一個Connection對象。 Connection connection = connectionFactory.createConnection(); // 第三步:開啟連接,調用Connection對象的start方法。 connection.start(); // 第四步:使用Connection對象創建一個Session對象。 //第一個參數:是否開啟事務。true:開啟事務,第二個參數忽略。 //第二個參數:當第一個參數為false時,才有意義。消息的應答模式。1、自動應答2、手動應答。一般是自動應答。 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session對象創建一個Destination對象(topic、queue),此處創建一個Queue對象。 //參數:隊列的名稱。 Queue queue = session.createQueue("test-queue"); // 第六步:使用Session對象創建一個Producer對象。 MessageProducer producer = session.createProducer(queue); // 第七步:創建一個Message對象,創建一個TextMessage對象。 /*TextMessage message = new ActiveMQTextMessage(); message.setText("hello activeMq,this is my first test.");*/ TextMessage textMessage = session.createTextMessage("hello activeMq,this is my first test."); // 第八步:使用Producer對象發送消息。 producer.send(textMessage); // 第九步:關閉資源。 producer.close(); session.close(); connection.close(); }
12.1.2. Consumer
消費者:接收消息。
第一步:創建一個ConnectionFactory對象。
第二步:從ConnectionFactory對象中獲得一個Connection對象。
第三步:開啟連接。調用Connection對象的start方法。
第四步:使用Connection對象創建一個Session對象。
第五步:使用Session對象創建一個Destination對象。和發送端保持一致queue,並且隊列的名稱一致。
第六步:使用Session對象創建一個Consumer對象。
第七步:接收消息。
第八步:列印消息。
第九步:關閉資源
@Test public void testQueueConsumer() throws Exception { // 第一步:創建一個ConnectionFactory對象。 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616"); // 第二步:從ConnectionFactory對象中獲得一個Connection對象。 Connection connection = connectionFactory.createConnection(); // 第三步:開啟連接。調用Connection對象的start方法。 connection.start(); // 第四步:使用Connection對象創建一個Session對象。 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session對象創建一個Destination對象。和發送端保持一致queue,並且隊列的名稱一致。 Queue queue = session.createQueue("test-queue"); // 第六步:使用Session對象創建一個Consumer對象。 MessageConsumer consumer = session.createConsumer(queue); // 第七步:接收消息。 consumer.setMessageListener(new MessageListener() { @Override public void onMessage(Message message) { try { TextMessage textMessage = (TextMessage) message; String text = null; //取消息的內容 text = textMessage.getText(); // 第八步:列印消息。 System.out.println(text); } catch (JMSException e) { e.printStackTrace(); } } }); //等待鍵盤輸入 System.in.read(); // 第九步:關閉資源 consumer.close(); session.close(); connection.close(); }
12.2. Topic
12.2.1. Producer
使用步驟:
第一步:創建ConnectionFactory對象,需要指定服務端ip及埠號。
第二步:使用ConnectionFactory對象創建一個Connection對象。
第三步:開啟連接,調用Connection對象的start方法。
第四步:使用Connection對象創建一個Session對象。
第五步:使用Session對象創建一個Destination對象(topic、queue),此處創建一個Topic對象。
第六步:使用Session對象創建一個Producer對象。
第七步:創建一個Message對象,創建一個TextMessage對象。
第八步:使用Producer對象發送消息。
第九步:關閉資源。
@Test public void testTopicProducer() throws Exception { // 第一步:創建ConnectionFactory對象,需要指定服務端ip及埠號。 // brokerURL伺服器的ip及埠號 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616"); // 第二步:使用ConnectionFactory對象創建一個Connection對象。 Connection connection = connectionFactory.createConnection(); // 第三步:開啟連接,調用Connection對象的start方法。 connection.start(); // 第四步:使用Connection對象創建一個Session對象。 // 第一個參數:是否開啟事務。true:開啟事務,第二個參數忽略。 // 第二個參數:當第一個參數為false時,才有意義。消息的應答模式。1、自動應答2、手動應答。一般是自動應答。 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session對象創建一個Destination對象(topic、queue),此處創建一個topic對象。 // 參數:話題的名稱。 Topic topic = session.createTopic("test-topic"); // 第六步:使用Session對象創建一個Producer對象。 MessageProducer producer = session.createProducer(topic); // 第七步:創建一個Message對象,創建一個TextMessage對象。 /* * TextMessage message = new ActiveMQTextMessage(); message.setText( * "hello activeMq,this is my first test."); */ TextMessage textMessage = session.createTextMessage("hello activeMq,this is my topic test"); // 第八步:使用Producer對象發送消息。 producer.send(textMessage); // 第九步:關閉資源。 producer.close(); session.close(); connection.close(); }
12.2.2. Consumer
消費者:接收消息。
第一步:創建一個ConnectionFactory對象。
第二步:從ConnectionFactory對象中獲得一個Connection對象。
第三步:開啟連接。調用Connection對象的start方法。
第四步:使用Connection對象創建一個Session對象。
第五步:使用Session對象創建一個Destination對象。和發送端保持一致topic,並且話題的名稱一致。
第六步:使用Session對象創建一個Consumer對象。
第七步:接收消息。
第八步:列印消息。
第九步:關閉資源
@Test public void testTopicConsumer() throws Exception { // 第一步:創建一個ConnectionFactory對象。 ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.168:61616"); // 第二步:從ConnectionFactory對象中獲得一個Connection對象。 Connection connection = connectionFactory.createConnection(); // 第三步:開啟連接。調用Connection對象的start方法。 connection.start(); // 第四步:使用Connection對象創建一個Session對象。 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); // 第五步:使用Session對象創建一個Destination對象。和發送端保