1. 程式人生 > >一些分散式相關問題 (分散式快取、分散式鎖、分散式session、分散式事務、分散式搜尋、Dubbo與SpringCloud、分散式儲存)

一些分散式相關問題 (分散式快取、分散式鎖、分散式session、分散式事務、分散式搜尋、Dubbo與SpringCloud、分散式儲存)

一些分散式相關問題

(分散式快取、分散式鎖、分散式session、分散式事務、分散式搜尋、Dubbo與SpringCloud、分散式儲存MongoDB、高併發系統架構的組成)

分散式快取

專案中使用快取可以做到:高效能(把複雜耗時操作結果快取起來),高併發(高額的請求,在進入資料庫前緩衝下)
常見快取問題:雙寫不一致、快取雪崩、快取穿透、快取併發競爭

分散式鎖

  • redis和zookeeper的分散式鎖的使用,及優缺點?

redis分散式鎖
有一個官方RedLock演算法,是redis官方支援的分散式鎖演算法。重要的是三點:互斥(只有一個客戶端獲取鎖),不死鎖,容錯

zk分散式鎖
就是某節點嘗試建立znode,此時建立成功就獲取鎖;別的客戶端建立鎖會失敗,只能註冊個監聽器監聽這個鎖。釋放鎖就刪除這個znode,通知客戶端,別的等待中的客戶端就可以重新加鎖。

分散式session

tomcat + redis
類似以前的session程式碼一樣,基於tomcat原生session支援即可。利用Tomcat RedisSessionManager部署session存到redis中

springsession + redis
上方策略嚴重依賴web容器且程式碼移植性弱。
基於java一站式解決方案,spring包掉大部分使用的框架,springcloud做微服務mspringboot做腳手架,所以使用spring session


給spring session配置基於redis來儲存session資料,然後配置了一個spring session的過濾器;這樣的話,session相關操作都交由spring session來管理。接著在程式碼中,操作原生session操作即可,基於springsession從redis取資料。

分散式事務

在這裡插入圖片描述

  • 思路一:兩段式提交
    在這裡插入圖片描述

所以這個就是所謂的XA事務,兩階段提交,有一個事務管理器的概念,負責協調多個數據庫(資源管理器)的事務,事務管理器先問問各個資料庫你準備好了嗎?如果每個資料庫都回復ok,那麼就正式提交事務,在各個資料庫上執行操作;如果任何一個數據庫回答不ok,那麼就回滾事務。
這種分散式事務方案,比較適合單塊應用裡,跨多個庫的分散式事務,而且因為嚴重依賴於資料庫層面來搞定複雜的事務,效率很低,絕對不適合高併發的場景。如果要玩兒,那麼基於spring + JTA就可以搞定,自己隨便搜個demo看看就知道了。

這個方案不現實,一般來說某個系統內部如果出現跨多個庫的這麼一個操作,是不合規的。我可以給大家介紹一下, 現在微服務,一個大的系統分成幾百個服務,幾十個服務。一般來說,我們的規定和規範,是要求說每個服務只能操作自己對應的一個數據庫。

如果你要操作別的服務對應的庫,不允許直連別的服務的庫,違反微服務架構的規範,你隨便交叉訪問,導致服務亂套,這樣是沒法管理與治理的,經常資料被別人改錯,自己的庫被別人寫掛。如果你要操作別人的服務的庫,你必須是通過呼叫別的服務的介面來實現,絕對不允許你交叉訪問別人的資料庫!

  • 思路二:TCC方案
    在這裡插入圖片描述

這個其實是用到了補償的概念,分為了三個階段:
1)Try階段:這個階段說的是對各個服務的資源做檢測以及對資源進行鎖定或者預留
2)Confirm階段:這個階段說的是在各個服務中執行實際的操作
3)Cancel階段:如果任何一個服務的業務方法執行出錯,那麼這裡就需要進行補償,就是執行已經執行成功的業務邏輯的回滾操作

