日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢(xún)客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

一、實(shí)現(xiàn)高性能數(shù)據(jù)庫(kù)集群

一般我們業(yè)務(wù)在讀多寫(xiě)少的場(chǎng)景下,遇到的第一個(gè)瓶頸就是數(shù)據(jù)庫(kù)這塊,大量的讀請(qǐng)求會(huì)來(lái)到數(shù)據(jù)庫(kù),這樣如果你初期部署的一個(gè)數(shù)據(jù)庫(kù)就會(huì)造成IO大量增加,使得請(qǐng)求變慢,甚至?xí)ㄋ勒麄€(gè)數(shù)據(jù)庫(kù),到了這個(gè)階段,我們一般會(huì)將讀請(qǐng)求和寫(xiě)請(qǐng)求進(jìn)行分開(kāi)數(shù)據(jù)處理,即采用主從讀寫(xiě)分離的方式。

注:這里說(shuō)的是主從并不是主備,主從中的從服務(wù)器是要承擔(dān)業(yè)務(wù)的,而主備中備份機(jī)器一般只作為備份存在。

我們采用主從讀寫(xiě)分離的方式,目的是為了將更多的讀請(qǐng)求進(jìn)行分發(fā)來(lái)緩解我們的大量讀請(qǐng)求。

讀寫(xiě)分離架構(gòu)原理

正如上面所說(shuō),讀寫(xiě)分離是為了將請(qǐng)求流量分散到不同的數(shù)據(jù)庫(kù)節(jié)點(diǎn)上,將寫(xiě)入數(shù)據(jù)的請(qǐng)求分發(fā)到主數(shù)據(jù)庫(kù),讀取數(shù)據(jù)的請(qǐng)求分發(fā)到從數(shù)據(jù)庫(kù),從數(shù)據(jù)可以有多臺(tái),即一主多從。如下圖:

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

從上圖可看出,有個(gè)關(guān)鍵技術(shù)就是主從復(fù)制,每次寫(xiě)入數(shù)據(jù)的時(shí)候,需要將主服務(wù)器數(shù)據(jù)復(fù)制到從服務(wù)器中,用來(lái)確保數(shù)據(jù)一致性。下面我們來(lái)單獨(dú)看看主從是怎么復(fù)制的,以我們互聯(lián)網(wǎng)中最熟悉的MySQL為例。

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

  1. 從服務(wù)器連接上主服務(wù)器,啟動(dòng)復(fù)制的時(shí)候,則會(huì)自身創(chuàng)建一個(gè)IO線程去像主數(shù)據(jù)庫(kù)服務(wù)器拉取binlog的更新信息。
  2. 把拉過(guò)來(lái)的binlog信息寫(xiě)到自己服務(wù)器的一個(gè)relay log日志文件中。
  3. 從數(shù)據(jù)庫(kù)服務(wù)器創(chuàng)建一個(gè)SQL線程,是為了將relay log的所有日志信息,進(jìn)行sql回寫(xiě)到自己的數(shù)據(jù)庫(kù)中,這樣就和主庫(kù)的數(shù)據(jù)一模一樣了。
  4. 當(dāng)主數(shù)據(jù)庫(kù)有數(shù)據(jù)更新的時(shí)候,比如新插入了一條或者update了一條數(shù)據(jù),這時(shí)候主庫(kù)會(huì)將這些數(shù)據(jù)更新到binlog二進(jìn)制文件中,同時(shí),主庫(kù)會(huì)創(chuàng)建一個(gè)binlog dump線程,這個(gè)線程將更新了的binlog信息發(fā)送到從庫(kù)的IO線程,需要注意的是,這個(gè)過(guò)程是異步的,如果等著從庫(kù)接受完成,是不是特別慢,且影響性能。

這樣的“一主多從”的主從復(fù)制方案做好之后,現(xiàn)在咱們就不怕當(dāng)前這些大量的讀請(qǐng)求了,因?yàn)槲覀儼堰@些大流量讀請(qǐng)求都分發(fā)到這些從數(shù)據(jù)庫(kù)中了,寫(xiě)入數(shù)據(jù)的請(qǐng)求依然還是寫(xiě)到主數(shù)據(jù),一點(diǎn)不影響我們讀的業(yè)務(wù),互不影響的。同時(shí),從數(shù)據(jù)庫(kù)還可以作為備份數(shù)據(jù)庫(kù)來(lái)使用,萬(wàn)一主庫(kù)突然故障了,它可以頂上去防止數(shù)據(jù)丟失。

