2021月薪過5萬 面試題總目錄
- 瘋狂創客圈 經典圖書 : 《Netty Zookeeper Redis 高并發實戰》 面試必備 + 面試必備 + 面試必備
- 瘋狂創客圈 經典圖書 : 《SpringCloud、Nginx高并發核心編程》 大廠必備 + 大廠必備 + 大廠必備
- 入大廠+漲工資 必備的 高并發社群: 【博客園總入口 】
| 搞定下面這些面試題,2021春招月薪過5萬(猛!) | 阿里、京東、美團、頭條… 隨意挑、橫著走!!! |
|---|---|
| Java基礎 | |
| JVM面試題(史上最強、持續更新、吐血推薦) | https://www.cnblogs.com/crazymakercircle/p/14365820.html |
| Java基礎面試題(史上最全、持續更新、吐血推薦) | https://www.cnblogs.com/crazymakercircle/p/14366081.html |
| 死鎖面試題(史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/14323919.html |
| 多執行緒、執行緒池、內置鎖 面試題 (史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/13903850.html |
| JUC并發包與容器類 - 面試題(史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/13904029.html |
| SpringBoot - 面試題(史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/14365487.html |
| Linux面試題(史上最全、持續更新、吐血推薦) | https://www.cnblogs.com/crazymakercircle/p/14366893.html |
| 網路協議面試題(史上最全、持續更新、吐血推薦) | https://www.cnblogs.com/crazymakercircle/p/14370335.html |
| 分布式、高并發、設計模式、架構 | |
| Zookeeper 面試題(史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/13900183.html |
| Mysql 面試題(史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/13900186.html |
| Redis 面試題 - 收藏版(史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/13900198.html |
| SpringCloud 面試題 - 收藏版(史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/13900212.html |
| Netty 面試題 (史上最強、持續更新) | https://www.cnblogs.com/crazymakercircle/p/13903625.html |
| 訊息佇列、RabbitMQ、Kafka、RocketMQ面試題 (史上最全、持續更新) | https://www.cnblogs.com/crazymakercircle/p/14367425.html |
| 設計模式面試題 (史上最全、持續更新、吐血推薦) | https://www.cnblogs.com/crazymakercircle/p/14367101.html |
| 架構設計面試題 (史上最全、持續更新、吐血推薦) | https://www.cnblogs.com/crazymakercircle/p/14367907.html |
2021春招月薪過5萬(猛!驚!)面試題之:架構設計篇
場景題
整理了一些常見的架構設計面試題,主要記錄關鍵點,具體細節就不詳細敘述了,案例慢慢補充,目前想起以下問題:
- 秒殺系統
- 短鏈接生成
- 高并發的紅包系統
- 分布式ID生成
- 分布式限流
- 分布式定時任務
- 新浪微博怎么推送微博
- 大檔案有限記憶體排序
秒殺系統
秒殺系統基本面試被問爛了,網上資料也很多,基本整理了內容如下:
設計難點:并發量大,應用、資料庫都承受不了,另外難控制超賣,
設計要點:
- 將請求盡量攔截在系統上游,html盡量靜態化,部署到cdn上面,按鈕及時設定為不可用,禁止用戶重復提交請求,
- 設定頁面快取,針對同一個頁面和uid一段時間內回傳快取頁面,
- 資料用快取抗,不直接落到資料庫,
- 讀資料的時候不做強一致性教研,寫資料的時候再做,
- 在每臺物理機上也快取商品資訊等等變動不大的相關的資料
- 像商品中的標題和描述這些本身不變的會在秒殺開始之前全量推送到秒殺機器上并一直快取直到秒殺結束,
- 像庫存這種動態資料會采用被動失效的方式快取一定時間(一般是數秒),失效后再去Tair快取拉取最新的資料,
- 如果允許的話,用異步的模式,等快取都落庫之后再回傳結果,
- 如果允許的話,增加答題教研等驗證措施,
其他業務和技術保障措施:
- 業務隔離,把秒殺做成一種營銷活動,賣家要參加秒殺這種營銷活動需要單獨報名,從技術上來說,賣家報名后對我們來說就是已知熱點,當真正開始時我們可以提前做好預熱,
- 系統隔離,系統隔離更多是運行時的隔離,可以通過分組部署的方式和另外 99% 分開,秒殺還申請了單獨的域名,目的也是讓請求落到不同的集群中,
- 資料隔離,秒殺所呼叫的資料大部分都是熱資料,比如會啟用單獨 cache 集群或 MySQL 資料庫來放熱點資料,目前也是不想0.01%的資料影響另外99.99%,
另外需要復習快取穿透、雪崩等等問題,主要的流量都落在了快取資料庫上,需要針對快取資料庫的高可用作保障,
短鏈接生成
這個應該是比較公認的方案了:
- 分布式ID生成器產生ID
- ID轉62進制字串
- 記錄資料庫,根據業務要求確定過期時間,可以保留部分永久鏈接
主要難點在于分布式ID生成,鑒于短鏈一般沒有嚴格遞增的需求,可以使用預先分發一個號段,然后生成的方式,
看了下新浪微博的短鏈接,8位,理論上可以保存超過200萬億對關系,具體怎么存盤的還有待研究,
紅包系統
紅包系統其實很像秒殺系統,只不過同一個秒殺的總量不大,但是全域的并發量非常大,比如春晚可能幾百萬人同時搶紅包,
主要技術難點也類似,主要在資料庫,減庫存的時候會搶鎖,另外由于業務需求不同,沒辦法異步,也不能超賣,事務更加嚴格,
不能采用的方式:
- 樂觀鎖:手慢會失敗,DB 面臨更大壓力,所以不能采用,
- 直接用快取頂,涉及到錢,一旦快取掛掉就完了,
建議的方式:
- 接入層垂直切分,根據紅包ID,發紅包、搶紅包、拆紅包、查詳情詳情等等都在同一臺機器上處理,互不影響,分而治之,
- 請求進行排隊,到資料庫的時候是串行的,就不涉及搶鎖的問題了,
- 為了防止佇列太長過載導致佇列被降級,直接打到資料庫上,所以資料庫前面再加上一個快取,用CAS自增控制并發,太高的并發直接回傳失敗,
- 紅包冷熱資料分離,按時間分表,
分布式ID
分布式ID生成大概也算老生常談的問題了,主要關鍵在于是否需要嚴格遞增,嚴格遞增的話效率必然大降,
不需要遞增的話比較簡單:
- 一種方式是預先分片,比如十臺機器,每臺先分一千個ID,一號機從0開始,二號從1000開始等等,缺點是大致上可以被人看出來業務量,
- 另一種方式是類似雪花演算法,每個機器有個id,然后基于時間算一個id,再加上一個遞增id,比如如下美團的方案,缺點是機器的時間戳不能回撥,回撥的話會出現問題,

如果要求嚴格遞增,我沒找到現成的很好的方案,大概只能單機生成,不能分布式了,然后都去單機上取號,效率的話,類似Redis的資料庫大概能到每秒十幾二十幾萬的速度,
分布式限流
常見的限流方法:
- 固定視窗計數器:按照時間段劃分視窗,有一次請求就+1,最為簡單的演算法,但這個演算法有時會讓通過請求量允許為限制的兩倍,
- 滑動視窗計數器:通過將視窗再細分,并且按照時間“滑動”來解決突破限制的問題,但是時間區間的精度越高,演算法所需的空間容量就越大,
- 漏桶:請求類似水滴,先放到桶里,服務的提供方則按照固定的速率從桶里面取出請求并執行,缺陷也很明顯,當短時間內有大量的突發請求時,即便此時服務器沒有任何負載,每個請求也都得在佇列中等待一段時間才能被回應,
- 令牌桶:往桶里面發放令牌,每個請求過來之后拿走一個令牌,然后只處理有令牌的請求,令牌桶滿了則多余的令牌會直接丟棄,令牌桶演算法既能夠將所有的請求平均分布到時間區間內,又能接受服務器能夠承受范圍內的突發請求,因此是目前使用較為廣泛的一種限流演算法,
Google 的開源專案 guava 提供了 RateLimiter 類,實作了單點的令牌桶限流,
分布式環境下,可以考慮用 Redis+Lua 腳本實作令牌桶,
如果請求量太大了,Redis 也撐不住怎么辦?我覺得可以類似于分布式 ID 的處理方式,Redis 前面在增加預處理,比如每臺及其預先申請一部分令牌,只有令牌用完之后才去 Redis,如果還是太大,是否可以垂直切分?按照流量的來源,比如地理位置、IP 之類的再拆開,
分布式定時任務
任務輪詢或任務輪詢+搶占排隊方案
- 每個服務器首次啟動時加入佇列;
- 每次任務運行首先判斷自己是否是當前可運行任務,如果是便運行;
- 如果不是當前運行的任務,檢查自己是否在佇列中,如果在,便退出,如果不在佇列中,進入佇列,
微博推送
主要難點:關系復雜,資料量大,一個人可以關注非常多的用戶,一個大 V 也有可能有幾千萬的粉絲,
先介紹最基本的方案:
- 推模式:推模式就是,用戶A關注了用戶 B,用戶 B 每發送一個動態,后臺遍歷用戶B的粉絲,往他們粉絲的 feed 里面推送一條動態,
- 拉模式:推模式相反,拉模式則是,用戶每次重繪 feed 第一頁,都去遍歷關注的人,把最新的動態拉取回來,
一般采用推拉結合的方式,用戶發送狀態之后,先推送給粉絲里面在線的用戶,然后不在線的那部分等到上線的時候再來拉取,
另外冷熱資料分離,用戶關系在快取里面可以設定一個過期時間,比如七天,七天沒上線的可能就很少用這個 APP,
大檔案排序
對于遠高于記憶體的檔案排序,
外歸并排序:
- 對檔案分割,然后分別排序
- 排好序的檔案依次讀取一個緩沖區的大小,然后進行排序,輸出到輸出緩沖區,然后保存到結果檔案,
如果是數字,可以用位圖排序,但是要求比較苛刻:
- 數字不重復
- 知道最大值
- 相對密集,因為沒出現的數字也會占用空間
比較適合電話號之類的,
其他場景題
1、情景題:如果一個外賣配送單子要發布,現在有200個騎手都想要接這一單,如何保證只有一個騎手接到單子?
這個可以用redis的lpush rpop來實作,
2、場景題:美團首頁每天會從10000個商家里面推薦50個商家置頂,每個商家有一個權值,你如何來推薦?第二天怎么更新推薦的商家?
這個可以用堆排,第二天更新推薦的可以在要更新之前的時候在redis做計算操作,然后放資料庫做個同步就行了,
3、場景題:微信搶紅包問題
悲觀鎖,樂觀鎖,存盤程序放在mysql資料庫中,
4、場景題:1000個任務,分給10個人做,你怎么分配,先在紙上寫個最簡單的版本,然后優化,
全域佇列,把1000任務放在一個佇列里面,然后每個人都是取,完成任務,
分為10個佇列,每個人分別到自己對應的佇列中去取務,
5、場景題:保證發送訊息的有序性,訊息處理的有序性,
給訊息加一個header,識別一下header的syn就行
6、如何把一個檔案快速下發到100w個服務器
邊下發,邊復制
7、給每個組分配不同的IP段,怎么設計一種結構使的快速得知IP是哪個組的?
8、10億個數,找出最大的10個,
建議一個大小為10的小根堆,
9、有幾臺機器存盤著幾億淘寶搜索日志,你只有一臺2g的電腦,怎么選出搜索熱度最高的十個搜索關鍵詞?
分bucket,每個bucket找出頻次最高的10個,總體用分治演算法做,
10、分布式集群中如何保證執行緒安全?
分布式鎖,意在讓分布式多執行緒的環境針對一個共享資源一次性只會有一個執行緒獲取到鎖里的資源,分布式鎖的實作一般就是redis和zk居多,redis設定一下expire time就行,
11、10萬個數,輸出從小到大?
先劃分成多個小檔案,送進記憶體排序,然后再采用多路歸并排序,
12、有十萬個單詞,找出重復次數最高十個?
map<String,Integer> 字串,頻次,然后堆排,
場景題答題小建議:
架構設計題目遠不止這些,我覺得主要從以下幾個方面準備:
- 先了解常用演算法,針對解決各種問題能用哪些演算法,比如大檔案排序用外排序,大量資料中的命中判斷用位圖/布隆過濾器等等,
- 注意擴展性、多考慮極端情況,多問自己幾個為什么,比如說起單機的限流演算法想想分布式的怎么做,
- 實在不知道怎么弄的敘述自己的思考程序,著重展示自己考慮周全、思維縝密,
比如之前一個同事面阿里被問整個機房網路掛了/斷電了之類的極端問題,相信很多人不可能真的遇到這種情況,而且可用性一般也到不了這個級別,如果是我的話,我會著重考慮資料一致性、資料恢復、臟資料處理之類的問題,是否有其他機房提供服務,如果有的話涉及到網路磁區,是不是可以引申談談 zab、raft 演算法,另外原本兩個或者三個機房提供服務,現在瞬間少了一個,其他機房的負載瞬間上升,怎么做削峰、降級,這就有回到我們會的問題上了,另外等到網路恢復了,怎么恢復服務?之前處理到一半的資料怎么處理?這些引申開來都有太多可以聊,
分布式微服務架構
問1.什么是分布式系統
分布式系統的目標與要素
分布式系統的目標是提升系統的整體性能和吞吐量另外還要盡量保證分布式系統的容錯性(假如增加10臺服務器才達到單機運行效果2倍左右的性能,那么這個分布式系統就根本沒有存在的意義),
即使采用了分布式系統,我們也要盡力運用并發編程、高性能網路框架等等手段提升單機上的程式性能,
分布式系統設計兩大思路:中心化和去中心化
中心化設計
- 兩個角色: 中心化的設計思想很簡單,分布式集群中的節點機器按照角色分工,大體上分為兩種角色: “領導” 和 “干活的”
- 角色職責: “領導”通常負責分發任務并監督“干活的”,發現誰太閑了,就想發設法地給其安排新任務,確保沒有一個“干活的”能夠偷懶,如果“領導”發現某個“干活的”因為勞累過度而病倒了,則是不會考慮先嘗試“醫治”他的,而是一腳踢出去,然后把他的任務分給其他人,其中微服務架構 Kubernetes 就恰好采用了這一設計思路,
- 中心化設計的問題
- 中心化的設計存在的最大問題是“領導”的安危問題,如果“領導”出了問題,則群龍無首,整個集群就奔潰了,但我們難以同時安排兩個“領導”以避免單點問題,
- 中心化設計還存在另外一個潛在的問題,既“領導”的能力問題:可以領導10個人高效作業并不意味著可以領導100個人高效作業,所以如果系統設計和實作得不好,問題就會卡在“領導”身上,
- 領導安危問題的解決辦法: 大多數中心化系統都采用了主備兩個“領導”的設計方案,可以是熱備或者冷備,也可以是自動切換或者手動切換,而且越來越多的新系統都開始具備自動選舉切換“領導”的能力,以提升系統的可用性,
去中心化設計
- 眾生地位平等: 在去中心化的設計里,通常沒有“領導”和“干活的”這兩種角色的區分,大家的角色都是一樣的,地位是平等的,全球互聯網就是一個典型的去中心化的分布式系統,聯網的任意節點設備宕機,都只會影響很小范圍的功能,
- “去中心化”不是不要中心,而是由節點來自由選擇中心, (集群的成員會自發的舉行“會議”選舉新的“領導”主持作業,最典型的案例就是ZooKeeper及Go語言實作的Etcd)
- 去中心化設計的問題: 去中心化設計里最難解決的一個問題是 “腦裂”問題 ,這種情況的發生概率很低,但影響很大,腦裂指一個集群由于網路的故障,被分為至少兩個彼此無法通信的單獨集群,此時如果兩個集群都各自作業,則可能會產生嚴重的資料沖突和錯誤,一般的設計思路是,當集群判斷發生了腦裂問題時,規模較小的集群就“自殺”或者拒絕服務,
分布式與集群的區別是什么?
- 分布式: 一個業務分拆多個子業務,部署在不同的服務器上
- 集群: 同一個業務,部署在多個服務器上,比如之前做電商網站搭的redis集群以及solr集群都是屬于將redis服務器提供的快取服務以及solr服務器提供的搜索服務部署在多個服務器上以提高系統性能、并發量解決海量存盤問題,
問2. 如何防止HA集群的腦裂
1. 引言
腦裂(split-brain),指在一個高可用(HA)系統中,當聯系著的兩個節點斷開聯系時,本來為一個整體的系統,分裂為兩個獨立節點,這時兩個節點開始爭搶共享資源,結果會導致系統混亂,資料損壞,
對于無狀態服務的HA,無所謂腦裂不腦裂;但對有狀態服務(比如MySQL)的HA,必須要嚴格防止腦裂,(但有些生產環境下的系統按照無狀態服務HA的那一套去配置有狀態服務,結果可想而知…)
2如何防止HA集群腦裂
一般采用2個方法
- 仲裁
當兩個節點出現分歧時,由第3方的仲裁者決定聽誰的,這個仲裁者,可能是一個鎖服務,一個共享盤或者其它什么東西, - fencing
當不能確定某個節點的狀態時,通過fencing把對方干掉,確保共享資源被完全釋放,前提是必須要有可靠的fence設備,
理想的情況下,以上兩者一個都不能少,但是,如果節點沒有使用共享資源,比如基于主從復制的資料庫HA,我們也可以安全的省掉fence設備,只保留仲裁,而且很多時候我們的環境里也沒有可用的fence設備,比如在云主機里,
所以,單純的雙節點,無論如何也防止不了腦裂,
3. 沒有fence設備是否安全
以PostgreSQL或MySQL的資料復制為例來說明這個問題,
客戶端路由有幾種方式,基于VIP,基于Proxy,基于DNS或者干脆客戶端維護一個服務端地址串列自己判斷主從,不管采用哪種方式,主從切換的時候都要更新路由,
基于VIP的路由有一些變數,如果本該死掉的節點沒有摘掉自己身上的VIP,那么它隨時可能出來搗亂(即使新主已經通過arping更新了所有主機上的arp快取,如果某個主機的arp過期,發一個arp查詢,那么就會發生ip沖突),所以可以認為VIP也是一種特殊的共享資源,必需把它從故障節點上摘掉,至于怎么摘,最簡單的辦法就是故障節點發現自己失聯后自己摘,如果它還活著的話(如果它死了,也就不用摘了),如果負責摘vip的行程無法作業怎么辦?這時候就可以用上本來不太靠譜的軟fence設備了(比如ssh),
也要考慮Proxy的高可用
至于基于服務端地址串列的方法,客戶端需要通過后臺服務判斷主從(比如PostgreSQL/MySQL會話是否處于只讀模式),這時,如果出現2個主,客戶端就會錯亂,為防止這個問題,原主節點發現自己失聯后要自己把服務停掉,這和前面摘vip的道理是一樣的,
4. 主從切換后資料能否保證不丟
主從切換后資料會不會丟和腦裂可以認為是2個不同的問題,還以PostgreSQL或MySQL的資料復制為例來說明,
對PostgreSQL,如果配置成同步流復制,可以做到不管路由是否正確,都不會丟資料,因為路由到錯誤節點的客戶端根本寫不進任何資料,它會一直等待從節點的反饋,而它以為的從節點,現在已經是主子了,當然不會理它,當然如果老是這樣也不好,但它給集群監視軟體糾正路由錯誤提供了充足的時間,
如果本來就是配置的異步復制,那就是說已經做好丟資料的準備了,這時候,主從切換時丟點資料也沒啥大不了,但要控制自動切換的次數,比如控制已經被failover掉的原主不允許自動上線,否則如果因為網路抖動導致故障切換,那么主從就會不停的來回切,不停的丟資料,破壞資料的一致性,
5. 如何實作上面的策略
你可以自己完全從頭開始實作一套符合上述邏輯的腳本,但我更傾向于基于成熟的集群軟體去搭建,比如Pacemaker+Corosync+合適的資源Agent,Keepalived我是極不推薦的,它就不適合用于有狀態服務的HA,即使你把仲裁,fence那些東西都加到方案里,總覺得別扭,
使用Pacemaker+Corosync的方案也有一些注意事項
1)了解資源Agent的功能和原理
了解資源Agent的功能和原理,才能知道它適用的場景,比如pgsql的資源Agent是比較完善的,支持同步和異步流復制,并且可以在兩者之前自動切換,并且可以保證同步復制下資料不會丟失,但目前MySQL的資源Agent就很弱了,沒有使用GTID又沒有日志補償,很容易丟資料,還是不要用的好,繼續用MHA吧(但是,部署MHA時務必要防范腦裂),
2)確保法定票數(quorum)
quorum可以認為是Pacemkaer自帶的仲裁機制,集群的所有節點中的多數選出一個協調者,集群的所有指令都由這個協調者發出,可以完美的杜絕腦裂問題,為了使這套機制有效運轉,集群中至少有3個節點,并且把no-quorum-policy設定成stop,這也是默認值,(很多教程為了方便演示,都把no-quorum-policy設定成ignore,生產環境如果也這么搞,又沒有其它仲裁機制,是很危險的!)
但是,如果只有2個節點該怎么辦?
一是拉一個機子借用一下湊足3個節點,再設定location限制,不讓資源分配到那個節點上,
二是把多個不滿足quorum小集群拉到一起,組成一個大的集群,同樣適用location限制控制資源的分配的位置,
但是如果你有很多雙節點集群,找不到那么多用于湊數的節點,又不想把這些雙節點集群拉到一起湊成一個大的集群(比如覺得不方便管理),那么可以考慮第三種方法,
第三種方法是配置一個搶占資源,以及服務和這個搶占資源的colocation約束,誰搶到搶占資源誰提供服務,這個搶占資源可以是某個鎖服務,比如基于zookeeper包裝一個,或者干脆自己從頭做一個,就像下面這個例子,http://my.oschina.net/hanhanztj/blog/515065(這個例子是基于http協議的短連接,更細致的做法是使用長連接心跳檢測,這樣服務端可以及時檢出連接斷開而釋放鎖)但是,一定要同時確保這個搶占資源的高可用,可以把提供搶占資源的服務做成lingyig高可用的,也可以簡單點,部署3個服務,雙節點上個部署一個,第三個部署在另外一個專門的仲裁節點上,至少獲取3個鎖中的2個才視為取得了鎖,這個仲裁節點可以為很多集群提供仲裁服務(因為一個機器只能部署一個Pacemaker實體,否則可以用部署了N個Pacemaker實體的仲裁節點做同樣的事情,),但是,如非迫不得已,盡量還是采用前面的方法,即滿足Pacemaker法定票數,這種方法更簡單,可靠
問3. 微服務架構基本理念和原則,為什么會在團隊中使用微服務架構,實行微服務架構程序中碰到的問題及其解決方案,
關鍵思路
對于微服務架構而言,服務建模、服務拆分和服務集成是基本的設計理念,而 RPC、RESTful、API 網關、分布式配置中心等基礎組件以及服務可用性和資料最終一致性等關鍵要素也是重點內容,至于引入微服務架構的原因和碰到的困難,團隊業務發展特點和組織架構、微服務粒度和邊界等都是回答該問題的切入點,為了實作微服務架構,我們可以引入 Spring Cloud 等相對完善的技術實作體系,也可以使用 Dubbo 作為我們的基礎微服務架構,
參考答案:
一體化架構的問題
或者說是微服務架構所解決的問題,
1.難以擴展
一體化架構應用只能通過在負載均衡器后面放置整個應用程式的多個實體來進行水平擴展,如果應用中的特定服務需要擴展,則沒有簡單的選項,我們需要完整地擴展應用程式,這顯然會造成不必要的資源浪費,
相比之下,基于微服務的應用程式允許我們根據需要獨立擴展單個服務,在上圖中,如果需要縮放服務B,則可以有10個實體,同時保持其他實體,并可以根據需要隨時更改,
2.交付時間長
一體化架構在單個應用的任何部分/層中進行的任何更改都需要構建和部署整個應用程式,個人開發人員還需要下載整個應用程式代碼來修復和測驗,而不僅僅是受影響的模塊,這就影響到了持續部署的效率,
而在微服務架構中,如果僅在一百個微服務中的一個中需要改變,則僅構建和部署改變的微服務,沒有必要部署一切,我們甚至可以在短時間內多次部署,
3.應用復雜性
過去,隨著應用規模的增長(功能、功能等),團隊也會相應擴張,應用很快就就會變得復雜和交織在一起,隨著不同的團隊不斷修改代碼,維護模塊化結構慢慢變得越來越困難,并慢慢導致像意大利面一樣交織的代碼,這不僅會影響代碼質量,還會影響整個組織,
在基于微服務的應用中,每個團隊都在單獨的微服務上作業,代碼會有序很多,
4.沒有明確的所有權
在一體化應用中,看起來獨立的團隊實際上并不是獨立的,它們同時在相同的代碼庫上作業,嚴重依賴于彼此,
在基于微服務的應用中,獨立團隊處理單獨的微服務,一個團隊將擁有一個完整的微服務,作業的明確所有權明確控制服務的一切,包括開發、部署和監控,
5.故障級聯
如果沒有正確設計,一體化交媾應用的一部分失敗可能會級聯并導致整個系統崩潰,
在基于微服務的架構的情況下,我們可以使用斷路器來避免這種故障,
6.Dev和Ops之間的墻
開發團隊通常會進行開發、測驗,一旦部署,就會將維護和支持的所有權交給運維團隊,應用此時與開發團隊無關了,而運維團隊需要努力在生產環境中支持一體化架構應用,
在基于微服務的應用中,團隊的組織理解為“構建它、運行它”,開發團隊繼續在生產中擁有該應用,
7.陷入某種技術/語言
使用一體化架構,意味著被某種已實作的技術/語言鎖定,如果需要更改技術/語言,則必須重寫整個應用程式,
使用微服務,每個服務可以根據需求和業務以不同的技識訓語言實作,任何改變服務技術/語言的決定都只需要重寫該特定服務,因為所有微服務都是相互獨立的,
8.支持微服務的正確工具/技術的可用性
幾年前,我們還沒有適當的工具和技術來支持微服務,但自從Docker容器和云基礎設施(特別是PaaS)向大眾提供服務以來,微服務正在大規模采用,因為它們提供了我們所需的“自由”,而無需進行傳統的配置程式,
小結
簡單來說,使用微服務架構會獲得以下好處:
- 獨立開發部署服務
- 速度和敏捷性
- 更高的代碼質量
- 獲得圍繞業務功能創建/組織的代碼
- 提高生產力
- 更容易擴展
- 自由(在某種程度上)選擇實施技術/語言
問3. RPC 的概念及其包含的核心組件和主流實作技術,如何實作一個自定義的 RPC 框架,
關鍵思路
該面試題相對容易回答,RPC 是分布式系統的基礎,從思路上我們應該理解它是由網路通信、序列化、傳輸協議、服務呼叫等組件所構成,同時,對業界主流 RPC 的實作技術也要有足夠的了解,如 Alibaba Dubbo、Google gRPC、Facebook Thrift 等,
RPC的由來
隨著互聯網的發展,網站應用的規模不斷擴大,常規的垂直應用架構已無法應對,分布式服務架構以及流動計算架構勢在必行,亟需一個治理系統確保架構有條不紊的演進,
- 單一應用架構
- 當網站流量很小時,只需一個應用,將所有功能都部署在一起,以減少部署節點和成本,
- 此時,用于簡化增刪改查作業量的 資料訪問框架(ORM) 是關鍵,
- 垂直應用架構
- 當訪問量逐漸增大,單一應用增加機器帶來的加速度越來越小,將應用拆成互不相干的幾個應用,以提升效率,
- 此時,用于加速前端頁面開發的 Web框架(MVC) 是關鍵,
- 分布式服務架構
- 當垂直應用越來越多,應用之間互動不可避免,將核心業務抽取出來,作為獨立的服務,逐漸形成穩定的服務中心,使前端應用能更快速的回應多變的市場需求,
- 此時,用于提高業務復用及整合的 分布式服務框架(RPC),提供統一的服務是關鍵,
例如:各個團隊的服務提供方就不要各自實作一套序列化、反序列化、網路框架、連接池、收發執行緒、超時處理、狀態機等“業務之外”的重復技術勞動,造成整體的低效,
所以,統一RPC框架來解決提供統一的服務,
以下我將分別從如下四個方面詳解RPC,

RPC的實作原理

也就是說兩臺服務器A,B,一個應用部署在A服務器上,想要呼叫B服務器上應用提供的函式/方法,由于不在一個記憶體空間,不能直接呼叫,需要通過網路來表達呼叫的語意和傳達呼叫的資料,
比如說,A服務器想呼叫B服務器上的一個方法:
Employee getEmployeeByName(String fullName)
整個呼叫程序,主要經歷如下幾個步驟:
1、建立通信
首先要解決通訊的問題:即A機器想要呼叫B機器,首先得建立起通信連接,
主要是通過在客戶端和服務器之間建立TCP連接,遠程程序呼叫的所有交換的資料都在這個連接里傳輸,連接可以是按需連接,呼叫結束后就斷掉,也可以是長連接,多個遠程程序呼叫共享同一個連接,
2、服務尋址
要解決尋址的問題,也就是說,A服務器上的應用怎么告訴底層的RPC框架,如何連接到B服務器(如主機或IP地址)以及特定的埠,方法的名稱名稱是什么,
通常情況下我們需要提供B機器(主機名或IP地址)以及特定的埠,然后指定呼叫的方法或者函式的名稱以及入參出參等資訊,這樣才能完成服務的一個呼叫,
可靠的尋址方式(主要是提供服務的發現)是RPC的實作基石,比如可以采用redis或者zookeeper來注冊服務等等,

- 從服務提供者的角度看:當提供者服務啟動時,需要自動向注冊中心注冊服務;
- 當提供者服務停止時,需要向注冊中心注銷服務;
- 提供者需要定時向注冊中心發送心跳,一段時間未收到來自提供者的心跳后,認為提供者已經停止服務,從注冊中心上摘取掉對應的服務,
- 從呼叫者的角度看:呼叫者啟動時訂閱注冊中心的訊息并從注冊中心獲取提供者的地址;
- 當有提供者上線或者下線時,注冊中心會告知到呼叫者;
- 呼叫者下線時,取消訂閱,
3、網路傳輸
3.1、序列化
當A機器上的應用發起一個RPC呼叫時,呼叫方法和其入參等資訊需要通過底層的網路協議如TCP傳輸到B機器,由于網路協議是基于二進制的,所有我們傳輸的引數資料都需要先進行序列化(Serialize)或者編組(marshal)成二進制的形式才能在網路中進行傳輸,然后通過尋址操作和網路傳輸將序列化或者編組之后的二進制資料發送給B機器,
3.2、反序列化
當B機器接收到A機器的應用發來的請求之后,又需要對接收到的引數等資訊進行反序列化操作(序列化的逆操作),即將二進制資訊恢復為記憶體中的表達方式,然后再找到對應的方法(尋址的一部分)進行本地呼叫(一般是通過生成代理Proxy去呼叫,
通常會有JDK動態代理、CGLIB動態代理、Javassist生成位元組碼技術等),之后得到呼叫的回傳值,
4、服務呼叫
B機器進行本地呼叫(通過代理Proxy)之后得到了回傳值,此時還需要再把回傳值發送回A機器,同樣也需要經過序列化操作,然后再經過網路傳輸將二進制資料發送回A機器,而當A機器接收到這些回傳值之后,則再次進行反序列化操作,恢復為記憶體中的表達方式,最后再交給A機器上的應用進行相關處理(一般是業務邏輯處理操作),
通常,經過以上四個步驟之后,一次完整的RPC呼叫算是完成了,
PRC架構組件
一個基本的RPC架構里面應該至少包含以下4個組件:
1、客戶端(Client):服務呼叫方(服務消費者)
2、客戶端存根(Client Stub):存放服務端地址資訊,將客戶端的請求引數資料資訊打包成網路訊息,再通過網路傳輸發送給服務端
3、服務端存根(Server Stub):接收客戶端發送過來的請求訊息并進行解包,然后再呼叫本地服務進行處理
4、服務端(Server):服務的真正提供者
RPC呼叫程序

1、服務消費者(client客戶端)通過本地呼叫的方式呼叫服務
2、客戶端存根(client stub)接收到呼叫請求后負責將方法、入參等資訊序列化(組裝)成能夠進行網路傳輸的訊息體
3、客戶端存根(client stub)找到遠程的服務地址,并且將訊息通過網路發送給服務端
4、服務端存根(server stub)收到訊息后進行解碼(反序列化操作)
5、服務端存根(server stub)根據解碼結果呼叫本地的服務進行相關處理
6、本地服務執行具體業務邏輯并將處理結果回傳給服務端存根(server stub)
7、服務端存根(server stub)將回傳結果重新打包成訊息(序列化)并通過網路發送至消費方
8、客戶端存根(client stub)接收到訊息,并進行解碼(反序列化)
9、服務消費方得到最終結果
問4 說說springcloud rpc 的執行流程和原理? 如何對springcloud 微服務進行高并發的性能優化?
請參考 《springcloud nginx 高并發核心編程》一書
分布式事務
問1:什么是分布式事務?
指事務的每個操作步驟都位于不同的節點上,需要保證事務的 AICD 特性,
- 產生原因
資料庫分庫分表;
SOA 架構,比如一個電商網站將訂單業務和庫存業務分離出來放到不同的節點上,
- 應用場景
下單:減少庫存同時更新訂單狀態,庫存和訂單不在不同一個資料庫,因此涉及分布式事務,
支付:買家賬戶扣款同時賣家賬戶入賬,買家和賣家賬戶資訊不在同一個資料庫,因此涉及分布式事務,
- 解決方案
3.1 兩階段提交協議
兩階段提交協議可以很好得解決分布式事務問題,它可以使用 XA 來實作,XA 它包含兩個部分:事務管理器和本地資源管理器,其中本地資源管理器往往由資料庫實作,比如 Oracle、DB2 這些商業資料庫都實作了 XA 介面,而事務管理器作為全域的協調者,負責各個本地資源的提交和回滾,
3.2 訊息中間件
訊息中間件也可稱作訊息系統 (MQ),它本質上是一個暫存轉發訊息的一個中間件,在分布式應用當中,我們可以把一個業務操作轉換成一個訊息,比如支付寶的余額轉如余額寶操作,支付寶系統執行減少余額操作之后向訊息系統發一個訊息,余額寶系統訂閱這條訊息然后進行增加賬戶金額操作,
3.2.1 訊息處理模型
點對點

.
發布/訂閱

.
3.2.2 訊息的可靠性
訊息的發送端的可靠性:發送端完成操作后一定能將訊息成功發送到訊息系統,
訊息的接收端的可靠性:接收端僅且能夠從訊息中間件成功消費一次訊息,
發送端的可靠性
在本地資料建一張訊息表,將訊息資料與業務資料保存在同一資料庫實體里,這樣就可以利用本地資料庫的事務機制,事務提交成功后,將訊息表中的訊息轉移到訊息中間件,若轉移訊息成功則洗掉訊息表中的資料,否則繼續重傳,
接收端的可靠性
保證接收端處理訊息的業務邏輯具有冪等性:只要具有冪等性,那么消費多少次訊息,最后處理的結果都是一樣的,
保證訊息具有唯一編號,并使用一張日志表來記錄已經消費的訊息編號,
CAP定理
在理論計算機科學中,CAP定理(CAP theorem),又被稱作布魯爾定理(Brewer’s theorem),它指出對于一個分布式計算系統來說,不可能同時滿足以下三點:
| 選項 | 描述 |
|---|---|
| Consistency(一致性) | 指資料在多個副本之間能夠保持一致的特性(嚴格的一致性) |
| Availability(可用性) | 指系統提供的服務必須一直處于可用的狀態,每次請求都能獲取到非錯的回應(不保證獲取的資料為最新資料) |
| Partition tolerance(磁區容錯性) | 分布式系統在遇到任何網路磁區故障的時候,仍然能夠對外提供滿足一致性和可用性的服務,除非整個網路環境都發生了故障 |
Spring Cloud在CAP法則上主要滿足的是A和P法則,Dubbo和Zookeeper在CAP法則主要滿足的是C和P法則
CAP僅適用于原子讀寫的NOSQL場景中,并不適合資料庫系統,現在的分布式系統具有更多特性比如擴展性、可用性等等,在進行系統設計和開發時,我們不應該僅僅局限在CAP問題上,
注意:不是所謂的3選2(不要被網上大多數文章誤導了)
現實生活中,大部分人解釋這一定律時,常常簡單的表述為:“一致性、可用性、磁區容忍性三者你只能同時達到其中兩個,不可能同時達到”,實際上這是一個非常具有誤導性質的說法,而且在CAP理論誕生12年之后,CAP之父也在2012年重寫了之前的論文,
當發生網路磁區的時候,如果我們要繼續服務,那么強一致性和可用性只能2選1,也就是說當網路磁區之后P是前提,決定了P之后才有C和A的選擇,也就是說磁區容錯性(Partition tolerance)我們是必須要實作的,
CAP定理的證明
關于CAP這三個特性我們就介紹完了,接下來我們試著證明一下為什么CAP不能同時滿足,
為了簡化證明的程序,我們假設整個集群里只有兩個N1和N2兩個節點,如下圖:
N1和N2當中各自有一個應用程式AB和資料庫,當系統滿足一致性的時候,我們認為N1和N2資料庫中的資料保持一致,在滿足可用性的時候,我們認為無論用戶訪問N1還是N2,都可以獲得正確的結果,在滿足磁區容錯性的時候,我們認為無論N1還是N2宕機或者是兩者的通信中斷,都不影響系統的運行,
我們假設一種極端情況,假設某個時刻N1和N2之間的網路通信突然中斷了,如果系統滿足磁區容錯性,那么顯然可以支持這種例外,問題是在此前提下,一致性和可用性是否可以做到不受影響呢?
我們做個假象實驗,如下圖,突然某一時刻N1和N2之間的關聯斷開:
有用戶向N1發送了請求更改了資料,將資料庫從V0更新成了V1,由于網路斷開,所以N2資料庫依然是V0,如果這個時候有一個請求發給了N2,但是N2并沒有辦法可以直接給出最新的結果V1,這個時候該怎么辦呢?
這個時候無法兩種方法,一種是將錯就錯,將錯誤的V0資料回傳給用戶,第二種是阻塞等待,等待網路通信恢復,N2中的資料更新之后再回傳給用戶,顯然前者犧牲了一致性,后者犧牲了可用性,
這個例子雖然簡單,但是說明的內容卻很重要,在分布式系統當中,CAP三個特性我們是無法同時滿足的,必然要舍棄一個,三者舍棄一個,顯然排列組合一共有三種可能,
BASE理論
BASE理論由eBay架構師Dan Pritchett提出,在2008年上被分表為論文,并且eBay給出了他們在實踐中總結的基于BASE理論的一套新的分布式事務解決方案,
BASE 是 Basically Available(基本可用) 、Soft-state(軟狀態) 和 Eventually Consistent(最終一致性) 三個短語的縮寫,BASE理論是對CAP中一致性和可用性權衡的結果,其來源于對大規模互聯網系統分布式實踐的總結,是基于CAP定理逐步演化而來的,它大大降低了我們對系統的要求,
BASE理論的核心思想
即使無法做到強一致性,但每個應用都可以根據自身業務特點,采用適當的方式來使系統達到最終一致性,也就是犧牲資料的一致性來滿足系統的高可用性,系統中一部分資料不可用或者不一致時,仍需要保持系統整體“主要可用”,
針對資料庫領域,BASE思想的主要實作是對業務資料進行拆分,讓不同的資料分布在不同的機器上,以提升系統的可用性,當前主要有以下兩種做法:
- 按功能劃分資料庫
- 分片(如開源的Mycat、Amoeba等),
由于拆分后會涉及分布式事務問題,所以eBay在該BASE論文中提到了如何用最終一致性的思路來實作高性能的分布式事務,
BASE理論三要素
1. 基本可用
基本可用是指分布式系統在出現不可預知故障的時候,允許損失部分可用性,但是,這絕不等價于系統不可用,
比如:
- 回應時間上的損失:正常情況下,一個在線搜索引擎需要在0.5秒之內回傳給用戶相應的查詢結果,但由于出現故障,查詢結果的回應時間增加了1~2秒
- 系統功能上的損失:正常情況下,在一個電子商務網站上進行購物的時候,消費者幾乎能夠順利完成每一筆訂單,但是在一些節日大促購物高峰的時候,由于消費者的購物行為激增,為了保護購物系統的穩定性,部分消費者可能會被引導到一個降級頁面
2. 軟狀態
軟狀態指允許系統中的資料存在中間狀態,并認為該中間狀態的存在不會影響系統的整體可用性,即允許系統在不同節點的資料副本之間進行資料同步的程序存在延時
3. 最終一致性
最終一致性強調的是系統中所有的資料副本,在經過一段時間的同步后,最終能夠達到一個一致的狀態,因此,最終一致性的本質是需要系統保證最終資料能夠達到一致,而不需要實時保證系統資料的強一致性,
負載均衡的演算法與實作
1.輪詢(Round Robin)
輪詢演算法把每個請求輪流發送到每個服務器上,下圖中,一共有 6 個客戶端產生了 6 個請求,這 6 個請求按 (1, 2, 3, 4, 5, 6) 的順序發送,最后,(1, 3, 5) 的請求會被發送到服務器 1,(2, 4, 6) 的請求會被發送到服務器 2,

.
該演算法比較適合每個服務器的性能差不多的場景,如果有性能存在差異的情況下,那么性能較差的服務器可能無法承擔多大的負載,下圖中,服務器 2 的性能比服務器 1 差,那么服務器 2 可能無法承擔多大的負載,

.
1. 加權輪詢(Weighted Round Robbin)
加權輪詢是在輪詢的基礎上,根據服務器的性能差異,為服務器賦予一定的權值,例如下圖中,服務器 1 被賦予的權值為 5,服務器 2 被賦予的權值為 1,那么 (1, 2, 3, 4, 5) 請求會被發送到服務器 1,(6) 請求會被發送到服務器 2,

.
1.3 最少連接(least Connections)
由于每個請求的連接時間不一樣,使用輪詢或者加權輪詢演算法的話,可能會讓一臺服務器當前連接數多大,而另一臺服務器的連接多小,造成負載不均衡,例如下圖中,(1, 3, 5) 請求會被發送到服務器 1,但是 (1, 3) 很快就斷開連接,此時只有 (5) 請求連接服務器 1;(2, 4, 6) 請求被發送到服務器 2,它們的連接都還沒有斷開,繼續運行時,服務器 2 會承擔多大的負載,

.
最少連接演算法就是將請求發送給當前最少連接數的服務器上,例如下圖中,服務器 1 當前連接數最小,那么請求 6 就會被發送到服務器 1 上,

.
1.4 加權最小連接(Weighted Least Connection)
在最小連接的基礎上,根據服務器的性能為每臺服務器分配權重,然后根據權重計算出每臺服務器能處理的連接數,

.
1.5 隨機演算法(Random)
把請求隨機發送到服務器上,和輪詢演算法類似,該演算法比較適合服務器性能差不多的場景,

.
-
實作
2.1 DNS 決議
使用 DNS 作為負載均衡器,會根據負載情況回傳不同服務器的 IP 地址,大型網站基本使用了這種方式最為第一級負載均衡手段,然后在內部在第二級負載均衡,

.
2.2 修改 MAC 地址
使用 LVS(Linux Virtual Server)這種鏈路層負載均衡器,根據負載情況修改請求的 MAC 地址,

.
2.3 修改 IP 地址
在網路層修改請求的目的 IP 地址,

.
2.4 HTTP 重定向
HTTP 重定向負載均衡服務器收到 HTTP 請求之后會回傳服務器的地址,并將該地址寫入 HTTP 重定向回應中回傳給瀏覽器,瀏覽器收到后再次發送請求,

.
2.5 反向代理
正向代理:發生在客戶端,是由用戶主動發起的,比如翻墻,客戶端通過主動訪問代理服務器,讓代理服務器獲得需要的外網資料,然后轉發回客戶端,
反向代理:發生在服務器端,用戶不知道發生了代理,

.
分布式鎖
Java 提供了兩種內置的鎖的實作,一種是由 JVM 實作的 synchronized 和 JDK 提供的 Lock,當你的應用是單機或者說單行程應用時,可以使用 synchronized 或 Lock 來實作鎖,當應用涉及到多機、多行程共同完成時,那么這時候就需要一個全域鎖來實作多個行程之間的同步,
- 使用場景
例如一個應用有手機 APP 端和 Web 端,如果在兩個客戶端同時進行一項操作時,那么就會導致這項操作重復進行,
- 實作方式
資料庫分布式鎖
基于 MySQL 鎖表
該實作方式完全依靠資料庫唯一索引來實作,當想要獲得鎖時,就向資料庫中插入一條記錄,釋放鎖時就洗掉這條記錄,如果記錄具有唯一索引,就不會同時插入同一條記錄,這種方式存在以下幾個問題:
鎖沒有失效時間,解鎖失敗會導致死鎖,其他執行緒無法再獲得鎖,
只能是非阻塞鎖,插入失敗直接就報錯了,無法重試,
不可重入,同一執行緒在沒有釋放鎖之前無法再獲得鎖,
采用樂觀鎖增加版本號
根據版本號來判斷更新之前有沒有其他執行緒更新過,如果被更新過,則獲取鎖失敗,
Redis 分布式鎖
基于 SETNX、EXPIRE
使用 SETNX(set if not exist)命令插入一個鍵值對時,如果 Key 已經存在,那么會回傳 False,否則插入成功并回傳 True,因此客戶端在嘗試獲得鎖時,先使用 SETNX 向 Redis 中插入一個記錄,如果回傳 True 表示獲得鎖,回傳 False 表示已經有客戶端占用鎖,
EXPIRE 可以為一個鍵值對設定一個過期時間,從而避免了死鎖的發生,
RedLock 演算法
ReadLock 演算法使用了多個 Redis 實體來實作分布式鎖,這是為了保證在發生單點故障時還可用,
嘗試從 N 個相互獨立 Redis 實體獲取鎖,如果一個實體不可用,應該盡快嘗試下一個,
計算獲取鎖消耗的時間,只有當這個時間小于鎖的過期時間,并且從大多數(N/2+1)實體上獲取了鎖,那么就認為鎖獲取成功了,
如果鎖獲取失敗,會到每個實體上釋放鎖,
Zookeeper 分布式鎖
Zookeeper 是一個為分布式應用提供一致性服務的軟體,例如配置管理、分布式協同以及命名的中心化等,這些都是分布式系統中非常底層而且是必不可少的基本功能,但是如果自己實作這些功能而且要達到高吞吐、低延遲同時還要保持一致性和可用性,實際上非常困難,
抽象模型
Zookeeper 提供了一種樹形結構級的命名空間,/app1/p_1 節點表示它的父節點為 /app1,

.
節點型別
永久節點:不會因為會話結束或者超時而消失;
臨時節點:如果會話結束或者超時就會消失;
有序節點:會在節點名的后面加一個數字后綴,并且是有序的,例如生成的有序節點為 /lock/node-0000000000,它的下一個有序節點則為 /lock/node-0000000001,依次類推,
監聽器
為一個節點注冊監聽器,在節點狀態發生改變時,會給客戶端發送訊息,
分布式鎖實作
創建一個鎖目錄 /lock,
在 /lock 下創建臨時的且有序的子節點,第一個客戶端對應的子節點為 /lock/lock-0000000000,第二個為 /lock/lock-0000000001,以此類推,
客戶端獲取 /lock 下的子節點串列,判斷自己創建的子節點是否為當前子節點串列中序號最小的子節點,如果是則認為獲得鎖,否則監聽自己的前一個子節點,獲得子節點的變更通知后重復此步驟直至獲得鎖;
執行業務代碼,完成后,洗掉對應的子節點,
會話超時
如果一個已經獲得鎖的會話超時了,因為創建的是臨時節點,因此該會話對應的臨時節點會被洗掉,其它會話就可以獲得鎖了,可以看到,Zookeeper 分布式鎖不會出現資料庫分布式鎖的死鎖問題,
羊群效應
在步驟二,一個節點未獲得鎖,需要監聽監聽自己的前一個子節點,這是因為如果監聽所有的子節點,那么任意一個子節點狀態改變,其它所有子節點都會收到通知,而我們只希望它的下一個子節點收到通知,
分布式 Session
如果不做任何處理的話,用戶將出現頻繁登錄的現象,比如集群中存在 A、B 兩臺服務器,用戶在第一次訪問網站時,Nginx 通過其負載均衡機制將用戶請求轉發到 A 服務器,這時 A 服務器就會給用戶創建一個 Session,當用戶第二次發送請求時,Nginx 將其負載均衡到 B 服務器,而這時候 B 服務器并不存在 Session,所以就會將用戶踢到登錄頁面,這將大大降低用戶體驗度,導致用戶的流失,這種情況是專案絕不應該出現的,
1 粘性 Session
原理
粘性 Session 是指將用戶鎖定到某一個服務器上,比如上面說的例子,用戶第一次請求時,負載均衡器將用戶的請求轉發到了 A 服務器上,如果負載均衡器設定了粘性 Session 的話,那么用戶以后的每次請求都會轉發到 A 服務器上,相當于把用戶和 A 服務器粘到了一塊,這就是粘性 Session 機制,
優點
簡單,不需要對 Session 做任何處理,
缺點
缺乏容錯性,如果當前訪問的服務器發生故障,用戶被轉移到第二個服務器上時,他的 Session 資訊都將失效,
適用場景
發生故障對客戶產生的影響較小;
服務器發生故障是低概率事件,
2 服務器 Session 復制
原理
任何一個服務器上的 Session 發生改變,該節點會把這個 Session 的所有內容序列化,然后廣播給所有其它節點,不管其他服務器需不需要 Session,以此來保證 Session 同步,
優點
可容錯,各個服務器間 Session 能夠實時回應,
缺點
會對網路負荷造成一定壓力,如果 Session 量大的話可能會造成網路堵塞,拖慢服務器性能,
實作方式
設定 Tomcat 的 server.xml 開啟 tomcat 集群功能,
在應用里增加資訊:通知應用當前處于集群環境中,支持分布式,即在 web.xml 中添加 選項,
3 Session 共享機制
使用分布式快取方案比如 Memcached、Redis,但是要求 Memcached 或 Redis 必須是集群,
使用 Session 共享也分兩種機制,兩種情況如下:
3.1 粘性 Session 共享機制
和粘性 Session 一樣,一個用戶的 Session 會系結到一個 Tomcat 上,Memcached 只是起到備份作用,

.
3.2 非粘性 Session 共享機制
原理
Tomcat 本身不存盤 Session,而是存入 Memcached 中,Memcached 集群構建主從復制架構,

.
優點
可容錯,Session 實時回應,
實作方式
用開源的 msm 插件解決 Tomcat 之間的 Session 共享:Memcached_Session_Manager(MSM)
4 Session 持久化到資料庫
原理
拿出一個資料庫,專門用來存盤 Session 資訊,保證 Session 的持久化,
優點
服務器出現問題,Session 不會丟失
缺點
如果網站的訪問量很大,把 Session 存盤到資料庫中,會對資料庫造成很大壓力,還需要增加額外的開銷維護資料庫,
5 Terracotta 實作 Session 復制
原理
Terracotta 的基本原理是對于集群間共享的資料,當在一個節點發生變化的時候,Terracotta 只把變化的部分發送給 Terracotta 服務器,然后由服務器把它轉發給真正需要這個資料的節點,它是服務器 Session 復制的優化,

.
優點
這樣對網路的壓力就非常小,各個節點也不必浪費 CPU 時間和記憶體進行大量的序列化操作,把這種集群間資料共享的機制應用在 Session 同步上,既避免了對資料庫的依賴,又能達到負載均衡和災難恢復的效果,
分庫與分表
分庫與分表帶來的分布式困境與應對之策

.
- 事務問題
使用分布式事務,
- 查詢問題
使用匯總表,
- ID 唯一性
使用全域唯一 ID:GUID;
為每個分片指定一個 ID 范圍
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/256352.html
標籤:其他