比較適合的場景:這個就是除非你是真的一致性要求太高,是你係統中核心之核心的場景,比如常見的就是資金類的場景,那你可以用TCC方案了,自己編寫大量的業務邏輯,自己判斷一個事務中的各個環節是否ok,不ok就執行補償/回滾程式碼。

簡而言之,就是需要自己手寫回滾程式碼經行補償,程式碼量不僅增加,還難以維護。

  • 思路三:可靠訊息最終一致性方案

這個的意思,就是乾脆不要用本地的訊息表了,直接基於MQ來實現事務。比如阿里的RocketMQ就支援訊息事務。
在這裡插入圖片描述
大概的意思就是:
1)A系統先發送一個prepared訊息到mq,如果這個prepared訊息傳送失敗那麼就直接取消操作別執行了
2)如果這個訊息傳送成功過了,那麼接著執行本地事務,如果成功就告訴mq傳送確認訊息,如果失敗就告訴mq回滾訊息
3)如果傳送了確認訊息,那麼此時B系統會接收到確認訊息,然後執行本地的事務
4)mq會自動定時輪詢所有prepared訊息回撥你的介面,問你,這個訊息是不是本地事務處理失敗了,所有沒傳送確認訊息?那是繼續重試還是回滾?一般來說這裡你就可以查下資料庫看之前本地事務是否執行,如果回滾了,那麼這裡也回滾吧。這個就是避免可能本地事務執行成功了,別確認訊息傳送失敗了。
5)這個方案裡,要是系統B的事務失敗了咋辦?重試咯,自動不斷重試直到成功,如果實在是不行,要麼就是針對重要的資金類業務進行回滾,比如B系統本地回滾後,想辦法通知系統A也回滾;或者是傳送報警由人工來手工回滾和補償

這個還是比較合適的,目前國內網際網路公司大都是這麼玩兒的,要不你舉用RocketMQ支援的,要不你就自己基於類似ActiveMQ?RabbitMQ?自己封裝一套類似的邏輯出來,總之思路就是這樣子的。

  • 思路四:最大努力通知方案
    在這裡插入圖片描述
    這個方案的大致意思就是:

1)系統A本地事務執行完之後,傳送個訊息到MQ
2)這裡會有個專門消費MQ的最大努力通知服務,這個服務會消費MQ然後寫入資料庫中記錄下來,或者是放入個記憶體佇列也可以,接著呼叫系統B的介面
3)要是系統B執行成功就ok了;要是系統B執行失敗了,那麼最大努力通知服務就定時嘗試重新呼叫系統B,反覆N次,最後還是不行就放棄

假如,我們現在想保證我們的某個系統非常的可靠,任何一個數據都不能錯,我們用的是微服務架構,幾十個服務。結果我們一盤點,發現,如果到處都要搞的話,一個系統要做幾十個分散式事務出來。
我們的經驗,我帶幾十人的team,最大的一個專案,起碼幾百個服務,複雜的分散式大型系統,裡面其實也沒幾個分散式事務。
你其實用任何一個分散式事務的這麼一個方案,都會導致你那塊兒程式碼會複雜10倍。很多情況下,系統A呼叫系統B、系統C、系統D,我們可能根本就不做分散式事務。如果呼叫報錯會列印異常日誌。
每個月也就那麼幾個bug,很多bug是功能性的,體驗性的,真的是涉及到資料層面的一些bug,一個月就幾個,兩三個?如果你為了確保系統自動保證資料100%不能錯,上了幾十個分散式事務,程式碼太複雜;效能太差,系統吞吐量、效能大幅度下跌。
99%的分散式介面呼叫,不要做分散式事務,直接就是監控(發郵件、發簡訊)、記錄日誌(一旦出錯,完整的日誌)、事後快速的定位、排查和出解決方案、修復資料。
每個月,每隔幾個月,都會對少量的因為程式碼bug,導致出錯的資料,進行人工的修復資料,自己臨時動手寫個程式,可能要補一些資料,可能要刪除一些資料,可能要修改一些欄位的值。
比你做50個分散式事務,成本要來的低上百倍,低幾十倍
trade off,權衡,要用分散式事務的時候,一定是有成本,程式碼會很複雜,開發很長時間,效能和吞吐量下跌,系統更加複雜更加脆弱反而更加容易出bug;好處,如果做好了,TCC、可靠訊息最終一致性方案,一定可以100%保證你那快資料不會出錯。
1%,0.1%,0.01%的業務,資金、交易、訂單,我們會用分散式事務方案來保證,會員積分、優惠券、商品資訊,其實不要這麼搞了