但是,我們不能一味的加從數(shù)據(jù)庫(kù),加個(gè)十七八個(gè)的,這樣做是無(wú)腦的操作啊,你想想看,你加一堆的的從數(shù)據(jù)庫(kù)連接到數(shù)據(jù)庫(kù),復(fù)制他的數(shù)據(jù),太多的IO線程會(huì)造成主數(shù)據(jù)不堪重負(fù)的,就會(huì)造成你寫(xiě)入數(shù)據(jù)慢,還會(huì)卡死,這就悲劇了。所以,不能這么搞啊,一般生產(chǎn)環(huán)境一個(gè)主數(shù)據(jù)庫(kù)掛三個(gè)從數(shù)據(jù)就行了,最多不能超過(guò)5個(gè)以上,要是還是不滿足肯定就會(huì)有其他方案了啊,多級(jí)緩存方案啊,是不是,后面會(huì)講的。

主從延時(shí)

上面說(shuō)了主從讀寫(xiě)分離的那么多好處, 主從同步是有延遲的,當(dāng)然,這個(gè)延時(shí)一般都在ms級(jí)別,但是如果到了秒級(jí)別,可能就會(huì)對(duì)有些業(yè)務(wù)造成影響,看我們能否接受。比如,我們?cè)谥Ц断到y(tǒng)創(chuàng)建支付單后,風(fēng)控系統(tǒng)會(huì)進(jìn)入查詢(xún)作出相應(yīng)的風(fēng)控操作,如果查不到就會(huì)可能終止本次交易了。

主從延遲優(yōu)化

  1. 我們可以在這些立馬需要查的業(yè)務(wù),讓它直接查主數(shù)據(jù)庫(kù),但是這種方案不推薦,因?yàn)榱看笈聲?huì)拖垮主數(shù)據(jù)
  2. 當(dāng)從數(shù)據(jù)庫(kù)讀取不到,我們回去再讀主數(shù)據(jù),這樣就能讀到數(shù)據(jù)了。但是,這種也是有風(fēng)險(xiǎn)的,量大也會(huì)拖垮主庫(kù)。
  3. 像我前面文章提到過(guò),分重要性業(yè)務(wù)和非重要業(yè)務(wù),將很核心的幾個(gè)業(yè)務(wù)查主數(shù)據(jù),其他非核心,讀寫(xiě)分離。
  4. 使用緩存,將新增的數(shù)據(jù)同時(shí)添加一份緩存,然后查緩存數(shù)據(jù),這種建議新增的數(shù)據(jù)使用緩存較好。
  5. 使用消息隊(duì)列中間件進(jìn)行消息冗余,將新的主數(shù)據(jù)內(nèi)容,通過(guò)消息中間件MQ冗余一份當(dāng)前數(shù)據(jù),然后發(fā)到需要查詢(xún)的系統(tǒng)。

在消息體不大,推薦使用第 種優(yōu)化方案,需要消息中間件;其次考慮緩存, redis,Memcache 都可以的,因?yàn)楦碌牟僮鳎枰戮彺妫残枰鉀Q一致性問(wèn)題,所以,新增的數(shù)據(jù),就首選緩存優(yōu)化方案。最后,推薦重要性非重要性隔離方案。最好不要使用都查詢(xún)主庫(kù)的操作。

如何優(yōu)雅使用讀寫(xiě)分離

我們現(xiàn)在使用了數(shù)據(jù)庫(kù)讀寫(xiě)分離的機(jī)制,但是我們代碼該怎么去友好的去訪問(wèn)數(shù)據(jù)庫(kù)呢?以前我們一個(gè)數(shù)據(jù)源配置就可以了,現(xiàn)在有好多個(gè)數(shù)據(jù)源了,代碼里既要區(qū)分哪個(gè)地方使用寫(xiě)數(shù)據(jù)庫(kù)的數(shù)據(jù)源,哪個(gè)地方需要使用讀數(shù)據(jù)的數(shù)據(jù)源。當(dāng)然,肯定是有辦法的,業(yè)界大佬們都早于我們遇到了這些問(wèn)題,下面我會(huì)分享出兩種方案:

1,程序代碼嵌入

代碼嵌入,是指通過(guò)在我們的代碼中開(kāi)發(fā)出數(shù)據(jù)庫(kù)訪問(wèn)中間層,由這個(gè)數(shù)據(jù)庫(kù)訪問(wèn)中間層去訪問(wèn)不同的數(shù)據(jù)源,以實(shí)現(xiàn)讀寫(xiě)分離和數(shù)據(jù)源的管理。現(xiàn)在推薦使用淘寶開(kāi)源的TDDL(Taobao Distributed Data Layer),使用方便,直接集成到我們代碼就可以了,它自己管理讀寫(xiě)分離和數(shù)據(jù)庫(kù)配置。

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

