咱們之因此要學習集羣,是由於單點服務器,存在一系列的問題。node
咱們之前學習的JavaEE項目,都是部署在一臺Tomcat上,全部的請求,都由這一臺服務器處理,存在很大風險:apache
A:併發處理能力有限。由於單服務器的性能有限制。因此單臺Tomcat的最大鏈接數有限制,編程
B:容錯率低,一旦服務器故障,整個服務就沒法訪問了。緩存
eBay於 1999年6月停機22小時的事故,中斷了約230萬的拍賣,使eBay的股票降低了9.2個百分點。tomcat
C:單臺服務器計算能力低,沒法完成複雜的海量數據計算。服務器
提升CPU主頻和總線帶寬是最初提供計算機性能的主要手段。可是這一手段對系統性能的提供是有限的。接着人們經過增長CPU個數和內存容量來提升性能,因而出現了向量機,對稱多處理機(SMP)等。可是當CPU的個數超過某一閾值,這些多處理機系統的可擴展性就變的極差。主要瓶頸在於CPU訪問內存的帶寬並不能隨着CPU個數的增長而有效增加。與SMP相反,集羣系統的性能隨着CPU個數的增長几乎是線性變化的網絡
集羣是是指將多臺服務器集中在一塊兒,每臺服務器都實現相同的業務,作相同的事情。可是每臺服務器並非缺一不可,存在的做用主要是緩解併發壓力和單點故障轉移問題。能夠利用一些廉價的符合工業標準的硬件構造高性能的系統。實現:高擴展、高性能、低成本、高可用!架構
注意:該圖中最大的特色就是,每一個Tomcat都完成相同的業務,可是分擔着不一樣用戶的訪問,它們並非缺一不可,若是一個Tomcat出現故障,網站依舊能夠運行。併發
伸縮性(Scalability)app
在一些大的系統中,預測最終用戶的數量和行爲是很是困難的,伸縮性是指系統適應不斷增加的用戶數的能力。提升這種併發會話能力的一種最直觀的方式就增長資源(CPU,內存,硬盤等),集羣是解決這個問題的另外一種方式,它容許一組服務器組在一塊兒,像單個服務器同樣分擔處理一個繁重的任務,咱們只須要將新的服務器加入集羣中便可,對於客戶來看,服務不管從連續性仍是性能上都幾乎沒有變化,好像系統在不知不覺中完成了升級
高可用性(High availability)
單一服務器的解決方案並非一個健壯方式,由於容易出現單點失效。像銀行、帳單處理這樣一些關鍵的應用程序是不能容忍哪怕是幾分鐘的死機。它們須要這樣一些服務在任什麼時候間均可以訪問並在可預期的合理的時間週期內有響應。高可用性集羣的出現是爲了使集羣的總體服務儘量可用,以便考慮計算硬件和軟件的易錯性。若是高可用性集羣中的主節點發生了故障,那麼這段時間內將由次節點代替它。次節點一般是主節點的鏡像,因此當它代替主節點時,它能夠徹底接管其身份,而且所以使系統環境對於用戶是一致的。
負載均衡(Load balancing)
負載均衡集羣爲企業需求提供了更實用的系統。如名稱所暗示的,該系統使負載能夠在計算機集羣中儘量平均地分攤處理。該負載多是須要均衡的應用程序處理負載或網絡流量負載。這樣的系統很是適合於運行同一組應用程序的大量用戶。每一個節點均可以處理一部分負載,而且能夠在節點之間動態分配負載,以實現平衡。
高性能 (High Performance )
一般,第一種涉及爲集羣開發並行編程應用程序,以解決複雜的科學問題。這是並行計算的基礎,儘管它不使用專門的並行超級計算機,這種超級計算機內部由十至上萬個獨立處理器組成。但它卻使用商業系統,如經過高速鏈接來連接的一組單處理器或雙處理器 PC,而且在公共消息傳遞層上進行通訊以運行並行應用程序。所以,您會經常據說又有一種便宜的 Linux 超級計算機問世了。但它實際是一個計算機集羣,其處理能力與真的超級計算機相等
A:系統過於龐大,開發維護困難
B:功能間耦合度過高
C:沒法針對單個模塊進行優化
D:沒法進行水平擴展
分佈式是指將多臺服務器集中在一塊兒,每臺服務器都實現整體中的不一樣業務,作不一樣的事情。而且每臺服務器都缺一不可,若是某臺服務器故障,則網站部分功能缺失,或致使總體沒法運行。存在的主要做用是大幅度的提升效率,緩解服務器的訪問和存儲壓力。
注意:該圖中最大特色是:每一個Web服務器(Tomcat)程序都負責一個網站中不一樣的功能,缺一不可。若是某臺服務器故障,則對應的網站功能缺失,也能夠致使其依賴功能甚至所有功能都不可以使用。
所以,分佈式系統須要運行在集羣服務器中,甚至分佈式系統的每一個不一樣子任務均可以部署集羣
通常分佈式中的每個節點,均可以作集羣。這樣的系統架構,咱們一般稱爲分佈式集羣架構。
通常狀況下,若是沒有特別說明,代理技術默認說的是正向代理技術。關於正向代理的概念以下: 正向代理(forward)是一個位於客戶端【用戶A】和原始服務器(origin server)【服務器B】之間的服務器【代理服務器Z】,爲了從原始服務器取得內容,用戶A向代理服務器Z發送一個請求並指定目標(服務器B),而後代理服務器Z向服務器B轉交請求並將得到的內容返回給客戶端。客戶端必需要進行一些特別的設置才能使用正向代理。
簡單來講,正向代理就是代理服務器替代訪問方【用戶A】去訪問目標服務器【服務器B】
爲何須要使用正向代理?
great firewall
被服務器屏蔽(wow)
若是在用戶A訪問服務器B某數據J以前,已經有人經過代理服務器Z訪問過服務器B上得數據J,那麼代理服務器Z會把數據J保存一段時間,若是有人正好取該數據J,那麼代理服務器Z再也不訪問服務器B,而把緩存的數據J直接發給用戶A。
服務器B並不知道訪問本身的實際是用戶A,由於代理服務器Z代替用戶A去直接與服務器B進行交互。若是代理服務器Z被用戶A徹底控制(或不徹底控制),會慣以「肉雞」術語稱呼。
總結一下:正向代理是一個位於客戶端和原始服務器(origin server)之間的服務器,爲了從原始服務器取得內容,客戶端向代理髮送一個請求並指定目標(原始服務器),而後代理向原始服務器轉交請求並將得到的內容返回給客戶端。客戶端必須設置正向代理服務器,固然前提是要知道正向代理服務器的IP地址,還有代理程序的端口。
反向代理正好與正向代理相反,對於客戶端而言代理服務器就像是原始服務器,而且客戶端不須要進行任何特別的設置。客戶端向反向代理的命名空間(name-space)中的內容發送普通請求,接着反向代理將判斷向何處(原始服務器)轉交請求,並將得到的內容返回給客戶端。 使用反向代理服務器的做用以下:
用戶A始終認爲它訪問的是原始服務器B而不是代理服務器Z,但實用際上反向代理服務器接受用戶A的應答,從原始資源服務器B中取得用戶A的需求資源,而後發送給用戶A。因爲防火牆的做用,只容許代理服務器Z訪問原始資源服務器B。在這個虛擬的環境下,防火牆和反向代理的共同做用保護了原始資源服務器B,但用戶A並不知情。
當反向代理服務器不止一個的時候,咱們甚至能夠把它們作成集羣,當更多的用戶訪問資源服務器B的時候,讓不一樣的代理服務器Z(x)去應答不一樣的用戶,而後發送不一樣用戶須要的資源。
並且反向代理服務器像正向代理服務器同樣擁有CACHE的做用,它能夠緩存原始資源服務器B的資源,而不是每次都要向原始資源服務器B請求數據,特別是一些靜態的數據,好比圖片和文件。
簡單來講,反向代理就是反向代理服務器替代原始服務器【服務器B】讓【用戶A】去訪問
Zookeeper是集羣分佈式中大管家
分佈式集羣系統比較複雜,子模塊不少,可是子模塊每每不是孤立存在的,它們彼此之間須要協做和交互,各個子系統就比如動物園裏的動物,爲了使各個子系統能正常爲用戶提供統一的服務,必須須要一種機制來進行協調——這就是ZooKeeper
Zookeeper 是爲分佈式應用程序提供高性能協調服務的工具集合,也是Google的Chubby一個開源的實現,是Hadoop 的分佈式協調服務。
在ZooKeeper集羣當中,集羣中的服務器角色有兩種:1個Leader和多個Follower,具體功能以下:
1)領導者(leader),負責進行投票的發起和決議,監控集羣中的(follower)是否存活(心跳機制),進行分配資源
2)follower用於接受客戶端請求並向客戶端返回結果,在選主過程當中參與投票
特色:
A:Zookeeper:一個leader,多個follower組成的集羣
B:全局數據一致:每一個server保存一份相同的數據副本,client不管鏈接到哪一個server,數據都是一致的
C:數據更新原子性,一次數據更新要麼成功,要麼失敗
D:實時性,在必定時間範圍內,client能讀到最新數據
E:半數機制:整個集羣中只要有一半以上存活,就能夠提供服務。所以一般Zookeeper由2n+1臺servers組成,每一個server都知道彼此的存在。每一個server都維護的內存狀態鏡像以及持久化存儲的事務日誌和快照。爲了保證Leader選舉能過獲得多數的支持,因此ZooKeeper集羣的數量通常爲奇數。對於2n+1臺server,只要有n+1臺(大多數)server可用,整個系統保持可用
以一個簡單的例子來講明整個選舉的過程.
假設有五臺服務器組成的zookeeper集羣,它們的id從1-5,同時它們都是最新啓動的,也就是沒有歷史數據,在存放數據量這一點上,都是同樣的.假設這些服務器依序啓動,來看看會發生什麼.
1) 服務器1啓動,此時只有它一臺服務器啓動了,它發出去的報沒有任何響應,因此它的選舉狀態一直是LOOKING狀態
2) 服務器2啓動,它與最開始啓動的服務器1進行通訊,互相交換本身的選舉結果,因爲二者都沒有歷史數據,因此id值較大的服務器2勝出,可是因爲沒有達到超過半數以上的服務器都贊成選舉它(這個例子中的半數以上是3),因此服務器1,2仍是繼續保持LOOKING狀態.
3) 服務器3啓動,根據前面的理論分析,服務器3成爲服務器1,2,3中的老大,而與上面不一樣的是,此時有三臺服務器選舉了它,因此它成爲了此次選舉的leader.
4) 服務器4啓動,根據前面的分析,理論上服務器4應該是服務器1,2,3,4中最大的,可是因爲前面已經有半數以上的服務器選舉了服務器3,因此它只能接收當小弟的命了.
5) 服務器5啓動,同4同樣,當小弟.
那麼,初始化的時候,是按照上述的說明進行選舉的,可是當zookeeper運行了一段時間以後,有機器down掉,從新選舉時,選舉過程就相對複雜了。
須要加入數據id、leader id和邏輯時鐘。
數據id:數據新的id就大,數據每次更新都會更新id。
Leader id:就是咱們配置的myid中的值,每一個機器一個。
邏輯時鐘:這個值從0開始遞增,每次選舉對應一個值,也就是說: 若是在同一次選舉中,那麼這個值應該是一致的 ; 邏輯時鐘值越大,說明這一次選舉leader的進程最新.
選舉的標準就變成:
一、邏輯時鐘小的選舉結果被忽略,從新投票
二、統一邏輯時鐘後,數據id大的勝出
三、數據id相同的狀況下,leader id大的勝出
根據這個規則選出leader。
Zookeeper包含一個簡單的原語集,分佈式應用程序能夠基於它實現命名服務、配置維護、集羣選主等:
命名服務:註冊節點信息,造成有層次的目錄結構(相似Java的包名)。
配置維護:配置信息的統一管理和動態切換
集羣選主:確保整個集羣中只有一個主,其它爲從。而且當主掛了後,能夠重新選主
單點的Solr服務的問題:
A:能存儲的數據量有限,若是是海量數據,沒法存儲
B:容易出現單點故障
C:對高併發的處理能力差
若是咱們的須要處理海量數據、應對高併發請求,而且讓咱們的服務實現高可用。那麼就必需要搭建SolrCloud了。反之,若是數據量不多,請求併發低的狀況下,是不須要SolrCloud的,單點Solr就夠了
SolrCloud(solr 雲)是Solr提供的分佈式搜索方案,能夠解決海量數據的 分佈式全文檢索,由於搭建了集羣,所以具有高可用的特性,同時對數據進行主從備份,避免了單點故障問題。能夠作到數據的快速恢復。而且能夠動態的添加新的節點,再對數據進行平衡
爲了實現海量數據的存儲,咱們會把索引進行分片(Shard),把分片後的數據存儲到不一樣Solr節點。
爲了保證節點數據的高可用,避免單點故障,咱們又會對每個Shard進行復制,產生不少副本(Replicas),每個副本對於一個Solr節點中的一個core
用戶訪問的時候,能夠訪問任何一個會被自動分配到任何一個可用副本進行查詢,這樣就實現了負載均衡。
邏輯結構:
Collection:在SolrCloud集羣中邏輯意義上的完整的索引。通常會包含多個Shard(分片),若是大於1個分片,那麼就是分佈式存儲。
Shard: Collection的邏輯分片。每一個Shard被化成一個或者多個replicas(副本),經過選舉肯定哪一個是Leader(主),其它爲從
Replica: Shard的一個副本,存儲在Solr集羣的某一臺機器中(就是一個節點),對應這臺Solr的一個Core。
Leader: 贏得選舉的Shard replicas。每一個Shard有多個Replicas,這幾個Replicas須要選舉來肯定一個Leader。選舉能夠發生在任什麼時候間,可是一般他們僅在某個Solr實例發生故障時纔會觸發。當索引documents時,SolrCloud會傳遞它們到此Shard對應的leader,leader再分發它們到所有Shard的replicas
分片數量越多,每一片的數據就越少,每個副本的數據就越少。可是通常不要多於機器數量
分片數量越少,每一片的數據就越多,每個副本的數據就越多。
副本數量越少,總數據量越少, 這樣能夠減小每一臺機器上的數據量,會下降高可用性,提升數據存儲上限。
副本數量越多,總數據量越多,會增長每一臺機器上的數據量,可是會提升整個集羣的高可用性。
咱們須要三臺服務器,也就是三臺虛擬機。分別是:
192.168.56.101
192.168.56.102
192.168.56.103
每臺及其上都須要部署如下環境:
JDK:基本Java運行環境
Tomcat:裝載Solr服務
Solr-4.10.2:Solr服務
Zookeeper:對Solr雲進行管理
理論上應該給每臺機器分別安裝,可是咱們是虛擬機,咱們能夠先安裝一臺,而後把虛擬機進行復制!
tar -zxvf zookeeper-3.4.5.tar.gz
某些機器沒法識別標點,所以咱們能夠把目錄的名稱作修改:
mv zookeeper-3.4.5 zookeeper
A:進入zookeeper/conf目錄
B:複製模板文件
cp zoo_sample.cfg zoo.cfg
C:修改配置文件信息,添加如下內容
vi zoo.cfg
要添加的內容:
dataDir=/usr/local/myapp/zookeeper/data dataLogDir=/usr/local/myapp/zookeeper/log server.1=192.168.56.101:2888:3888 server.2=192.168.56.102:2888:3888 server.3=192.168.56.103:2888:3888
注意:模板文件中已經有一個dataDir參數,咱們必定要把這個刪除,或者在這個基礎上修改
dataDir:數據目錄
dataLogDir:日誌目錄
server.1=x.x.x.x:port1:port2 指定全部zookeeper的節點信息
server後的數字是節點ID,port1是心跳端口,port2是數據端口
咱們在配置文件裏指定了數據和日誌目錄。因此咱們須要建立這些目錄
A:先進入zookeeper目錄
B:建立目錄
mkdir –m 755 data
mkdir –m 755 log
這樣兩個命令能夠在建立目錄的同時指定文件夾的權限
進入data目錄,建立文件myid,而且寫上ID信息:1
vi myid
插入id:1
注意,其它節點的ID必須與配置文件中的ID一致,分別是2和3
A:vi /etc/profile(修改文件)
B:添加內容:
export ZOOKEEPER_HOME=/usr/local/myapp/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin
C:從新編譯文件:
source /etc/profile
啓動zookeeper:
zkServer.sh start
中止zookeeper:
zkServer.sh stop
查看狀態:
zkServer.sh status
先stop 掉原zk
zkServer.sh stop
而後以./zkServer.sh start-foreground方式啓動,會看到啓動日誌
zkServer.sh start-foreground
修改:tomcat文件夾下的bin目錄中的catalina.sh文件,添加如下信息:
export JAVA_OPTS="-Dsolr.solr.home=/usr/local/myapp/solr-4.10.2/example/solr -DzkHost=192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181"
-Dsolr.solr.solr.home指定的是Solr索引庫位置
-DzkHost指定的是三個zookeeper的ip和客戶端端口信息
這樣tomcat啓動後,solr服務就能夠到zookeeper中註冊本身的信息,或者獲取其它節點信息。
分別爲192.168.56.102和192.168.56.103
修改zookeeper目錄中 data/myid的內容,分別爲2和3
zkServer.sh start
查看狀態:
zkServer.sh status
中止:
zkServer.sh stop
Zookeeper提供了本身的客戶端命令行工具,與Linux的命令很是類似。
A:啓動客戶端工具:
zkCli.sh –server ip:port
這裏的參數能夠省略,若是省略,默認訪問的是本機的zookeeper節點即:localhost:2181
B:顯示根目錄下、文件: ls / 使用 ls 命令來查看當前 ZooKeeper 中所包含的內容
C:顯示根目錄下、文件: ls2 / 查看當前節點數據並能看到更新次數等數據
D:建立文件,並設置初始內容: create /zk "test" 建立一個新的 znode節點「 zk 」以及與它關聯的字符串
E:獲取文件內容: get /zk 確認 znode 是否包含咱們所建立的字符串
F:修改文件內容: set /zk "zkbak" 對 zk 所關聯的字符串進行設置
G:刪除文件: delete /zk 將剛纔建立的 znode 刪除
H:退出客戶端: quit
I:幫助命令: help
<solrcloud> <str name="host">192.168.56.101</str> <int name="hostPort">8080</int> <str name="hostContext">${hostContext:solr}</str> <int name="zkClientTimeout">${zkClientTimeout:30000}</int> <bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool> </solrcloud>
咱們訪問一臺Solr服務的地址,通常是這樣的:http://192.168.56.101:8080/solr
而在這裏的幾個參數,分別對應這個地址的一些信息:
host:就是Solr服務的IP地址,每臺機器配置爲本身的IP
hostPort:就是監聽端口,咱們是Tomcat服務,所以是8080
hostContext:就是訪問的路徑,這裏缺省值是solr,咱們不用改
因爲zookeeper統一管理solr的配置文件(主要是schema.xml、solrconfig.xml), solrCloud各各節點使用zookeeper管理的配置文件。之後不管建立任何的core,本地的配置文件都沒用了,使用的都是zookeeper的配置文件
執行下邊的命令將/usr/local/myapp/solr-4.10.2/example/solr/collection1/conf/下的配置文件上傳到zookeeper:
sh /usr/local/myapp/solr-4.10.2/example/scripts/cloud-scripts/zkcli.sh -zkhost 192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181 -cmd upconfig -confdir /usr/local/myapp/solr-4.10.2/example/solr/collection1/conf/ -confname solrconf
解釋:
/usr/local/myapp/solr-4.10.2/example/scripts/cloud-scripts/zkcli.sh : Solr提供的訪問Zookeeper的腳本文件 -zkhost 192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181 : 指定Zookeeper的地址信息 -cmd upconfig : 指定操做的命令。這裏是上傳配置 -confdir /usr/local/myapp/solr-4.10.2/example/solr/collection1/conf/ : 指定要上傳的配置文件目錄,咱們上傳Solr的樣例中的配置 -confname solrconf : 指定註冊到Zookeeper中後配置文件目錄名稱
Solr採用的是相似WebService的API接口,採用Http方式進行訪問,所以,其操做命令都是一些URL聯接及對應參數
http://192.168.56.101:8080/solr/admin/collections?action=CREATE&name=myCollection1&numShards=3&replicationFactor=2&maxShardsPerNode=8&property.schema=schema.xml&property.config=solrconfig.xml
參數說明:
name :指明collection名稱
numShards :指明分片數
replicationFactor :指明副本數
maxShardsPerNode : 每一個節點最大分片數(默認爲1)
property.schema :指定使用的schema.xml,這個文件必須在zookeeper上。
property.config :指定使用的solrconfig.xml,這個文件必須在zookeeper上。
http://192.168.56.101:8080/solr/admin/collections?action=DELETE&name=collection1
http://192.168.56.101:8080/solr/admin/collections?action=LIST
http://192.168.56.101:8080/solr/admin/collections?action=CLUSTERSTATUS
http://192.168.56.101:8080/solr/admin/collections?action=SPLITSHARD&collection=myCollection2&shard=shard2
http://192.168.56.101:8080/solr/admin/collections?action=DELETESHARD&collection=myCollection2&shard=shard1
更多的命令請參數官方文檔:
apache-solr-ref-guide-4.10.pdf
注意:
啓動solrCloud須要先啓動solrCloud依賴的全部zookeeper服務器,再啓動每臺solr服務器。
若是服務器跟服務器之間沒法通信,查看每臺服務器的/etc/hosts 裏面是否配置了其餘服務器的IP地址和hostname
測試:在一臺Solr上建立的索引,從其它solr服務上能夠查詢到
從任意一臺Solr上查詢索引,選擇任意的一個分片,都會返回一個完整的結果
三臺服務器,任意掛掉一臺,依然不會影響使用,事實上,只要剩餘的機器上,有完整的shard分片信息,都不影響使用。無論剩餘幾臺服務器
當一個節點掛掉時,若是有索引的更新,那麼這個節點啓動後,會自動同步新的數據
若是咱們啓動新的Solr服務,那麼這個服務也能夠融入集羣中。
與單機Solr相比,API僅僅是在建立SolrServer時發生了改變,其它沒有變化。
單機採用的是:HttpSolrServer
SolrCloud採用的是:CloudSolrServer
@Test public void testWrite() throws Exception{ // 建立SolrServer CloudSolrServer server = new CloudSolrServer("192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181"); // 指定要訪問的Collection名稱 server.setDefaultCollection("collection1"); // 建立Document對象 SolrInputDocument document = new SolrInputDocument(); // 添加字段 document.addField("id", "20"); document.addField("title", "duang手機,自帶特效的手機,值得擁有"); // 添加Document到Server server.add(document); // 提交 server.commit(); }
@Test public void testDelete() throws Exception{ // 建立SolrServer CloudSolrServer server = new CloudSolrServer("192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181"); // 指定要訪問的Collection名稱 server.setDefaultCollection("collection1"); // 根據ID刪除 server.deleteById("20"); // 提交 server.commit(); }
@Test public void testSearch() throws Exception { // 建立SolrServer CloudSolrServer server = new CloudSolrServer("192.168.56.101:2181,192.168.56.102:2181,192.168.56.103:2181"); // 指定要訪問的Collection名稱 server.setDefaultCollection("collection1"); // 查找數據 QueryResponse response = server.query(new SolrQuery("title:手機")); // 以document形式解析數據 SolrDocumentList documentList = response.getResults(); // 遍歷 for (SolrDocument solrDocument : documentList) { System.out.println(solrDocument.getFieldValue("id")); System.out.println(solrDocument.getFieldValue("title")); } }