分散式搜尋ES——ElasticSearch

底層還是lucene。核心思想:在多臺機器上啟動多個es程序例項,組成es叢集,es在儲存資料的基本單位是索引
index—>type—>mapping—>document—>field
(庫)       (表)       (表的定義)       (行)

  • ES寫資料
    1)客戶端選擇一個node傳送請求過去,這個node就是coordinating node(協調節點)
    2)coordinating node,對document進行路由,將請求轉發給對應的node(有primary shard)
    3)實際的node上的primary shard處理請求,然後將資料同步到replica node
    4)coordinating node,如果發現primary node和所有replica node都搞定之後,就返回響應結果給客戶端

  • ES讀資料
    查詢,GET某一條資料,寫入了某個document,這個document會自動給你分配一個全域性唯一的id,doc id,同時也是根據doc id進行hash路由到對應的primary shard上面去。也可以手動指定doc id,比如用訂單id,使用者id。
    你可以通過doc id來查詢,會根據doc id進行hash,判斷出來當時把doc id分配到了哪個shard上面去,從那個shard去查詢
    1)客戶端傳送請求到任意一個node,成為coordinate node
    2)coordinate node對document進行路由,將請求轉發到對應的node,此時會使用round-robin隨機輪詢演算法,在primary shard以及其所有replica中隨機選擇一個,讓讀請求負載均衡
    3)接收請求的node返回document給coordinate node
    4)coordinate node返回document給客戶端

  • ES搜尋資料
    1)客戶端傳送請求到一個coordinate node
    2)協調節點將搜尋請求轉發到所有的shard對應的primary shard或replica shard也可以
    3)query phase:每個shard將自己的搜尋結果(其實就是一些doc id),返回給協調節點,由協調節點進行資料的合併、排序、分頁等操作,產出最終結果
    4)fetch phase:接著由協調節點,根據doc id去各個節點上拉取實際的document資料,最終返回給客戶端

  • 搜尋的底層原理,倒排索引,畫圖說明傳統資料庫和倒排索引的區別

  • 寫資料底層原理

1)先寫入buffer,在buffer裡的時候資料是搜尋不到的;同時將資料寫入translog日誌檔案

2)如果buffer快滿了,或者到一定時間,就會將buffer資料refresh到一個新的segment file中,但是此時資料不是直接進入segment file的磁碟檔案的,而是先進入os cache的。這個過程就是refresh。

每隔1秒鐘,es將buffer中的資料寫入一個新的segment file,每秒鐘會產生一個新的磁碟檔案,segment file,這個segment file中就儲存最近1秒內buffer中寫入的資料

但是如果buffer裡面此時沒有資料,那當然不會執行refresh操作咯,每秒建立換一個空的segment file,如果buffer裡面有資料,預設1秒鐘執行一次refresh操作,刷入一個新的segment file中

作業系統裡面,磁碟檔案其實都有一個東西,叫做os cache,作業系統快取,就是說資料寫入磁碟檔案之前,會先進入os cache,先進入作業系統級別的一個記憶體快取中去

只要buffer中的資料被refresh操作,刷入os cache中,就代表這個資料就可以被搜尋到了

為什麼叫es是準實時的?NRT,near real-time,準實時。預設是每隔1秒refresh一次的,所以es是準實時的,因為寫入的資料1秒之後才能被看到。

可以通過es的restful api或者java api,手動執行一次refresh操作,就是手動將buffer中的資料刷入os cache中,讓資料立馬就可以被搜尋到。

只要資料被輸入os cache中,buffer就會被清空了,因為不需要保留buffer了,資料在translog裡面已經持久化到磁碟去一份了