特點(diǎn)是:

  • 實(shí)現(xiàn)簡(jiǎn)單,可以根據(jù)自己業(yè)務(wù)進(jìn)行定制化開(kāi)發(fā)
  • 語(yǔ)言不同,就得開(kāi)發(fā)不同語(yǔ)言版本的數(shù)據(jù)庫(kù)訪問(wèn)層

2,部署獨(dú)立代理層

部署代理層是指,在我們的業(yè)務(wù)服務(wù)器和數(shù)據(jù)庫(kù)直接引入數(shù)據(jù)訪問(wèn)代理層,并不用自己寫(xiě)代碼。現(xiàn)在為代表的開(kāi)源中間件有阿里的MyCat、360的Atlas、美團(tuán)的DBProxy等。這些都是使用標(biāo)準(zhǔn)的MySql通信協(xié)議。

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

特點(diǎn):

  • 不用自己編寫(xiě)多余代碼,使用方便。
  • 支持對(duì)語(yǔ)言
  • sql語(yǔ)句會(huì)跨兩層網(wǎng)絡(luò),性能稍微低一點(diǎn)。

建議,在自己公司沒(méi)有比較成熟的中間件團(tuán)隊(duì)的話就用程序代碼封裝的方案,雖然寫(xiě)代碼麻煩點(diǎn),但是自己可以把控;要是公司有成熟中間件團(tuán)隊(duì),就盡量考慮代理層部署的方案,因?yàn)樾枰袀€(gè)團(tuán)隊(duì)要研究和長(zhǎng)期維護(hù)這個(gè)代理層,才能確保業(yè)務(wù)正常發(fā)展,現(xiàn)在我們公司大部分都用的是代理層方案,是有個(gè)專(zhuān)門(mén)團(tuán)隊(duì)來(lái)維護(hù)。

總結(jié),今天講到了當(dāng)我們讀多寫(xiě)少的場(chǎng)景下,采取數(shù)據(jù)庫(kù)讀寫(xiě)分離的方式來(lái)分?jǐn)偞罅髁俊?/p>

二、大量并發(fā)寫(xiě)入所帶來(lái)的性能問(wèn)題優(yōu)化

隨著運(yùn)營(yíng)部門(mén)的同事在不停的做出各種促銷(xiāo)或者拉新活動(dòng),我們注冊(cè)用戶(hù)越來(lái)越多,同時(shí)訂單量以及用戶(hù)行為數(shù)據(jù)等持續(xù)的增加,導(dǎo)致我們的系統(tǒng)現(xiàn)在出現(xiàn)了下面這些問(wèn)題。

  1. 訂單量劇增,單表數(shù)據(jù)量已經(jīng)達(dá)到了千萬(wàn)的級(jí)別了,這個(gè)時(shí)候的索引查詢(xún)已經(jīng)很慢了,所以現(xiàn)在我們的類(lèi)似這些大數(shù)據(jù)表的查詢(xún)性能很差
  2. 數(shù)據(jù)量持續(xù)增加,現(xiàn)在我們的磁盤(pán)大部分空間都被使用,導(dǎo)致數(shù)據(jù)庫(kù)的復(fù)制備份操作很緩慢,所以,目前數(shù)據(jù)庫(kù)系統(tǒng)已不能滿足現(xiàn)在的數(shù)據(jù)量級(jí)。
  3. 我們整個(gè)系統(tǒng)的所有業(yè)務(wù),訂單,用戶(hù),優(yōu)惠券、政策等等都在一個(gè)數(shù)據(jù)庫(kù)系統(tǒng),耦合性太高,數(shù)據(jù)不隔離。
  4. 像每天大量的用戶(hù)關(guān)注、行為數(shù)據(jù)以及訂單數(shù)據(jù)的寫(xiě)入,導(dǎo)致系統(tǒng)的寫(xiě)入性能持續(xù)下降。

以上這些問(wèn)題均是由于大并發(fā)的寫(xiě)入操作導(dǎo)致目前的系統(tǒng)讀寫(xiě)性能下降,并且系統(tǒng)可用性也在降低,這些都是現(xiàn)在階段需要解決的,需要將這些數(shù)據(jù)進(jìn)行分片,也就是分散開(kāi),欄均攤我們整個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù)壓力,同時(shí)也是解決單機(jī)數(shù)據(jù)容量以及性能的解決方案,我們業(yè)界現(xiàn)在比較流行的方法就是“分庫(kù)分表”的方案。

