前言
前段時間,空閑時間在公司調試zookeeper,被同事(也是同學,暫稱為小馬哥)看到了。他說你還玩這東西?事實上,我們這種小型公司85%的項目中用不到zookeeper,大家接觸的都比較少。有的甚至沒聽說過。
后來,小馬哥私下來問我,究竟什么是zookeeper(下文全部用zk來代指zookeeper),當時快速解釋道:分布式協調,配置管理,master選舉,分布式鎖,還可以實現隊列。
是的,這樣解釋好像沒幾個人懂,百度一大堆都是這樣的話。本文中,並不會介紹zk的api和使用,只是讓大家明白為什么要有zk。具體使用,我們在下一篇文章中詳細說明。
促使我寫這篇文章的原因有2個:
1、希望能帶給看這篇文章人一定幫助,寫完后,首先推送給小馬哥看看,增加個閱讀量……
2、加深自己的理解。
(純文字描述的一篇文章,盡量將故事寫的讓大家有興趣看看下去)
從集中式到分布式
1、小弟入行較晚,2016年中旬踏入編程行業時已然存在眾多武林高手和很牛的系統。但,我相信,10多年前,在中國,應該大多數的項目還是集中式的,所謂集中式,即一個應用集中部署,以網購商城舉一個例子,這個應用的功能包含用戶注冊,商家上架新貨,客戶搜索商品並下單,訂單,倉庫,物流更新等等一系列功能。然而中國網上購物的人很少,可能開始每天只有幾百幾千人用這個系統。並沒有什么問題。
2、后來,人們發現網購很爽很便宜啊,互相口頭推薦,網上購物吧,聽起來,這種方式時髦(依稀記得我媽當年一直提醒說我付款后人家不發貨怎么辦,哈哈),后來,越多的人開始網購。發現這台服務器頂不住了,於是開始服務器擴容,加到N台做負載均衡,OK,事情好像緩和了。用戶體驗流暢了一些。
3、又過了一段時間,商城的產品經理提了個需求,商家對我們系統的后台添加新貨的功能很不滿意,我們要重構此處功能。耗時1個月后,后台重構完成,網站發布公告,今晚停機維護1小時進行系統升級。嗯,1小時升級完成了。這1小時,很多購物迷妹准備買東西,結果維護,去了另一平台買到了。我們的商城這1小時損失了1萬用戶,每人預計消費100塊,丟失了100萬的成交額。老板生氣了,大罵CTO!
4、為了解決這個困境,CTO想了個辦法,我們把后台商家添加新貨的這個模塊重新開發一個系統吧,這樣以后維護的時候,我們只是商家端維護,不影響用戶下單。
OK,第一版從集中式過渡到分布式的場景出來了,將商家端和用戶端分離成2個項目,我發現了幾個非常大的好處:
1、2個端成立2個開發團隊,大家互不干涉,商家端功能較少,我們只需要3個人就能維護這個項目。
2、商家端用戶較少,我們只需要集群2台機器,而用戶端,中國的網購用戶太多了,我們部署900台吧。
3、而且公司總部在浙江,團隊有3個兄弟是北京的,以后分配這3個兄弟可以回北京的辦公區來專門負責商家端了。以后公司成立了北京分部。可以將大批的北京的IT精英納入自己麾下。例如阿里巴巴的釘釘和阿里雲主要就是在北京(沒調查過)
后來,介於這種好處,CTO把用戶模塊,搜索模塊,訂單模塊,倉儲物流模塊都分開部署了。
分布式后存在的問題
問題1、用戶模塊,訂單,搜索等模塊現在都是不同的項目了,現在問題出現了,小馬哥登錄前台瀏覽好了一件衣服后,下單跳到了訂單模塊,(在開發人員的角度講,這是2個系統啊,session不共享)小馬哥再次登錄到訂單系統,又想查看物流信息(跳到物流模塊),提示小馬哥未登錄,小馬哥生氣了,這什么傻逼玩意兒,老子不買了,一直提示讓我登錄。分布式導致的問題,應該我們開發人員來買單,而不是讓用戶感到不爽。
此種問題解決方案很簡單,我們將session共享啊,不要把session放到JVM的HashMap中(java程序員的角度),我們集中緩存session到redis中吧,但是,這樣cookie不共享啊,如果1級域名不相同的話,訪問A系統返回的cookie並不會帶到B系統(cookie域),這個問題,我們也比較好解決。共用1級域名就行,我們叫a.hkmall.com,b.hkmall.com。事實上,資料顯示早期的分布式系統就是這樣解決會話共享問題的。
但這樣,還存在很多問題,比如物流模塊這幫兄弟的系統不是用java寫的,用的python,人家大罵,你們這cookie里的jessionid是什么東西啊,我們可不認識。是的,這種方式限定了語言。
后來,終於有了企業級解決方案(單點登錄SSO)(關於sso的詳細描述,建議大家自行查閱相關資料,之后可能會寫一篇基於CAS的SSO,個人也是個小菜鳥,只是在個人學習項目hkmall中用到了這些)
BTW、吐槽一個點:個人認為,上述這種情況下有必要SSO,而且也有意義,但我所見過的一些系統的單點登錄,小弟愚昧,一直沒有意會到SSO的用意是什么,比如我們公司的。一堆互不相干的系統,集成到一起登錄,事實上,這些系統之間很多沒有聯系,A系統的用戶壓根不可能登錄到B系統。徒增了用戶登錄時的困難性和開發人員的調試和對接的難度。換句話說,假如有天A系統用戶要授權為可以使用B系統,B系統要接納A系統用戶的重構工作量也不小(比如有的系統做了用戶本地化等等操作……)。當然了,個人只是站在了技術的角度上,高層面的想法我是沒有想到的!
問題2、我們拿訂單模塊與倉儲模塊來舉個例子,假設用戶執行下單操作,我們用消息隊列將訂單消息寫到中間件中,此時倉庫模塊訂閱了這個消息,要執行相應的庫存 -1操作。但因某種原因(或許是網絡原因,倉庫模塊掛了等)導致倉庫沒有執行-1這步操作,而這恰好又是最后一件商品,后來又一個用戶下單,發現倉庫還有商品,又下單成功了!這樣出現了一個問題,只有一件商品,卻被2個用戶買到了。究竟要發貨給誰??(可能這個例子舉的不夠恰當,事實上沒有系統這樣設計,只是為了說明情況)
諸如此類情況,我們出現了數據不一致的情況,我們在集中式系統中,很容易的通過鎖與數據庫的ACID特性可以保證這種情況不發生,但在分布式系統中,好像並沒有特別好的解決方案。
問題N、當然了,分布式的諸多問題,並不是在我們這篇文章的討論范圍之內。如果感興趣,可以詳細查閱以下ACP,BASE理論等,個人認為,分布式系統的理論非常重要,如果對理論掌握的很嫻熟,在技術選型與代碼方面稍加練習后應該沒有太大的難度。
沒有分布式就不會有zookeeper
引入1、假設我們上邊的分布式系統中集群部署了900台機器(假設的原因是實際中我們不會這樣的方式部署),這900個節點有900個配置文件,我們數據庫地址沒有使用域名而使用了ip,現在換ip了,我們要修改900個配置文件,並且重啟所有應用系統。相信這一步操作對運維來說是災難性的。此時肯定要將這個配置寫到一個地方,我們這900個應用來引用它。如我們公司使用的NAS文件系統等。但是,萬一這個集中存儲的系統掛了呢?況且,我不想因為這一處改動而重啟900次,我希望ip變了后通知一下我的應用,自動加載新的ip就好了。
需求:可以唯一的幫我保存一份東西,並且你要可靠,別我向你拿東西的時候拿不到了。並且你在把東西修改了的時候告訴我一聲。
zookeeper簡介:
它很像數據結構當中的樹,也很像文件系統的目錄。樹是由節點所組成,Zookeeper的數據存儲也同樣是基於節點,這種節點叫做Znode。
/ 地球
/ 地球 /動物園
/ 地球 /動物園 /老虎
/ 地球 /動物園 /獅子
如上,每一級的路徑都唯一,且有上下級關系,每一個路徑,都是一個Znode。
后續繼續更新