3)只要資料進入os cache,此時就可以讓這個segment file的資料對外提供搜尋了

4)重複1~3步驟,新的資料不斷進入buffer和translog,不斷將buffer資料寫入一個又一個新的segment file中去,每次refresh完buffer清空,translog保留。隨著這個過程推進,translog會變得越來越大。當translog達到一定長度的時候,就會觸發commit操作。

buffer中的資料,倒是好,每隔1秒就被刷到os cache中去,然後這個buffer就被清空了。所以說這個buffer的資料始終是可以保持住不會填滿es程序的記憶體的。

每次一條資料寫入buffer,同時會寫入一條日誌到translog日誌檔案中去,所以這個translog日誌檔案是不斷變大的,當translog日誌檔案大到一定程度的時候,就會執行commit操作。

5)commit操作發生第一步,就是將buffer中現有資料refresh到os cache中去,清空buffer

6)將一個commit point寫入磁碟檔案,裡面標識著這個commit point對應的所有segment file

7)強行將os cache中目前所有的資料都fsync到磁碟檔案中去

translog日誌檔案的作用是什麼?就是在你執行commit操作之前,資料要麼是停留在buffer中,要麼是停留在os cache中,無論是buffer還是os cache都是記憶體,一旦這臺機器死了,記憶體中的資料就全丟了。

所以需要將資料對應的操作寫入一個專門的日誌檔案,translog日誌檔案中,一旦此時機器宕機,再次重啟的時候,es會自動讀取translog日誌檔案中的資料,恢復到記憶體buffer和os cache中去。

commit操作:1、寫commit point;2、將os cache資料fsync強刷到磁碟上去;3、清空translog日誌檔案

8)將現有的translog清空,然後再次重啟啟用一個translog,此時commit操作完成。預設每隔30分鐘會自動執行一次commit,但是如果translog過大,也會觸發commit。整個commit的過程,叫做flush操作。我們可以手動執行flush操作,就是將所有os cache資料刷到磁碟檔案中去。

不叫做commit操作,flush操作。es中的flush操作,就對應著commit的全過程。我們也可以通過es api,手動執行flush操作,手動將os cache中的資料fsync強刷到磁碟上去,記錄一個commit point,清空translog日誌檔案。

9)translog其實也是先寫入os cache的,預設每隔5秒刷一次到磁碟中去,所以預設情況下,可能有5秒的資料會僅僅停留在buffer或者translog檔案的os cache中,如果此時機器掛了,會丟失5秒鐘的資料。但是這樣效能比較好,最多丟5秒的資料。也可以將translog設定成每次寫操作必須是直接fsync到磁碟,但是效能會差很多。

實際上你在這裡,如果面試官沒有問你es丟資料的問題,你可以在這裡給面試官炫一把,你說,其實es第一是準實時的,資料寫入1秒後可以搜尋到;可能會丟失資料的,你的資料有5秒的資料,停留在buffer、translog os cache、segment file os cache中,有5秒的資料不在磁碟上,此時如果宕機,會導致5秒的資料丟失。

如果你希望一定不能丟失資料的話,你可以設定個引數,官方文件,百度一下。每次寫入一條資料,都是寫入buffer,同時寫入磁碟上的translog,但是這會導致寫效能、寫入吞吐量會下降一個數量級。本來一秒鐘可以寫2000條,現在你一秒鐘只能寫200條,都有可能。

10)如果是刪除操作,commit的時候會生成一個.del檔案,裡面將某個doc標識為deleted狀態,那麼搜尋的時候根據.del檔案就知道這個doc被刪除了

11)如果是更新操作,就是將原來的doc標識為deleted狀態,然後新寫入一條資料

12)buffer每次refresh一次,就會產生一個segment file,所以預設情況下是1秒鐘一個segment file,segment file會越來越多,此時會定期執行merge

13)每次merge的時候,會將多個segment file合併成一個,同時這裡會將標識為deleted的doc給物理刪除掉,然後將新的segment file寫入磁碟,這裡會寫一個commit point,標識所有新的segment file,然後開啟segment file供搜尋使用,同時刪除舊的segment file。