提到分庫(kù)分表,大家應(yīng)該都不陌生,但是怎么在自己項(xiàng)目中合理的使用分庫(kù)分表卻不是一件容易的事情,從今天開(kāi)始,我們從分庫(kù)分表的策略到怎么部署上線以及怎么避坑等內(nèi)容開(kāi)始切入,幫助大家更好的掌握并使用分庫(kù)分表的技術(shù)

怎么做數(shù)據(jù)庫(kù)垂直拆分

垂直拆分是分庫(kù)分表方案中最為常見(jiàn)的一種方式,大的核心思想就是,將一堆的統(tǒng)一數(shù)據(jù)放到其他節(jié)點(diǎn)數(shù)據(jù)庫(kù)中或者表中進(jìn)行存儲(chǔ),不同于我們前面主從復(fù)制,主從復(fù)制是所有節(jié)點(diǎn)數(shù)據(jù)都是一樣,而垂直拆分后,是每個(gè)節(jié)點(diǎn)存儲(chǔ)一部分?jǐn)?shù)據(jù),就像Hadoop里面的一個(gè)個(gè)的Block一樣。

垂直拆分好處:

  • 有效解決了單個(gè)數(shù)據(jù)庫(kù)或者表的數(shù)據(jù)存儲(chǔ)瓶頸。
  • 有效提高數(shù)據(jù)查詢(xún)性能。
  • 有效提高并發(fā)寫(xiě)入性能,因?yàn)槭强梢詫?xiě)到多個(gè)庫(kù)里面了。

我們公司的有個(gè)項(xiàng)目,你就理解我是用戶(hù)關(guān)注類(lèi)的就行,這些數(shù)據(jù)已經(jīng)到了億級(jí)別的了,之前是沒(méi)分庫(kù)分表的,到了億級(jí)別之后,不論是查詢(xún)還是寫(xiě)入或者是報(bào)表之類(lèi)的,反正就是各種痛苦,后來(lái)就是進(jìn)行分庫(kù)分表,分到多個(gè)庫(kù),才得以解決。

垂直拆分策略

我們現(xiàn)在知道了我們急需分庫(kù)分表的操作了,但是,我們?cè)撏ㄟ^(guò)什么策略去將我們的數(shù)據(jù)庫(kù)進(jìn)行垂直拆分呢?我這里建議是,我們最好按照我們的系統(tǒng)業(yè)務(wù)來(lái)進(jìn)行垂直拆分,垂直拆分就是將數(shù)據(jù)庫(kù)豎著拆分,根據(jù)業(yè)務(wù)的不同將原有數(shù)據(jù)庫(kù)中的那些表分到不同的數(shù)據(jù)庫(kù)節(jié)點(diǎn)中。

不同的數(shù)據(jù)庫(kù)對(duì)應(yīng)著不同的業(yè)務(wù),比如,我們將用戶(hù)相關(guān)的表放在了用戶(hù)數(shù)據(jù)庫(kù)節(jié)點(diǎn)里,訂單相關(guān)的表放在了訂單數(shù)據(jù)庫(kù)節(jié)點(diǎn)上,關(guān)注相關(guān)的表放在了關(guān)注數(shù)據(jù)庫(kù)節(jié)點(diǎn)里。這樣還有個(gè)好處就是,我們的關(guān)注數(shù)據(jù)量龐大到了幾億的量級(jí)如果影響到了數(shù)據(jù)的操作,但是并不影響用戶(hù)的登錄和瀏覽、搜索下單操作。起到了很好的數(shù)據(jù)隔離的作用。

案例展示

以前,我們用戶(hù)表、關(guān)注表、訂單表都在同一個(gè)庫(kù)里面,也就是在我們的主庫(kù)中,后來(lái)經(jīng)過(guò)拆分后,它們分別被拆到用戶(hù)庫(kù)、關(guān)注庫(kù)、訂單庫(kù)等。

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

垂直拆分這種方案,其實(shí)在我們中等規(guī)模的互聯(lián)網(wǎng)公司里都會(huì)首先使用到,但是,隨著數(shù)據(jù)的增加這種單庫(kù)里面的表還是會(huì)面臨瓶頸的,看上面我講的我們關(guān)注表數(shù)據(jù),雖然拆到了關(guān)注庫(kù)里面,但是關(guān)注表數(shù)據(jù)都已經(jīng)好幾億了,仍是會(huì)影響我們這塊業(yè)務(wù)的。所以說(shuō),垂直拆分只能暫緩我們的問(wèn)題,但是,像那種單表數(shù)據(jù)驟增的情況還是需要采取另一種方法的,那就是我們下面要說(shuō)的水平拆分。

