分佈式系統常見問題總結(一)css
參考:html
微信公衆號:架構師之路前端
1)im系統,例如qq或者微博,每一個人都讀本身的數據(好友列表、羣列表、我的信息);mysql
2)微博系統,每一個人讀你關注的人的數據,一我的讀多我的的數據;nginx
3)秒殺系統,庫存只有一份,全部人會在集中的時間讀和寫這些數據,多我的讀一個數據。程序員
例如:小米手機每週二的秒殺,可能手機只有1萬部,但瞬時進入的流量多是幾百幾千萬。web
又例如:12306搶票,票是有限的,庫存一份,瞬時流量很是多,都讀相同的庫存。讀寫衝突,鎖很是嚴重,這是秒殺業務難的地方。那咱們怎麼優化秒殺業務的架構呢?redis
優化方向有兩個(今天就講這兩個點):算法
(1)將請求儘可能攔截在系統上游(不要讓鎖衝突落到數據庫上去)。傳統秒殺系統之因此掛,請求都壓倒了後端數據層,數據讀寫鎖衝突嚴重,併發高響應慢,幾乎全部請求都超時,流量雖大,下單成功的有效流量甚小。以12306爲例,一趟火車其實只有2000張票,200w我的來買,基本沒有人能買成功,請求有效率爲0。sql
(2)充分利用緩存,秒殺買票,這是一個典型的讀多些少的應用場景,大部分請求是車次查詢,票查詢,下單和支付纔是寫請求。一趟火車其實只有2000張票,200w我的來買,最多2000我的下單成功,其餘人都是查詢庫存,寫比例只有0.1%,讀比例佔99.9%,很是適合使用緩存來優化。好,後續講講怎麼個「將請求儘可能攔截在系統上游」法,以及怎麼個「緩存」法,講講細節。
常見的站點架構基本是這樣的(絕對不畫忽悠類的架構圖)
(1)瀏覽器端,最上層,會執行到一些JS代碼
(2)站點層,這一層會訪問後端數據,拼html頁面返回給瀏覽器
(3)服務層,向上遊屏蔽底層數據細節,提供數據訪問
(4)數據層,最終的庫存是存在這裏的,mysql是一個典型(固然還有會緩存)
這個圖雖然簡單,但能形象的說明大流量高併發的秒殺業務架構,你們要記得這一張圖。
後面細細解析各個層級怎麼優化。
第一層,客戶端怎麼優化(瀏覽器層,APP層)
問你們一個問題,你們都玩過微信的搖一搖搶紅包對吧,每次搖一搖,就會日後端發送請求麼?回顧咱們下單搶票的場景,點擊了「查詢」按鈕以後,系統那個卡呀,進度條漲的慢呀,做爲用戶,我會不自覺的再去點擊「查詢」,對麼?繼續點,繼續點,點點點。。。有用麼?無緣無故的增長了系統負載,一個用戶點5次,80%的請求是這麼多出來的,怎麼整?
(a)產品層面,用戶點擊「查詢」或者「購票」後,按鈕置灰,禁止用戶重複提交請求;
(b)JS層面,限制用戶在x秒以內只能提交一次請求;
APP層面,能夠作相似的事情,雖然你瘋狂的在搖微信,其實x秒才向後端發起一次請求。這就是所謂的「將請求儘可能攔截在系統上游」,越上游越好,瀏覽器層,APP層就給攔住,這樣就能擋住80%+的請求,這種辦法只能攔住普通用戶(但99%的用戶是普通用戶)對於羣內的高端程序員是攔不住的。firebug一抓包,http長啥樣都知道,js是萬萬攔不住程序員寫for循環,調用http接口的,這部分請求怎麼處理?
第二層,站點層面的請求攔截
怎麼攔截?怎麼防止程序員寫for循環調用,有去重依據麼?ip?cookie-id?…想複雜了,這類業務都須要登陸,用uid便可。在站點層面,對uid進行請求計數和去重,甚至不須要統一存儲計數,直接站點層內存存儲(這樣計數會不許,但最簡單)。一個uid,5秒只准透過1個請求,這樣又能攔住99%的for循環請求。
5s只透過一個請求,其他的請求怎麼辦?緩存,頁面緩存,同一個uid,限制訪問頻度,作頁面緩存,x秒內到達站點層的請求,均返回同一頁面。同一個item的查詢,例如車次,作頁面緩存,x秒內到達站點層的請求,均返回同一頁面。如此限流,既能保證用戶有良好的用戶體驗(沒有返回404)又能保證系統的健壯性(利用頁面緩存,把請求攔截在站點層了)。
頁面緩存不必定要保證全部站點返回一致的頁面,直接放在每一個站點的內存也是能夠的。優勢是簡單,壞處是http請求落到不一樣的站點,返回的車票數據可能不同,這是站點層的請求攔截與緩存優化。
好,這個方式攔住了寫for循環發http請求的程序員,有些高端程序員(黑客)控制了10w個肉雞,手裏有10w個uid,同時發請求(先不考慮實名制的問題,小米搶手機不須要實名制),這下怎麼辦,站點層按照uid限流攔不住了。
第三層 服務層來攔截(反正就是不要讓請求落到數據庫上去)
服務層怎麼攔截?大哥,我是服務層,我清楚的知道小米只有1萬部手機,我清楚的知道一列火車只有2000張車票,我透10w個請求去數據庫有什麼意義呢?沒錯,請求隊列!
對於寫請求,作請求隊列,每次只透有限的寫請求去數據層(下訂單,支付這樣的寫業務)
1w部手機,只透1w個下單請求去db
3k張火車票,只透3k個下單請求去db
若是均成功再放下一批,若是庫存不夠則隊列裏的寫請求所有返回「已售完」。
對於讀請求,怎麼優化?cache抗,無論是memcached仍是redis,單機抗個每秒10w應該都是沒什麼問題的。如此限流,只有很是少的寫請求,和很是少的讀緩存mis的請求會透到數據層去,又有99.9%的請求被攔住了。
固然,還有業務規則上的一些優化。回想12306所作的,分時分段售票,原來統一10點賣票,如今8點,8點半,9點,...每隔半個小時放出一批:將流量攤勻。
其次,數據粒度的優化:你去購票,對於餘票查詢這個業務,票剩了58張,仍是26張,你真的關注麼,其實咱們只關心有票和無票?流量大的時候,作一個粗粒度的「有票」「無票」緩存便可。
第三,一些業務邏輯的異步:例以下單業務與 支付業務的分離。這些優化都是結合 業務 來的,我以前分享過一個觀點「一切脫離業務的架構設計都是耍流氓」架構的優化也要針對業務。
好了,最後是數據庫層
瀏覽器攔截了80%,站點層攔截了99.9%並作了頁面緩存,服務層又作了寫請求隊列與數據緩存,每次透到數據庫層的請求都是可控的。db基本就沒什麼壓力了,閒庭信步,單機也能扛得住,仍是那句話,庫存是有限的,小米的產能有限,透這麼多請求來數據庫沒有意義。
所有透到數據庫,100w個下單,0個成功,請求有效率0%。透3k個到數據,所有成功,請求有效率100%。
上文應該描述的很是清楚了,沒什麼總結了,對於秒殺系統,再次重複下我我的經驗的兩個架構優化思路:
(1)儘可能將請求攔截在系統上游(越上游越好);
(2)讀多寫少的經常使用多使用緩存(緩存抗讀壓力);
瀏覽器和APP:作限速
站點層:按照uid作限速,作頁面緩存
服務層:按照業務作寫請求隊列控制流量,作數據緩存
數據層:閒庭信步
而且:結合業務作優化
問題1、按你的架構,其實壓力最大的反而是站點層,假設真實有效的請求數有1000萬,不太可能限制請求鏈接數吧,那麼這部分的壓力怎麼處理?
答:每秒鐘的併發可能沒有1kw,假設有1kw,解決方案2個:
(1)站點層是能夠經過加機器擴容的,最不濟1k臺機器來唄。
(2)若是機器不夠,拋棄請求,拋棄50%(50%直接返回稍後再試),原則是要保護系統,不能讓全部用戶都失敗。
問題2、「控制了10w個肉雞,手裏有10w個uid,同時發請求」 這個問題怎麼解決哈?
答:上面說了,服務層寫請求隊列控制
問題3:限制訪問頻次的緩存,是否也能夠用於搜索?例如A用戶搜索了「手機」,B用戶搜索「手機」,優先使用A搜索後生成的緩存頁面?
答:這個是能夠的,這個方法也常常用在「動態」運營活動頁,例如短期推送4kw用戶app-push運營活動,作頁面緩存。
問題4:若是隊列處理失敗,如何處理?肉雞把隊列被撐爆了怎麼辦?
答:處理失敗返回下單失敗,讓用戶再試。隊列成本很低,爆了很難吧。最壞的狀況下,緩存了若干請求以後,後續請求都直接返回「無票」(隊列裏已經有100w請求了,都等着,再接受請求也沒有意義了)
問題5:站點層過濾的話,是把uid請求數單獨保存到各個站點的內存中麼?若是是這樣的話,怎麼處理多臺服務器集羣通過負載均衡器將相同用戶的響應分佈到不一樣服務器的狀況呢?仍是說將站點層的過濾放到負載均衡前?
答:能夠放在內存,這樣的話看似一臺服務器限制了5s一個請求,全局來講(假設有10臺機器),實際上是限制了5s 10個請求,解決辦法:
1)加大限制(這是建議的方案,最簡單)
2)在nginx層作7層均衡,讓一個uid的請求儘可能落到同一個機器上
問題6:服務層過濾的話,隊列是服務層統一的一個隊列?仍是每一個提供服務的服務器各一個隊列?若是是統一的一個隊列的話,需不須要在各個服務器提交的請求入隊列前進行鎖控制?
答:能夠不用統一一個隊列,這樣的話每一個服務透過更少許的請求(總票數/服務個數),這樣簡單。統一一個隊列又複雜了。
問題7:秒殺以後的支付完成,以及未支付取消佔位,如何對剩餘庫存作及時的控制更新?
答:數據庫裏一個狀態,未支付。若是超過期間,例如45分鐘,庫存會從新會恢復(你們熟知的「回倉」),給咱們搶票的啓示是,開動秒殺後,45分鐘以後再試試看,說不定又有票喲~
問題8:不一樣的用戶瀏覽同一個商品 落在不一樣的緩存實例顯示的庫存徹底不同 請問老師怎麼作緩存數據一致或者是容許髒讀?
答:目前的架構設計,請求落到不一樣的站點上,數據可能不一致(頁面緩存不同),這個業務場景能接受。但數據庫層面真實數據是沒問題的。
問題9:就算處於業務把優化考慮「3k張火車票,只透3k個下單請求去db」那這3K個訂單就不會發生擁堵了嗎?
答:(1)數據庫抗3k個寫請求仍是ok的;(2)能夠數據拆分;(3)若是3k扛不住,服務層能夠控制透過去的併發數量,根據壓測狀況來吧,3k只是舉例;
問題10;若是在站點層或者服務層處理後臺失敗的話,需不須要考慮對這批處理失敗的請求作重放?仍是就直接丟棄?
答:別重放了,返回用戶查詢失敗或者下單失敗吧,架構設計原則之一是「fail fast」。
問題11.對於大型系統的秒殺,好比12306,同時進行的秒殺活動不少,如何分流?
答:垂直拆分
問題12、額外又想到一個問題。這套流程作成同步仍是異步的?若是是同步的話,應該還存在會有響應反饋慢的狀況。但若是是異步的話,如何控制可以將響應結果返回正確的請求方?
答:用戶層面確定是同步的(用戶的http請求是夯住的),服務層面能夠同步能夠異步。
問題13、秒殺羣提問:減庫存是在那個階段減呢?若是是下單鎖庫存的話,大量惡意用戶下單鎖庫存而不支付如何處理呢?
答:數據庫層面寫請求量很低,還好,下單不支付,等時間過完再「回倉」,以前提過了。
1、需求緣起
幾乎全部的業務系統,都有生成一個記錄標識的需求,例如:
(1)消息標識:message-id
(2)訂單標識:order-id
(3)帖子標識:tiezi-id
這個記錄標識每每就是數據庫中的惟一主鍵,數據庫上會創建彙集索引(cluster index),即在物理存儲上以這個字段排序。
這個記錄標識上的查詢,每每又有分頁或者排序的業務需求,例如:
(1)拉取最新的一頁消息:selectmessage-id/ order by time/ limit 100
(2)拉取最新的一頁訂單:selectorder-id/ order by time/ limit 100
(3)拉取最新的一頁帖子:selecttiezi-id/ order by time/ limit 100
因此每每要有一個time字段,而且在time字段上創建普通索引(non-cluster index)。
咱們都知道普通索引存儲的是實際記錄的指針,其訪問效率會比彙集索引慢,若是記錄標識在生成時可以基本按照時間有序,則能夠省去這個time字段的索引查詢:
select message-id/ (order by message-id)/limit 100
再次強調,能這麼作的前提是,message-id的生成基本是趨勢時間遞增的。
這就引出了記錄標識生成(也就是上文提到的三個XXX-id)的兩大核心需求:
(1)全局惟一
(2)趨勢有序
這也是本文要討論的核心問題:如何高效生成趨勢有序的全局惟一ID。
2、常見方法、不足與優化
【常見方法一:使用數據庫的 auto_increment 來生成全局惟一遞增ID】
優勢:
(1)簡單,使用數據庫已有的功能
(2)可以保證惟一性
(3)可以保證遞增性
(4)步長固定
缺點:
(1)可用性難以保證:數據庫常見架構是一主多從+讀寫分離,生成自增ID是寫請求,主庫掛了就玩不轉了
(2)擴展性差,性能有上限:由於寫入是單點,數據庫主庫的寫性能決定ID的生成性能上限,而且難以擴展
改進方法:
(1)增長主庫,避免寫入單點
(2)數據水平切分,保證各主庫生成的ID不重複
如上圖所述,由1個寫庫變成3個寫庫,每一個寫庫設置不一樣的auto_increment初始值,以及相同的增加步長,以保證每一個數據庫生成的ID是不一樣的(上圖中庫0生成0,3,6,9…,庫1生成1,4,7,10,庫2生成2,5,8,11…)
改進後的架構保證了可用性,但缺點是:
(1)喪失了ID生成的「絕對遞增性」:先訪問庫0生成0,3,再訪問庫1生成1,可能致使在很是短的時間內,ID生成不是絕對遞增的(這個問題不大,咱們的目標是趨勢遞增,不是絕對遞增)
(2)數據庫的寫壓力依然很大,每次生成ID都要訪問數據庫
爲了解決上述兩個問題,引出了第二個常見的方案
【常見方法二:單點批量ID生成服務】
分佈式系統之因此難,很重要的緣由之一是「沒有一個全局時鐘,難以保證絕對的時序」,要想保證絕對的時序,仍是隻能使用單點服務,用本地時鐘保證「絕對時序」。數據庫寫壓力大,是由於每次生成ID都訪問了數據庫,可使用批量的方式下降數據庫寫壓力。
如上圖所述,數據庫使用雙master保證可用性,數據庫中只存儲當前ID的最大值,例如0。ID生成服務假設每次批量拉取6個ID,服務訪問數據庫,將當前ID的最大值修改成5,這樣應用訪問ID生成服務索要ID,ID生成服務不須要每次訪問數據庫,就能依次派發0,1,2,3,4,5這些ID了,當ID發完後,再將ID的最大值修改成11,就能再次派發6,7,8,9,10,11這些ID了,因而數據庫的壓力就下降到原來的1/6了。
優勢:
(1)保證了ID生成的絕對遞增有序
(2)大大的下降了數據庫的壓力,ID生成能夠作到每秒生成幾萬幾十萬個
缺點:
(1)服務仍然是單點
(2)若是服務掛了,服務重啓起來以後,繼續生成ID可能會不連續,中間出現空洞(服務內存是保存着0,1,2,3,4,5,數據庫中max-id是5,分配到3時,服務重啓了,下次會從6開始分配,4和5就成了空洞,不過這個問題也不大)
(3)雖然每秒能夠生成幾萬幾十萬個ID,但畢竟仍是有性能上限,沒法進行水平擴展
改進方法:
單點服務的經常使用高可用優化方案是「備用服務」,也叫「影子服務」,因此咱們能用如下方法優化上述缺點(1):
如上圖,對外提供的服務是主服務,有一個影子服務時刻處於備用狀態,當主服務掛了的時候影子服務頂上。這個切換的過程對調用方是透明的,能夠自動完成,經常使用的技術是vip+keepalived,具體就不在這裏展開。
【常見方法三:uuid】
上述方案來生成ID,雖然性能大增,但因爲是單點系統,總仍是存在性能上限的。同時,上述兩種方案,無論是數據庫仍是服務來生成ID,業務方Application都須要進行一次遠程調用,比較耗時。有沒有一種本地生成ID的方法,即高性能,又時延低呢?
uuid是一種常見的方案:string ID =GenUUID();
優勢:
(1)本地生成ID,不須要進行遠程調用,時延低
(2)擴展性好,基本能夠認爲沒有性能上限
缺點:
(1)沒法保證趨勢遞增
(2)uuid過長,每每用字符串表示,做爲主鍵創建索引查詢效率低,常見優化方案爲「轉化爲兩個uint64整數存儲」或者「折半存儲」(折半後不能保證惟一性)
【常見方法四:取當前毫秒數】
uuid是一個本地算法,生成性能高,但沒法保證趨勢遞增,且做爲字符串ID檢索效率低,有沒有一種能保證遞增的本地算法呢?
取當前毫秒數是一種常見方案:uint64 ID = GenTimeMS();
優勢:
(1)本地生成ID,不須要進行遠程調用,時延低
(2)生成的ID趨勢遞增
(3)生成的ID是整數,創建索引後查詢效率高
缺點:
(1)若是併發量超過1000,會生成重複的ID
我去,這個缺點要了命了,不能保證ID的惟一性。固然,使用微秒能夠下降衝突機率,但每秒最多隻能生成1000000個ID,再多的話就必定會衝突了,因此使用微秒並不從根本上解決問題。
【常見方法五:類snowflake算法】
snowflake是twitter開源的分佈式ID生成算法,其核心思想是:一個long型的ID,使用其中41bit做爲毫秒數,10bit做爲機器編號,12bit做爲毫秒內序列號。這個算法單機每秒內理論上最多能夠生成1000*(2^12),也就是400W的ID,徹底能知足業務的需求。
借鑑snowflake的思想,結合各公司的業務邏輯和併發量,能夠實現本身的分佈式ID生成算法。
舉例,假設某公司ID生成器服務的需求以下:
(1)單機高峯併發量小於1W,預計將來5年單機高峯併發量小於10W
(2)有2個機房,預計將來5年機房數量小於4個
(3)每一個機房機器數小於100臺
(4)目前有5個業務線有ID生成需求,預計將來業務線數量小於10個
(5)…
分析過程以下:
(1)高位取從2016年1月1日到如今的毫秒數(假設系統ID生成器服務在這個時間以後上線),假設系統至少運行10年,那至少須要10年*365天*24小時*3600秒*1000毫秒=320*10^9,差很少預留39bit給毫秒數
(2)每秒的單機高峯併發量小於10W,即平均每毫秒的單機高峯併發量小於100,差很少預留7bit給每毫秒內序列號
(3)5年內機房數小於4個,預留2bit給機房標識
(4)每一個機房小於100臺機器,預留7bit給每一個機房內的服務器標識
(5)業務線小於10個,預留4bit給業務線標識
這樣設計的64bit標識,能夠保證:
(1)每一個業務線、每一個機房、每一個機器生成的ID都是不一樣的
(2)同一個機器,每一個毫秒內生成的ID都是不一樣的
(3)同一個機器,同一個毫秒內,以序列號區區分保證生成的ID是不一樣的
(4)將毫秒數放在最高位,保證生成的ID是趨勢遞增的
缺點:
(1)因爲「沒有一個全局時鐘」,每臺服務器分配的ID是絕對遞增的,但從全局看,生成的ID只是趨勢遞增的(有些服務器的時間早,有些服務器的時間晚)
最後一個容易忽略的問題:
生成的ID,例如message-id/ order-id/ tiezi-id,在數據量大時每每須要分庫分表,這些ID常常做爲取模分庫分表的依據,爲了分庫分表後數據均勻,ID生成每每有「取模隨機性」的需求,因此咱們一般把每秒內的序列號放在ID的最末位,保證生成的ID是隨機的。
又若是,咱們在跨毫秒時,序列號老是歸0,會使得序列號爲0的ID比較多,致使生成的ID取模後不均勻。解決方法是,序列號不是每次都歸0,而是歸一個0到9的隨機數,這個地方。
1、靜態頁面
靜態頁面,是指互聯網架構中,幾乎不變的頁面(或者變化頻率很低),例如:
首頁等html頁面
js/css等樣式文件
jpg/apk等資源文件
靜態頁面,有與之匹配的技術架構來加速,例如:
CDN
nginx
squid/varnish
2、動態頁面
動態頁面,是指互聯網架構中,不一樣用戶不一樣場景訪問,都不同的頁面,例如:
百度搜索結果頁
淘寶商品列表頁
速運我的訂單中心頁
這些頁面,不一樣用戶,不一樣場景訪問,大都會動態生成不一樣的頁面。
動態頁面,有與之匹配的技術架構,例如:
分層架構
服務化架構
數據庫,緩存架構
3、互聯網動靜分離架構
動靜分離是指,靜態頁面與動態頁面分開不一樣系統訪問的架構設計方法。
通常來講:
靜態頁面訪問路徑短,訪問速度快,幾毫秒
動態頁面訪問路徑長,訪問速度相對較慢(數據庫的訪問,網絡傳輸,業務邏輯計算),幾十毫秒甚至幾百毫秒,對架構擴展性的要求更高
靜態頁面與動態頁面以不一樣域名區分
4、頁面靜態化
既然靜態頁面訪問快,動態頁面生成慢,有沒有可能,將本來須要動態生成的站點提早生成好,使用靜態頁面加速技術來訪問呢?
這就是互聯網架構中的「頁面靜態化」優化技術。
舉例,以下圖,58同城的帖子詳情頁,本來是須要動態生成的:
瀏覽器發起http請求,訪問/detail/12348888x.shtml 詳情頁
web-server層從RESTful接口中,解析出帖子id是12348888
service層經過DAO層拼裝SQL語句,訪問數據庫
最終獲取數據,拼裝html返回瀏覽器
而「頁面靜態化」是指,將帖子ID爲12348888的帖子12348888x.shtml提早生成好,由靜態頁面相關加速技術來加速:
這樣的話,將極大提高訪問速度,減小訪問時間,提升用戶體驗。
5、頁面靜態化的適用場景
頁面靜態化優化後速度會加快,那能不能全部的場景都使用這個優化呢?哪些業務場景適合使用這個架構優化方案呢?
一切脫離業務的架構設計都是耍流氓,頁面靜態化,適用於:總數據量不大,生成靜態頁面數量很少的業務。例如:
58速運的城市頁只有幾百個,就能夠用這個優化,只需提早生成幾百個城市的「靜態化頁面」便可
一些二手車業務,只有幾萬量二手車庫存,也能夠提早生成這幾萬量二手車的靜態頁面
像58同城這樣的信息模式業務,有幾十億的帖子量,就不太適合於靜態化(碎片文件多,反而訪問慢)
6、總結
「頁面靜態化」是一種將本來須要動態生成的站點提早生成靜態站點的優化技術。
總數據量不大,生成靜態頁面數量很少的業務,很是適合於「頁面靜態化」優化。
RD:單庫數據量太大,數據庫扛不住了,我要申請一個數據庫從庫,讀寫分離。
DBA:數據量多少?
RD:5000w左右。
DBA:讀寫吞吐量呢?
RD:讀QPS約200,寫QPS約30左右。
上週在公司聽到兩個技術同窗討論,感受對讀寫分離解決什麼問題沒有弄清楚,有些奔潰。
另,對於互聯網某些業務場景,並非很喜歡數據庫讀寫分離架構,一些淺見見文末。
1、讀寫分離
什麼是數據庫讀寫分離?
答:一主多從,讀寫分離,主動同步,是一種常見的數據庫架構,通常來講:
主庫,提供數據庫寫服務
從庫,提供數據庫讀服務
主從之間,經過某種機制同步數據,例如mysql的binlog
一個組從同步集羣一般稱爲一個「分組」。
分組架構究竟解決什麼問題?
答:大部分互聯網業務讀多寫少,數據庫的讀每每最早成爲性能瓶頸,若是但願:
線性提高數據庫讀性能
經過消除讀寫鎖衝突提高數據庫寫性能
此時可使用分組架構。
一句話,分組主要解決「數據庫讀性能瓶頸」問題,在數據庫扛不住讀的時候,一般讀寫分離,經過增長從庫線性提高系統讀性能。
2、水平切分
什麼是數據庫水平切分?
答:水平切分,也是一種常見的數據庫架構,通常來講:
每一個數據庫之間沒有數據重合,沒有相似binlog同步的關聯
全部數據並集,組成所有數據
會用算法,來完成數據分割,例如「取模」
一個水平切分集羣中的每個數據庫,一般稱爲一個「分片」。
水平切分架構究竟解決什麼問題?
答:大部分互聯網業務數據量很大,單庫容量容易成爲瓶頸,若是但願:
線性下降單庫數據容量
線性提高數據庫寫性能
此時可使用水平切分架構。
一句話總結,水平切分主要解決「數據庫數據量大」問題,在數據庫容量扛不住的時候,一般水平切分。
3、爲何不喜歡讀寫分離
對於互聯網大數據量,高併發量,高可用要求高,一致性要求高,前端面向用戶的業務場景,若是數據庫讀寫分離:
數據庫鏈接池須要區分:讀鏈接池,寫鏈接池
若是要保證讀高可用,讀鏈接池要實現故障自動轉移
有潛在的主庫從庫一致性問題
若是面臨的是「讀性能瓶頸」問題,增長緩存可能來得更直接,更容易一點
關於成本,從庫的成本比緩存高很多
對於雲上的架構,以阿里云爲例,主庫提供高可用服務,從庫不提供高可用服務
因此,上述業務場景下,樓主建議使用緩存架構來增強系統讀性能,替代數據庫主從分離架構。
固然,使用緩存架構的潛在問題:若是緩存掛了,流量所有壓到數據庫上,數據庫會雪崩。不過幸虧,雲上的緩存通常都提供高可用的服務。
4、總結
讀寫分離,解決「數據庫讀性能瓶頸」問題
水平切分,解決「數據庫數據量大」問題
對於互聯網大數據量,高併發量,高可用要求高,一致性要求高,前端面向用戶的業務場景,微服務緩存架構,可能比數據庫讀寫分離架構更合適