es裡的寫流程,有4個底層的核心概念,refresh、flush、translog、merge

當segment file多到一定程度的時候,es就會自動觸發merge操作,將多個segment file給merge成一個segment file。

分散式解決方案 Dubbo

  • Dubbo的缺點,過分依賴zookeeper,就是過分依賴註冊中心。在微服務中,應該做到各司其職,就是註冊中心服務閘道器,配置中心,三者不應該耦合度那麼高。【與springcloud的對比:註冊中心——Eureka、服務閘道器——Zuul、配置中心——SpringCloud Config】
    微服務理應各個服務解耦,獨立不相關的。

【面試點】dubbo是如何實現負載均衡的?dubbo需要動態獲取服務列表,才能呼叫服務 。

  • Dubbo的容錯策略,沒有細粒度到方法級別上;負載均衡則可以確定到方法上,導致使用上有一定的彆扭。

  • 引申出的問題:一個服務,如果都是查詢,配置成failover;若有新增或修改,一定要配置成failfast
    目前Dubbo的叢集容錯策略,還沒有能夠細粒度到方法上

  • Dubbo在微服務的地位
    Dubbo更擅長Tcp/Ip協議,雖然支援http協議,但是那樣就是相當於一個單機的傳統業務,類似部署在tomcat中了。

dubbo所暴露的服務,一般情況下是不支援瀏覽器的。服務面向tcp/ip的客戶端

圖圖

Dubbo多用於內網叢集間通訊,解決服務叢集之間的呼叫的,然後Application/Controller控制層想要呼叫服務,連線到的是註冊中心

使用者訪問的是Nginx,然後訪問應用,再訪問註冊中心…這個過程之中,使用者是感覺不出來使用了dubbo。dubbo擅長構建內網的,基於tcp/ip通訊的叢集

Dubbo是將原來應用中的service剝離出來,然後暴露出來,而controller沒變。MVC三層中的Model層進行了剝離拆分。

而SpringCloud才是擅長分離應用層/控制層。綜上dubbo和springcloud各有擅長的領域。dubbo擅長內網基於模型,業務層的拆分、springcloud則是擅長對控制層拆分。dubbo主內,springcloud主外。

又因為業務層主要是內部通訊,毋須面向使用者,且使用tcp/ip層協議能更好的提升效能,選擇Dubbo;對外使用springcloud,對controller進行拆分,再用上分散式的Nosql,就是全棧分散式

分散式解決方案 SpringCloud

  • 什麼是微服務?
    基於SOA架構的一種架構,系統中各個微服務可被獨立部署,微服務間解耦合,各服務單一職責。
    特點是:分散式業務拆分
    微服務的設計原則:AFK拆分原則(x軸水平擴充套件,y軸垂直拆分)、前後端分離原則無狀態服務(把有狀態業務變成無狀態計算類服務,將狀態資料放到分散式快取中儲存,這樣微服務的動態增刪不需在考慮資料同步)、RestFul通訊風格

微服務的4個設計原則和19個解決方案http://p.primeton.com/articles/59b0f9244be8e61fea00be67

思路:基於服務名,可以查詢服務列表,再根據負載均衡策略,選擇一個服務,這樣實現對controller的負載均衡呼叫;那如果想要實現自動的服務發現與註冊,引入註冊中心的概念。去把服務和服務列表註冊到某個路徑下,日後可以查詢。

  • Ribbon的作用?
    其實就是操縱了spring中的工具類RestTemplate,去修改RestTemplate中的呼叫服務列表的地址,做到來回的切換地址,這樣就實現了簡單的負載均衡。