怎么做數(shù)據(jù)庫(kù)水平拆分

水平拆分的核心思想是,將單一數(shù)據(jù)表數(shù)據(jù)按照我們約定的某種規(guī)則進(jìn)行拆分到多個(gè)數(shù)據(jù)庫(kù)和數(shù)據(jù)表中,我們的關(guān)注點(diǎn)是在表數(shù)據(jù)本身上。

有哪些常用拆分規(guī)則

1,按照表中某一字段取哈希值進(jìn)行拆分,例如我們的用戶(hù)表,如果將其拆分為16個(gè)庫(kù),每個(gè)庫(kù)64張表,那么,我們就將UID哈希,為什么哈希大家知道吧,前面文章分析了hashmap,應(yīng)該都懂吧。然后將哈希值對(duì)16取余,得到哪一個(gè)數(shù)據(jù)庫(kù),然后對(duì)64取余就知道哪個(gè)表。這種規(guī)則比較適用于這種實(shí)體類(lèi)的表。

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

2,按照某一個(gè)表字段的區(qū)間做拆分,這里最常使用就是日期字段了,比如我們關(guān)注表的創(chuàng)建時(shí)間,比如我們要查某個(gè)月的關(guān)注數(shù)據(jù),就可以將月份數(shù)據(jù)放進(jìn)對(duì)應(yīng)月份表中,這樣我們就可以根據(jù)創(chuàng)建時(shí)間來(lái)定位到我們數(shù)據(jù)存儲(chǔ)在哪張表里面,然后在根據(jù)我們的查詢(xún)條件進(jìn)行相應(yīng)的查詢(xún)。

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

數(shù)據(jù)庫(kù)進(jìn)行分庫(kù)分表后,我們代碼怎么去訪問(wèn),也會(huì)帶來(lái)一定的麻煩,之前只用訪問(wèn)一個(gè)庫(kù)就行了,現(xiàn)在數(shù)據(jù)都被分到其他庫(kù)里面了,這個(gè)和我們前面的讀寫(xiě)分離差不多,可以去看看()

現(xiàn)在數(shù)據(jù)庫(kù)的分庫(kù)分表解決了我們數(shù)據(jù)庫(kù)瓶頸、并發(fā)寫(xiě)入和讀取等問(wèn)題,也解決了我們擴(kuò)展和數(shù)據(jù)隔離的問(wèn)題,但是引入了分庫(kù)分表,也會(huì)給我們帶來(lái)一些問(wèn)題:

怎么解決分庫(kù)分表帶來(lái)的問(wèn)題

1,分區(qū)鍵

分區(qū)鍵就是我們用來(lái)進(jìn)行分庫(kù)分表的字段,我們每次查詢(xún)的時(shí)候都必須得帶上這個(gè)字段,才能找到數(shù)據(jù)所在的庫(kù)和表,我們將上面用戶(hù)數(shù)據(jù)按照uid進(jìn)行分庫(kù)分表的,那如果現(xiàn)在我想按照昵稱(chēng)來(lái)查詢(xún)?cè)趺崔k呢?

  • 這里我們一般建議,另外建立一張UID和昵稱(chēng)的映射表。
  • 然后通過(guò)昵稱(chēng)查詢(xún)出UID
  • 在通過(guò)UID就可以進(jìn)行定位到庫(kù)和表了

2,多表JOIN

我們現(xiàn)在的單表數(shù)據(jù)都被分到多庫(kù)多表中了,然后有些程序員之前寫(xiě)的那些連表join 操作怎么辦,跨庫(kù)了,就不能使用JOIN了。所以這塊我們需要將他們放到我們業(yè)務(wù)代碼中進(jìn)行處理了,其實(shí)代碼中處理我們會(huì)更清晰一些

3,統(tǒng)計(jì)類(lèi)

和上面JOIN類(lèi)似,類(lèi)似統(tǒng)計(jì)的count()就不能使用了,然后這塊我們建議是,通過(guò)另外建一張表活著放到redis緩存里面,最后再合并就行了,也很簡(jiǎn)單。

最后建議,我們?cè)谖覀兊臉I(yè)務(wù)中不要一開(kāi)始就去分庫(kù)分表,在沒(méi)必要的情況下不要去分庫(kù)分表;如果真的要分庫(kù)分表,在公司資源充足下,建議一次性分到位,會(huì)給你很爽的感覺(jué),比如分16個(gè)庫(kù)64張表,資源緊缺的話,我們就根據(jù)業(yè)務(wù)來(lái)分,后續(xù)會(huì)將一些更過(guò)的方案。