只有Eureka是AP,其他學到的Nosql和ZK都是CP,留了可用性,就無法保證一致性。

  • Eureka與Ribbon,實現負載均衡的思路:
    (SpringCloud負載中心的本質),本質是修改RestTemplate的攔截器,在攔截器中集成了Eureka,Eureka去查詢服務列表,拿到服務列表之後,實現了一套負載均衡策略,預設輪詢。

  • 熔斷與容錯
    熔斷:當呼叫超時時,進行熔斷處理
    容錯:當呼叫失敗時,進行容錯處理

  • SpringCloud是利用NetFilx的Hystrix實現類來實現熔斷,對加註解的controller方法做一個環繞通知,切到HystrixCommand方法實現中,容錯/熔斷就走getFallback方法

  • 熔斷器的使用簡述:
    引入依賴、入口類上加註解(@EnableCircuitBreaker等價於@EnableHystrix)、要切的方法上加上註解(@HystrixCommand)

  • SpringCloudConfig
    未來開發專案,想要動態變更引數配置, 將這個類寫成元件bean,在bean類上加@RefreshScope,這樣Spring在生產這個bean的時候,會基於這個bean生成一個代理物件,對類中的所有方法進行代理,當執行重新整理方法的時候;它會重新對bean的代理物件bean引數賦值。

  • Bus 訊息匯流排

  • Zuul 服務閘道器
    閘道器就相當於代理,可以把服務對映為對應url,因為網路服務太多,那需要統一一個入口,讓使用者藉由閘道器訪問後臺服務,這樣效能會有損耗。好處是可以規劃服務,所有請求訪問閘道器入口下的url,可以將後臺叢集規模隱藏。另一個好處是,提供Filter功能,邊緣化服務。

疑問:為什麼不使用Nginx來做閘道器呢? Nginx無法搭建叢集(只有概念,沒有實操)

  • 根據點選做推薦+flume採集示例:
    搭建完閘道器後,請求走的是zuul閘道器,這樣可以利用filter可以拿到request請求,可以作統計處理。就是發的請求,會有固定的一串東西,最後拿到東西的id,可以將點選傳給flume,後臺就可以統計並記錄。 打分同理:拿到xxxScore的url,將打分儲存起來,可以對登入使用者基於打分進行推薦了。

  • 許可權管理示例:
    閘道器filter可以拿到request,那當然也可以拿到對應的session,也就能拿到對應使用者。
    服務邊緣化:springcloud在開發微服務的過程中,可以對服務進行拆分,但是服務對外界的形式需要是閘道器形式,任何請求不可以對內直接呼叫,內網架構不能向外暴露,對使用者暴露的只可以是閘道器。
    建立閘道器,在閘道器加上許可權控制,每個業務互相訪問,先走的一定是閘道器。這樣可以防止非法的服務訪問。


  • 總結:
    Ribbon:負載均衡,原理是利用給restTemplate增加攔截器,攔截器修改訪問的ip和port;
    Eureka:Ribbon一般需要和Eureka整合,拿到服務所對應的服務列表,隨機的去調,修改方式是在bean工廠中注入一個xxx實現類,有不同的策略 輪詢或隨機,兩者結合就可以實現功能了;
    Hystrix:斷路器,原理是藉助Netfilx的Hystrix工具包,通過非同步的形式啟動,主執行緒負責計時,計運算元執行緒請求處理時間,超時熔斷,子執行緒失敗容錯。Hystrix可以用在服務端,也可以用在呼叫端,實現原理就是aop,對加註解的方法做環繞通知,起到熔斷容錯策略。
    Config:配置伺服器,可以集中應用中的配置。目前可以將配置放到git上。配置伺服器實現動態重新整理的原理是:在服務啟動時,配置的bean會通過代理,重新整理賦值。
    Bus:訊息匯流排,讓配置伺服器的提供方和引用方,都註冊到訊息隊列當中,這樣執行任意一臺,busrefrush可以更新所有節點
    Zuul:服務閘道器,作用是遮蔽後臺服務,對外提供一個統一的入口,類似於Nginx代理伺服器

分散式儲存MongoDB

  • 一些小tips
    結構大致是:庫 —— 集合 —— 記錄
    集合大小不限,單條記錄16MB限制;大於16MB用GridFS儲存大檔案。