總結(jié),今天我們針對(duì)大并發(fā)的寫(xiě)入造成的我們數(shù)據(jù)庫(kù)的瓶頸以及性能低下問(wèn)題,我們就引入了分庫(kù)分表的方案,主要分為數(shù)據(jù)庫(kù)垂直拆分和水平拆分,也提到了拆分后給我們帶來(lái)了哪些挑戰(zhàn)并且給出相應(yīng)的解決方案。

三、分庫(kù)分表后,保證ID全局唯一

上兩篇講到了我們的系統(tǒng)在面臨大并發(fā)讀取的時(shí)候,采用了讀寫(xiě)分離主從復(fù)制(數(shù)據(jù)庫(kù)讀寫(xiě)分離方案,實(shí)現(xiàn)高性能數(shù)據(jù)庫(kù)集群)的方案去應(yīng)對(duì),后來(lái)又面臨了大并發(fā)寫(xiě)入的時(shí)候,系統(tǒng)數(shù)據(jù)庫(kù)采用了分庫(kù)分表的方案(數(shù)據(jù)庫(kù)分庫(kù)分表方案,優(yōu)化大量并發(fā)寫(xiě)入所帶來(lái)的性能問(wèn)題),通過(guò)垂直拆分以及水平拆分的方式,將數(shù)據(jù)分到多個(gè)庫(kù)和多個(gè)表中去應(yīng)對(duì)的,即現(xiàn)在是這樣的一套分布式存儲(chǔ)結(jié)構(gòu)

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

數(shù)據(jù)庫(kù)分庫(kù)分表那篇也講到了,使用了分庫(kù)分表勢(shì)必會(huì)帶來(lái)和我們之前使用不大相同的問(wèn)題。今天,我將其中一個(gè)和我們開(kāi)發(fā)息息相關(guān)的問(wèn)題提出來(lái)進(jìn)行講解,也就是我們開(kāi)發(fā)中所使用的的主鍵的問(wèn)題。我們知道,以前我們單庫(kù)的時(shí)候,主鍵唯一ID是自增的,現(xiàn)在好了,我們的數(shù)據(jù)被分到多個(gè)庫(kù)的多個(gè)表里面了,如果我們還是使用之前的主鍵自增策略,那么這樣就會(huì)出現(xiàn)兩個(gè)數(shù)據(jù)插入到了兩個(gè)不同的表會(huì)出現(xiàn)相同的ID值,這時(shí)我們?cè)撛趺慈ナ褂媚兀?/p>

對(duì)于什么是主鍵,主鍵該怎么選,今天不做講解,我相信大家可能比我還精通,我們今天主要是講唯一主鍵ID在分布式存儲(chǔ)系統(tǒng)下怎么生成,保證ID的唯一性且符合我們業(yè)務(wù)需要,才是我們開(kāi)發(fā)人員最關(guān)心的實(shí)戰(zhàn)。

UUID

這個(gè)時(shí)候,你可能會(huì)說(shuō),自增用不了,那我就是用UUID嘛,這個(gè)UUID生成出來(lái)的就是唯一的。的確,在我以前在一個(gè)公司中的確接觸到是使用UUID來(lái)生成唯一主鍵ID的,而且性能還可以。但是,我想提一點(diǎn)的就是,當(dāng)這個(gè)ID和我們業(yè)務(wù)交集不相關(guān)的時(shí)候是可以使用UUID生成主鍵的。比如,一般我們業(yè)務(wù)是需要用來(lái)做查詢(xún)的,而且最好是單調(diào)遞增的,這樣我們的UUID就很不適合了。

主鍵ID單調(diào)遞增有什么好處呢?

1,就拿我們用戶(hù)關(guān)注航班這個(gè)模塊來(lái)說(shuō),我們查看某個(gè)航班關(guān)注用戶(hù)按照時(shí)間的先后進(jìn)行排序。因?yàn)楝F(xiàn)在的ID是時(shí)間上有序的,所以現(xiàn)在我們就可以按照ID來(lái)進(jìn)行排序了,同時(shí)這樣對(duì)于有些并不是要存儲(chǔ)時(shí)間的業(yè)務(wù)來(lái)說(shuō),會(huì)減少不少的存儲(chǔ)空間。

2,有序的ID可以提升數(shù)據(jù)寫(xiě)入的性能

我們知道主鍵其實(shí)在數(shù)據(jù)庫(kù)中就是一種索引,而索引在MySql數(shù)據(jù)庫(kù)的B+數(shù)據(jù)結(jié)構(gòu)中是順序存儲(chǔ)的,所以每次插入的時(shí)候就是遞增排序的,直接追加到后面就行。如果是無(wú)序的話,則每次插入數(shù)據(jù)之前還得查找它應(yīng)該所在的位置,這無(wú)疑就會(huì)增加數(shù)據(jù)的異動(dòng)等相關(guān)的開(kāi)銷(xiāo),如下圖:

數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

如上圖所示,如果我們生成的ID是有序的,那這個(gè) 50 就直接插在尾部就行了,如果是無(wú)序的話,突然生成了一個(gè) 26,我們還得先找到 26 需要存放的位置,然后還要對(duì)其后面數(shù)據(jù)進(jìn)行挪位置。

3,UUID不具備業(yè)務(wù)相關(guān)性

我們現(xiàn)在開(kāi)發(fā)的項(xiàng)目都是依據(jù)公司業(yè)務(wù)開(kāi)展的,而我們的唯一ID一般都是和業(yè)務(wù)有關(guān)系的,比如,有些訂單ID中帶上了時(shí)間的維度、機(jī)房的維度以及業(yè)務(wù)類(lèi)型等維度。也就是為了我方便進(jìn)行定位是那種業(yè)務(wù)的訂單,才會(huì)這么設(shè)計(jì)的,是不是。

而UUID是由32位的16進(jìn)制數(shù)字組成的字符串,不僅在存儲(chǔ)空間上造成浪費(fèi),更不具備我們業(yè)務(wù)相關(guān)性。那我們?cè)撛趺唇鉀Q呢?其實(shí)twitter提出來(lái)的Snowflake 算法就能很好滿足我們現(xiàn)在的要求,滿足了主鍵ID的全局唯一性、單調(diào)遞增性,也可以滿足我們的業(yè)務(wù)相關(guān)。所以,我們現(xiàn)在使用的唯一ID生成方式就是使用Snowflake算法,這個(gè)算法其實(shí)很簡(jiǎn)單。下面我們來(lái)對(duì)其進(jìn)行講解,并對(duì)其相應(yīng)改造使其能用到我們的開(kāi)發(fā)業(yè)務(wù)中來(lái)。

Snowflake 算法原理

Snowflake 是由 64 比特bit二進(jìn)制數(shù)字組成的,一共分為4大部分:

  • 1位默認(rèn)不使用
  • 41位時(shí)間戳
  • 10位機(jī)器ID
  • 12位序列號(hào)
數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

  1. 我們從上圖中可以看出snowflake算法的第二部分的41位時(shí)間戳,大概可以支撐2^41/1000/60/60/24/365 年,也就是大約有69年。我們?cè)O(shè)計(jì)一個(gè)系統(tǒng)用69年應(yīng)該是足夠了吧。
  2. 10位的機(jī)器ID我們可以怎么使用呢?我們可以劃分成大概2到3位IDC,也就是可以支撐4到8個(gè)IDC機(jī)房;然后劃分7到 8 位的機(jī)器ID,即可以支撐128~256臺(tái)機(jī)器。
  3. 12位的序號(hào),就代表每個(gè)節(jié)點(diǎn)每毫秒可以生成4096個(gè)ID序號(hào)。

如何改造

我們現(xiàn)在已經(jīng)知道了Snowflake 算法的核心原理,并且知道了其有64位的二進(jìn)制數(shù)據(jù),那我們就可以根據(jù)自己業(yè)務(wù)進(jìn)行改造以更好的來(lái)為我們業(yè)務(wù)服務(wù)。一般不同的公司對(duì)其進(jìn)行改造的方式都不盡相同,但是道理都是一樣的。我們可以這么做:

  1. 我們是減少序列號(hào)的位數(shù),增加機(jī)器ID的位數(shù),是為了用來(lái)支撐我們單IDC的更多機(jī)器。
  2. 將我們業(yè)務(wù)ID加入進(jìn)去用來(lái)區(qū)分我們不同的業(yè)務(wù)。比如,1位0 + 41位時(shí)間戳 + 6位IDC(64個(gè)IDC) + 6位業(yè)務(wù)信息(支撐64種業(yè)務(wù)) + 10位自增序列(每毫秒1024個(gè)ID)
數(shù)據(jù)庫(kù)讀寫(xiě)分離詳解

 

如此,我們就可以在單機(jī)房部署這么一個(gè)統(tǒng)一ID發(fā)號(hào)器,然后用Keeplive 保證高可用(對(duì)于高可用不熟悉的回去看看哈「高可用」你們服務(wù)器掛了怎么辦,我們是這樣做的)可以將不同的業(yè)務(wù)模塊ID加入進(jìn)去,這樣的好處是即使哪個(gè)業(yè)務(wù)出問(wèn)題了,我只看ID號(hào)我就分析出來(lái),比如,我看到現(xiàn)在ID號(hào)有我的訂單ID業(yè)務(wù),我就去看訂單模塊。