MongoDB適合儲存大尺寸,低價值資料,比如歸檔資料,指的是舊資料

  • 一些小tips2
    Mongodb中,固定集合capped的使用,例如輪播圖
    Mongodb DML中一些注意點:

save和insert區別:
在沒有_id的情況下,兩者一樣都是自動產生_id的插入;
當給定_id時,insert是插入,save則可能是更新

find和findone區別:
findone返回的是json文件,就是一個變數;
find返回遊標,效果是這能遍歷一次。

空值查詢:利用type型別null,也可以利用exist存在false

分頁中size和count的區別:
size:返回遊標大小,受分頁引數影響
count:返回的是查詢匹配的記錄總條數


高併發系統架構的組成

  1. 系統拆分:將一個系統拆分成若干子系統,例如dubbo來搞定;然後每個系統連線一個數據庫,做到多資料庫抗高併發。
  2. 快取:高併發場景,一般讀多寫少,就是讓讀請求走快取。redis可以做到單機幾萬併發
  3. MQ:高併發場景,業務操作頻繁操作資料庫,redis無法承載,且資料格式簡單無事務;所以使用MQ,大量請求堆積在MQ中,排好隊後,慢慢寫調,控制在mysql承載範圍內。
    所以考慮在專案裡,那些承載複雜寫業務邏輯的場景裡,如何用MQ來非同步寫,提高併發性。MQ單機抗幾萬併發也是ok的。
  4. 分庫分表:資料庫也要高併發,對資料庫進行拆分,拆庫抗高併發,拆表提升sql效能。
  5. 讀寫分離:資料庫多是讀多寫少,每必要所有請求集中在一個庫上。
    使用主從架構,主寫從讀,讀大流量時動態新增更多從庫。
  6. ES:分散式搜尋,天然分散式支援高併發。可以一些比較簡單的查詢、統計類的操作,可以考慮用es來承載,還有一些全文搜尋類的操作,也可以考慮用es來承載。

其實實際上在真正的複雜的業務系統裡,做高併發要遠遠比我這個圖複雜幾十倍到上百倍。你需要考慮,哪些需要分庫分表,哪些不需要分庫分表,單庫單表跟分庫分表如何join,哪些資料要放到快取裡去啊,放哪些資料再可以抗掉高併發的請求,你需要完成對一個複雜業務系統的分析之後,然後逐步逐步的加入高併發的系統架構的改造,這個過程是務必複雜的,一旦做過一次,一旦做好了,你在這個市場上就會非常的吃香。
其實大部分公司,真正看重的,不是說你掌握高併發相關的一些基本的架構知識,架構中的一些技術,RocketMQ、Kafka、Redis、Elasticsearch,高併發這一塊,單單有技術的人才。
真正想要的是,對一個有幾十萬行程式碼的複雜的分散式系統,一步一步架構、設計以及實踐過高併發架構的人,這個經驗是難能可貴的。

  • 技術對應:
    高併發分流 —— Nginx —— Tengine
    高併發快取 —— Redis、Memcached —— Tair
    分散式訊息佇列 —— RabbitMQ、Kafka —— Notify、MetaQ
    分散式儲存 —— ShardingJDBC、MongoDB —— 分散式資料庫
    分散式協調工具 —— Zookeeper、Dubbo —— 分散式服務HSF(最新一代RPC框架HSF,全稱High Speed Framework)
    分散式通訊框架
    Docker容器技術

  • 網際網路技術架構圖

請求先經過LVS或F5硬體,進行負載均衡,然後交給Nginx叢集【作用seesion分散式共享,Nginx本地快取,動靜分離】,然後真正的請求去到API閘道器,根據驗證和引數情況調控,這時會用到中介軟體技術,如快取服務,搜尋服務,MQ傳送到微服務叢集中等,如果可以從緩資料,就直接走快取;搜尋引擎同理,之後未被處理的請求會來到微服務叢集。這一切一切是為了減輕後端儲存服務的壓力【傳統DB、檔案儲存、NoSql】。其他還有些元件如配置中心、服務註冊發現、服務編排,為一系列業務服務。