開(kāi)發(fā)如何使用

現(xiàn)在我們知道Snowflake 算法原理了,還知道了我們可以進(jìn)行改造了。那我們開(kāi)發(fā)人員該怎么去使用,來(lái)為我們業(yè)務(wù)生成統(tǒng)一的唯一ID呢?

1,直接嵌入到業(yè)務(wù)代碼

嵌入業(yè)務(wù)代碼的意思就是,這個(gè)snowflake算法就部署在和我們業(yè)務(wù)相同的服務(wù)器上,這樣我們代碼使用的時(shí)候,就不用了跨網(wǎng)絡(luò)調(diào)用,性能相對(duì)比較好。但是也是有缺點(diǎn)的,因?yàn)槲覀兊臉I(yè)務(wù)機(jī)器肯定是很多的,這就意味著我們發(fā)號(hào)器算法需要更多的機(jī)器ID位數(shù)。同時(shí),太多的業(yè)務(wù)服務(wù)器我們會(huì)很難保證業(yè)務(wù)機(jī)器id的唯一性,這里就需要引用zookeeper一致性組件來(lái)保證每次機(jī)器重啟都能能獲得唯一的機(jī)器ID。

2,獨(dú)立部署成發(fā)號(hào)器服務(wù)

也就是說(shuō),我們將其作為單獨(dú)的服務(wù)部署到單獨(dú)的機(jī)器上,已對(duì)外提供服務(wù)。這樣就是多了網(wǎng)絡(luò)的傳輸,不過(guò)影響不大,比如,我可以將其部署成一個(gè)主備的方式對(duì)外提供發(fā)號(hào)服務(wù),機(jī)器ID可以用作序列號(hào)使用,這樣也就是會(huì)有更多的自增序號(hào),有部分大廠就是以這樣單獨(dú)的服務(wù)提供出來(lái)的。

開(kāi)發(fā)中避坑大法

1,雖然snowflake很優(yōu)秀,但是它是基于系統(tǒng)時(shí)間的,萬(wàn)一我們系統(tǒng)的時(shí)間不準(zhǔn)怎么辦,就會(huì)造成我們的ID會(huì)重復(fù)。那我們的做法就是,要利用系統(tǒng)的對(duì)時(shí)功能,一旦發(fā)現(xiàn)時(shí)間不一致,就暫停發(fā)號(hào)器,等到時(shí)鐘準(zhǔn)了在啟用。

2,還有一個(gè)坑比較關(guān)鍵,也是常發(fā)生的,就是當(dāng)我們的QPS并發(fā)不高的時(shí)候,比如每毫秒只生成一個(gè)ID號(hào),這樣就是直接結(jié)果是,每次生成的ID末尾都是1,這樣我們分庫(kù)分表就會(huì)出現(xiàn)問(wèn)題呀對(duì)吧,因?yàn)槲覀冇眠@個(gè)ID去分庫(kù)分表呀,會(huì)造成數(shù)據(jù)不均勻,是吧,忘記了去復(fù)習(xí)哈(數(shù)據(jù)庫(kù)分庫(kù)分表方案,優(yōu)化大量并發(fā)寫(xiě)入所帶來(lái)的性能問(wèn)題)那我們?cè)趺唇鉀Q呢?

我們可以將時(shí)間戳記錄從毫秒記錄改為秒記錄,這樣我一秒可以發(fā)好多個(gè)號(hào)了

生成的序列號(hào)起始號(hào)隨機(jī)啟動(dòng),比如這一秒起始號(hào)是10,我下一秒隨機(jī)了變成了28,這樣就更加分散開(kāi)了。

總結(jié),今天我們針對(duì)分庫(kù)分表之后帶來(lái)的第一個(gè)直接影響我們開(kāi)發(fā)的問(wèn)題,就是主鍵ID唯一性的問(wèn)題,然后說(shuō)到了使用Snowflake算法去解決,并且對(duì)其原理和使用進(jìn)行了詳細(xì)的講解,同時(shí),還將其在使用中遇到的坑給講出來(lái)了,也對(duì)其進(jìn)行了填坑分析,讓大家直接避免遇到同樣的問(wèn)題。當(dāng)然生成唯一ID有多種,我們根據(jù)業(yè)務(wù)選擇合適我們自己的就好

分享到:
標(biāo)簽:數(shù)據(jù)庫(kù)
用戶(hù)無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定