精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

NoSQL數(shù)據(jù)庫(kù)的主主備份

數(shù)據(jù)庫(kù)
如果你想知道我和igorcoding是怎樣在Tarantool內(nèi)部建立一個(gè)系統(tǒng)的,請(qǐng)看正文。

Tarantool DBMS的高性能應(yīng)該很多人都聽說過,包括其豐富的工具套件和某些特定功能。比如,它擁有一個(gè)非常強(qiáng)大的on-disk存儲(chǔ)引擎Vinyl,并且知道怎樣處理JSON文檔。然而,大部分文章往往忽略了一個(gè)關(guān)鍵點(diǎn):通常,Tarantool僅僅被視為存儲(chǔ)器,而實(shí)際上其***特點(diǎn)是能夠在存儲(chǔ)器內(nèi)部寫代碼,從而高效處理數(shù)據(jù)。如果你想知道我和igorcoding是怎樣在Tarantool內(nèi)部建立一個(gè)系統(tǒng)的,請(qǐng)繼續(xù)往下看。

如果你用過Mail.Ru電子郵件服務(wù),你應(yīng)該知道它可以從其他賬號(hào)收集郵件。如果支持OAuth協(xié)議,那么在收集其他賬號(hào)的郵件時(shí),我們就不需要讓用戶提供第三方服務(wù)憑證了,而是用OAuth令牌來代替。此外,Mail.Ru Group有很多項(xiàng)目要求通過第三方服務(wù)授權(quán),并且需要用戶的OAuth令牌才能處理某些應(yīng)用。因此,我們決定建立一個(gè)存儲(chǔ)和更新令牌的服務(wù)。

我猜大家都知道OAuth令牌是什么樣的,閉上眼睛回憶一下,OAuth結(jié)構(gòu)由以下3-4個(gè)字段組成:

 

  1.  
  2. “token_type” : “bearer”,  
  3. “access_token” : “XXXXXX”,  
  4. “refresh_token” : “YYYYYY”,  
  5. “expires_in” : 3600  
  • 訪問令牌(access_token)——允許你執(zhí)行動(dòng)作、獲取用戶數(shù)據(jù)、下載用戶的好友列表等等;
  • 更新令牌(refresh_token)——讓你重新獲取新的access_token,不限次數(shù);
  • 過期時(shí)間(expires_in)——令牌到期時(shí)間戳或任何其他預(yù)定義時(shí)間,如果你的access_token到期了,你就不能繼續(xù)訪問所需的資源。

現(xiàn)在我們看一下服務(wù)的簡(jiǎn)單框架。設(shè)想有一些前端可以在我們的服務(wù)上寫入和讀出令牌,還有一個(gè)獨(dú)立的更新器,一旦令牌到期,就可以通過更新器從OAuth服務(wù)提供商獲取新的訪問令牌。

NoSQL數(shù)據(jù)庫(kù)的主主備份

如上圖所示,數(shù)據(jù)庫(kù)的結(jié)構(gòu)也十分簡(jiǎn)單,由兩個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)(主和從)組成,為了說明兩個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn)分別位于兩個(gè)數(shù)據(jù)中心,二者之間由一條垂直的虛線隔開,其中一個(gè)數(shù)據(jù)中心包含主數(shù)據(jù)庫(kù)節(jié)點(diǎn)及其前端和更新器,另一個(gè)數(shù)據(jù)中心包含從數(shù)據(jù)庫(kù)節(jié)點(diǎn)及其前端,以及訪問主數(shù)據(jù)庫(kù)節(jié)點(diǎn)的更新器。

面臨的困難

我們面臨的主要問題在于令牌的使用期(一個(gè)小時(shí))。詳細(xì)了解這個(gè)項(xiàng)目之后,也許有人會(huì)問“在一小時(shí)內(nèi)更新1000萬條記錄,這真的是高負(fù)載服務(wù)嗎?如果我們用一個(gè)數(shù)除一下,結(jié)果大約是3000rps”。然而,如果因?yàn)閿?shù)據(jù)庫(kù)維護(hù)或故障,甚至服務(wù)器故障(一切皆有可能)導(dǎo)致一部分記錄沒有得到更新,那事情將會(huì)變得比較麻煩。比如,如果我們的服務(wù)(主數(shù)據(jù)庫(kù))因?yàn)槟承┰虺掷m(xù)中斷15分鐘,就會(huì)導(dǎo)致25%的服務(wù)中斷(四分之一的令牌變成無效,不能再繼續(xù)使用);如果服務(wù)中斷30分鐘,將會(huì)有一半的數(shù)據(jù)不能得到更新;如果中斷1小時(shí),那么所有的令牌都將失效。假設(shè)數(shù)據(jù)庫(kù)癱瘓一個(gè)小時(shí),我們重啟系統(tǒng),然后整個(gè)1000萬條令牌都需要進(jìn)行快速更新。這算不算高負(fù)載服務(wù)呢?

一開始一切都還進(jìn)展地比較順利,但是兩年后,我們進(jìn)行了邏輯擴(kuò)展,增加了幾個(gè)指標(biāo),并且開始執(zhí)行一些輔助邏輯…….總之,Tarantool耗盡了CPU資源。盡管所有資源都是遞耗資源,但這樣的結(jié)果確實(shí)讓我們大吃一驚。

幸運(yùn)的是,系統(tǒng)管理員幫我們安裝了當(dāng)時(shí)庫(kù)存中內(nèi)存***的CPU,解決了我們隨后6個(gè)月的CPU需求。但這只是權(quán)宜之計(jì),我們必須想出一個(gè)解決辦法。當(dāng)時(shí),我們學(xué)習(xí)了一個(gè)新版的Tarantool(我們的系統(tǒng)是用Tarantool 1.5寫的,這個(gè)版本除了在Mail.Ru Group,其他地方基本沒用過)。Tarantool 1.6大力提倡主主備份,于是我們想:為什么不在連接主主備份的三個(gè)數(shù)據(jù)中心分別建立一個(gè)數(shù)據(jù)庫(kù)備份呢?這聽起來是個(gè)不錯(cuò)的計(jì)劃。

NoSQL數(shù)據(jù)庫(kù)的主主備份

三個(gè)主機(jī)、三個(gè)數(shù)據(jù)中心和三個(gè)更新器,都分別連接自己的主數(shù)據(jù)庫(kù)。即使一個(gè)或者兩個(gè)主機(jī)癱瘓了,系統(tǒng)仍然照常運(yùn)行,對(duì)吧?那么這個(gè)方案的缺點(diǎn)是什么呢?缺點(diǎn)就是,我們將一個(gè)OAuth服務(wù)提供商的請(qǐng)求數(shù)量有效地增加到了三倍,也就是說,有多少個(gè)副本,我們就要更新幾乎相同數(shù)量的令牌,這樣不行。最直接的解決辦法就是,想辦法讓各個(gè)節(jié)點(diǎn)自己決定誰是leader,那樣就只需要更新存儲(chǔ)在leader上的節(jié)點(diǎn)了。

選擇leader節(jié)點(diǎn)

選擇leader節(jié)點(diǎn)的算法有很多,其中有一個(gè)算法叫Paxos,相當(dāng)復(fù)雜,不知道怎樣簡(jiǎn)化,于是我們決定用Raft代替。Raft是一個(gè)非常通俗易懂的算法,誰能通信就選誰做leader,一旦通信連接失敗或者其他因素,就重新選leader。具體實(shí)施辦法如下:

NoSQL數(shù)據(jù)庫(kù)的主主備份

Tarantool外部既沒有Raft也沒有Paxos,但是我們可以使用net.box內(nèi)置模式,讓所有節(jié)點(diǎn)連接成一個(gè)網(wǎng)狀網(wǎng)(即每一個(gè)節(jié)點(diǎn)連接剩下所有節(jié)點(diǎn)),然后直接在這些連接上用Raft算法選出leader節(jié)點(diǎn)。***,所有節(jié)點(diǎn)要么成為leader節(jié)點(diǎn),要么成為follower節(jié)點(diǎn),或者二者都不是。

如果你覺得Raft算法實(shí)施起來有困難,下面的Lua代碼可以幫到你:

 

  1. local r = self.pool.call(self.FUNC.request_vote, 
  2.                      self.term, self.uuid) 
  3. self._vote_count = self:count_votes(r) 
  4.  
  5. if self._vote_count > self._nodes_count / 2 then 
  6.     log.info(“[raft-srv] node %d won elections”, self.id) 
  7.     self:_set_state(self.S.LEADER) 
  8.     self:_set_leader({ id=self.id, uuid=self.uuid }) 
  9.     self._vote_count = 0 
  10.     self:stop_election_timer() 
  11.     self:start_heartbeater() 
  12. else 
  13.     log.info(“[raft-srv] node %d lost elections”, self.id) 
  14.     self:_set_state(self.S.IDLE) 
  15.     self:_set_leader(msgpack.NULL
  16.     self._vote_count = 0 
  17.     self:start_election_timer() 
  18. end 

現(xiàn)在我們給遠(yuǎn)程服務(wù)器發(fā)送請(qǐng)求(其他Tarantool副本)并計(jì)算來自每一個(gè)節(jié)點(diǎn)的票數(shù),如果我們有一個(gè)quorum,我們就選定了一個(gè)leader,然后發(fā)送heartbeats,告訴其他節(jié)點(diǎn)我們還活著。如果我們?cè)谶x舉中失敗了,我們可以發(fā)起另一場(chǎng)選舉,一段時(shí)間之后,我們又可以投票或被選為leader。

只要我們有一個(gè)quorum,選中一個(gè)leader,我們就可以將更新器指派給所有節(jié)點(diǎn),但是只準(zhǔn)它們?yōu)閘eader服務(wù)。

這樣我們就規(guī)范了流量,由于任務(wù)是由單一的節(jié)點(diǎn)派出,因此每一個(gè)更新器獲得大約三分之一的任務(wù),有了這樣的設(shè)置,我們可以失去任何一臺(tái)主機(jī),因?yàn)槿绻撑_(tái)主機(jī)出故障了,我們可以發(fā)起另一個(gè)選舉,更新器也可以切換到另一個(gè)節(jié)點(diǎn)。然而,和其他分布式系統(tǒng)一樣,有好幾個(gè)問題與quorum有關(guān)。

“廢棄”節(jié)點(diǎn)

如果各個(gè)數(shù)據(jù)中心之間失去聯(lián)系了,那么我們需要有一些適當(dāng)?shù)臋C(jī)制去維持整個(gè)系統(tǒng)正常運(yùn)轉(zhuǎn),還需要有一套機(jī)制能恢復(fù)系統(tǒng)的完整性。Raft成功地做到了這兩點(diǎn):

NoSQL數(shù)據(jù)庫(kù)的主主備份

假設(shè)Dataline數(shù)據(jù)中心掉線了,那么該位置的節(jié)點(diǎn)就變成了“廢棄”節(jié)點(diǎn),也就是說該節(jié)點(diǎn)就看不到其他節(jié)點(diǎn)了,集群中的其他節(jié)點(diǎn)可以看到這個(gè)節(jié)點(diǎn)丟失了,于是引發(fā)了另一個(gè)選舉,然后新的集群節(jié)點(diǎn)(即上級(jí)節(jié)點(diǎn))被選為leader,整個(gè)系統(tǒng)仍然保持運(yùn)轉(zhuǎn),因?yàn)楦鱾€(gè)節(jié)點(diǎn)之間仍然保持一致性(大半部分節(jié)點(diǎn)仍然互相可見)。

那么問題來了,與丟失的數(shù)據(jù)中心有關(guān)的更新器怎么樣了呢?Raft說明書沒有給這樣的節(jié)點(diǎn)一個(gè)單獨(dú)的名字,通常,沒有quorum的節(jié)點(diǎn)和不能與leader聯(lián)系的節(jié)點(diǎn)會(huì)被閑置下來。然而,它可以自己建立網(wǎng)絡(luò)連接然后更新令牌,一般來說,令牌都是在連接模式時(shí)更新,但是,也許用一個(gè)連接“廢棄”節(jié)點(diǎn)的更新器也可以更新令牌。一開始我們并不確定這樣做有意義,這樣不會(huì)導(dǎo)致冗余更新嗎?

這個(gè)問題我們需要在實(shí)施系統(tǒng)的過程中搞清楚。我們的***個(gè)想法是不更新:我們有一致性、有quorum,丟失任何一個(gè)成員,我們都不應(yīng)該更新。但是后來我們有了另一個(gè)想法,我們看一下Tarantool中的主主備份,假設(shè)有兩個(gè)主節(jié)點(diǎn)和一個(gè)變量(key)X=1,我們同時(shí)在每一個(gè)節(jié)點(diǎn)上給這個(gè)變量賦一個(gè)新值,一個(gè)賦值為2,另一個(gè)賦值為3,然后,兩個(gè)節(jié)點(diǎn)互相交換備份日志(就是X變量的值)。在一致性上,這樣實(shí)施主主備份是很糟糕的(無意冒犯Tarantool開發(fā)者)。

NoSQL數(shù)據(jù)庫(kù)的主主備份

如果我們需要嚴(yán)格的一致性,這樣是行不通的。然而,回憶一下我們的OAuth令牌是由以下兩個(gè)重要因素組成:

  • 更新令牌,本質(zhì)上***有效;
  • 訪問令牌,有效期為一個(gè)小時(shí);

我們的更新器有一個(gè)refresh函數(shù),可以從一個(gè)更新令牌獲取任意數(shù)量的訪問令牌,一旦發(fā)布,它們都將保持一個(gè)小時(shí)內(nèi)有效。

我們考慮一下以下場(chǎng)景:兩個(gè)follower節(jié)點(diǎn)正在和一個(gè)leader節(jié)點(diǎn)交互,它們更新自己的令牌,接收***個(gè)訪問令牌,這個(gè)訪問令牌被復(fù)制,于是現(xiàn)在每一個(gè)節(jié)點(diǎn)都有這個(gè)訪問令牌,然后,連接中斷了,所以,其中一個(gè)follower節(jié)點(diǎn)變成了“廢棄”節(jié)點(diǎn),它沒有quorum,既看不到leader也看不到其他follower,然而,我們?cè)试S我們的更新器去更新位于“廢棄”節(jié)點(diǎn)上的令牌,如果“廢棄”節(jié)點(diǎn)沒有連接網(wǎng)絡(luò),那么整個(gè)方案都將停止運(yùn)行。盡管如此,如果發(fā)生簡(jiǎn)單的網(wǎng)絡(luò)拆分,更新器還是可以維持正常運(yùn)行。

一旦網(wǎng)絡(luò)拆分結(jié)束,“廢棄”節(jié)點(diǎn)重新加入集群,就會(huì)引發(fā)另一場(chǎng)選舉或者數(shù)據(jù)交換。注意,第二和第三個(gè)令牌一樣,也是“好的”。

原始的集群成員恢復(fù)之后,下一次更新將只在一個(gè)節(jié)點(diǎn)上發(fā)生,然后備份。換句話來說,當(dāng)集群拆分之后,被拆分的各個(gè)部分各自獨(dú)立更新,但是一旦重新整合,數(shù)據(jù)一致性也因此恢復(fù)。通常,需要N/2+1個(gè)活動(dòng)節(jié)點(diǎn)(對(duì)于一個(gè)3節(jié)點(diǎn)集群,就是需要2個(gè)活動(dòng)節(jié)點(diǎn))去保持集群正常運(yùn)轉(zhuǎn)。盡管如此,對(duì)我們而言,即使只有1個(gè)活動(dòng)節(jié)點(diǎn)也足夠了,它會(huì)發(fā)送盡可能多的外部請(qǐng)求。

重申一下,我們已經(jīng)討論了請(qǐng)求數(shù)量逐漸增加的情況,在網(wǎng)絡(luò)拆分或節(jié)點(diǎn)中斷時(shí)期,我們能夠提供一個(gè)單一的活動(dòng)節(jié)點(diǎn),我們會(huì)像平時(shí)一樣更新這個(gè)節(jié)點(diǎn),如果出現(xiàn)絕對(duì)拆分(即當(dāng)一個(gè)集群被分成***數(shù)量的節(jié)點(diǎn),每一個(gè)節(jié)點(diǎn)有一個(gè)網(wǎng)絡(luò)連接),如上所述,OAuth服務(wù)提供商的請(qǐng)求數(shù)量將提升至三倍。但是,由于這個(gè)事件發(fā)生的時(shí)間相對(duì)短暫,所以情況不是太糟,我們可不希望一直工作在拆分模式。通常情況下,系統(tǒng)處于有quorum和網(wǎng)絡(luò)連接,并且所有節(jié)點(diǎn)都啟動(dòng)運(yùn)行的狀態(tài)。

分片

還有一個(gè)問題沒有解決:我們已經(jīng)達(dá)到了CPU上限,最直接的解決辦法就是分片。

NoSQL數(shù)據(jù)庫(kù)的主主備份

假設(shè)我們有兩個(gè)數(shù)據(jù)庫(kù)分片,每一個(gè)都有備份,有一個(gè)這樣的函數(shù),給定一些key值,就可以計(jì)算出哪一個(gè)分片上有所需要的數(shù)據(jù)。如果我們通過電子郵件分片,一部分地址存儲(chǔ)在一個(gè)分片上,另一部分地址存儲(chǔ)在另一個(gè)分片上,我們很清楚我們的數(shù)據(jù)在哪里。

有兩種方法可以分片。一種是客戶端分片,我們選擇一個(gè)返回分片數(shù)量的連續(xù)的分片函數(shù),比如CRC32、Guava或Sumbur,這個(gè)函數(shù)在所有客戶端的實(shí)現(xiàn)方式都一樣。這種方法的一個(gè)明顯優(yōu)勢(shì)在于數(shù)據(jù)庫(kù)對(duì)分片一無所知,你的數(shù)據(jù)庫(kù)正常運(yùn)轉(zhuǎn),然后分片就發(fā)生了。

然而,這種方法也存在一個(gè)很嚴(yán)重的缺陷。一開始,客戶端非常繁忙。如果你想要一個(gè)新的分片,你需要把分片邏輯加進(jìn)客戶端,這里的***的問題是,可能一些客戶端在使用這種模式,而另一些客戶端卻在使用另一種完全不同的模式,而數(shù)據(jù)庫(kù)本身卻不知道有兩種不同的分片模式。

我們選擇另一種方法—數(shù)據(jù)庫(kù)內(nèi)部分片,這種情況下,數(shù)據(jù)庫(kù)代碼變得更加復(fù)雜,但是為了折中我們可以使用簡(jiǎn)單的客戶端,每一個(gè)連接數(shù)據(jù)庫(kù)的客戶端被路由到任意節(jié)點(diǎn),由一個(gè)特殊函數(shù)計(jì)算出哪一個(gè)節(jié)點(diǎn)應(yīng)該被連接、哪一個(gè)節(jié)點(diǎn)應(yīng)該被控制。前面提到,由于數(shù)據(jù)庫(kù)變得更加復(fù)雜,因此為了折中,客戶端就變得更加簡(jiǎn)單了,但是這樣的話,數(shù)據(jù)庫(kù)就要對(duì)其數(shù)據(jù)全權(quán)負(fù)責(zé)。此外,最困難的事就是重新分片,如果你有一大堆客戶端無法更新,相比之下,如果數(shù)據(jù)庫(kù)負(fù)責(zé)管理自己的數(shù)據(jù),那重新分片就會(huì)變得非常簡(jiǎn)單。

具體怎樣實(shí)施呢?

 

NoSQL數(shù)據(jù)庫(kù)的主主備份

六邊形代表Tarantool實(shí)體,有3個(gè)節(jié)點(diǎn)組成分片1,另一個(gè)3節(jié)點(diǎn)集群作為分片2,如果我們將所有節(jié)點(diǎn)互相連接,結(jié)果會(huì)怎樣呢?根據(jù)Raft,我們可以知道每一個(gè)集群的狀態(tài),誰是leader服務(wù)器誰是follower服務(wù)器也一目了然,由于是集群內(nèi)連接,我們還可以知道其他分片(例如它的leader分片或者follower分片)的狀態(tài)。總的來說,如果訪問***個(gè)分片的用戶發(fā)現(xiàn)這并不是他需要的分片,我們很清楚地知道應(yīng)該指導(dǎo)他往哪里走。

我們來看一些簡(jiǎn)單的例子。

假設(shè)用戶向駐留在***個(gè)分片上的key發(fā)出請(qǐng)求,該請(qǐng)求被***個(gè)分片上的某一個(gè)節(jié)點(diǎn)接收,這個(gè)節(jié)點(diǎn)知道誰是leader,于是將請(qǐng)求重新路由到分片leader,反過來,分片leader對(duì)這個(gè)key進(jìn)行讀或?qū)懀⑶覍⒔Y(jié)果反饋給用戶。

第二個(gè)場(chǎng)景:用戶的請(qǐng)求到達(dá)***個(gè)分片中的相同節(jié)點(diǎn),但是被請(qǐng)求的key卻在第二個(gè)分片上,這種情況也可以用類似的方法處理,***個(gè)分片知道第二個(gè)分片上誰是leader,然后把請(qǐng)求送到第二個(gè)分片的leader進(jìn)行轉(zhuǎn)發(fā)和處理,再將結(jié)果返回給用戶。

這個(gè)方案十分簡(jiǎn)單,但也存在一定的缺陷,其中***的問題就是連接數(shù),在二分片的例子中,每一個(gè)節(jié)點(diǎn)連接到其他剩下的節(jié)點(diǎn),連接數(shù)是6*5=30,如果再加一個(gè)3節(jié)點(diǎn)分片,那么連接數(shù)就增加到72,這會(huì)不會(huì)有點(diǎn)多呢?

我們?cè)撊绾谓鉀Q這個(gè)問題呢?我們只需要增加一些Tarantool實(shí)例,我們叫它代理,而不叫分片或數(shù)據(jù)庫(kù),用代理去解決所有的分片問題:包括計(jì)算key值和定位分片領(lǐng)導(dǎo)。另一方面,Raft集群保持自包含,只在分片內(nèi)部工作。當(dāng)用戶訪問代理時(shí),代理計(jì)算出所需要的分片,如果需要的是leader,就對(duì)用戶作相應(yīng)的重定向,如果不是leader,就將用戶重定向至分片內(nèi)的任意節(jié)點(diǎn)。

NoSQL數(shù)據(jù)庫(kù)的主主備份

由此產(chǎn)生的復(fù)雜性是線性的,取決于節(jié)點(diǎn)數(shù)量。現(xiàn)在一共3個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)3個(gè)分片,連接數(shù)少了幾倍。

代理方案的設(shè)計(jì)考慮到了進(jìn)一步規(guī)模擴(kuò)展(當(dāng)分片數(shù)量大于2時(shí)),當(dāng)只有2個(gè)分片時(shí),連接數(shù)不變,但是當(dāng)分片數(shù)量增加時(shí),連接數(shù)會(huì)劇減。分片列表存儲(chǔ)在Lua配置文件中,所以,如果想要獲取新列表,我們只需要重載代碼就好了。

綜上所述,首先,我們進(jìn)行主主備份,應(yīng)用Raft算法,然后加入分片和代理,***我們得到的是一個(gè)單塊,一個(gè)集群,所以說,目前這個(gè)方案看上去是比較簡(jiǎn)單的。

剩下的就是只讀或只寫令牌的的前端了,我們有更新器可以更新令牌,獲得更新令牌后把它傳到OAuth服務(wù)提供商,然后寫一個(gè)新的訪問令牌。

前面說過我們的一些輔助邏輯耗盡了CPU資源,現(xiàn)在我們將這些輔助資源移到另一個(gè)集群上。

輔助邏輯主要和地址簿有關(guān),給定一個(gè)用戶令牌,就會(huì)有一個(gè)對(duì)應(yīng)的地址簿,地址簿上的數(shù)據(jù)量和令牌一樣,為了不耗盡一臺(tái)機(jī)器上的CPU資源,我們顯然需要一個(gè)與副本相同的集群,只需要加一堆更新地址簿的更新器就可以了(這個(gè)任務(wù)比較少見,因此地址簿不會(huì)和令牌一起更新)。

***,通過整合這兩個(gè)集群,我們得到一個(gè)相對(duì)簡(jiǎn)單的完整結(jié)構(gòu):

NoSQL數(shù)據(jù)庫(kù)的主主備份

令牌更新隊(duì)列

為什么我們本可以使用標(biāo)準(zhǔn)隊(duì)列卻還要用自己的隊(duì)列呢?這和我們的令牌更新模型有關(guān)。令牌一旦發(fā)布,有效期就是一個(gè)小時(shí),當(dāng)令牌快要到期時(shí),需要進(jìn)行更新,而令牌更新必須在某個(gè)特定的時(shí)間點(diǎn)之前完成。

NoSQL數(shù)據(jù)庫(kù)的主主備份

假設(shè)系統(tǒng)中斷了,但是我們有一堆已到期的令牌,而在我們更新這些令牌的同時(shí),又有其他令牌陸續(xù)到期,雖然我們***肯定能全部更新完,但是如果我們先更新那些即將到期的(60秒內(nèi)),再用剩下的資源去更新已經(jīng)到期的,是不是會(huì)更合理一些?(優(yōu)先級(jí)別***的是還有4-5分鐘才到期的令牌)

用第三方軟件來實(shí)現(xiàn)這個(gè)邏輯并不是件容易的事,然而,對(duì)于Tarantool來說卻不費(fèi)吹灰之力??匆粋€(gè)簡(jiǎn)單的方案:在Tarantool中有一個(gè)存儲(chǔ)數(shù)據(jù)的元組,這個(gè)元組的一些ID設(shè)置了基礎(chǔ)key值,為了得到我們需要的隊(duì)列,我們只需要添加兩個(gè)字段:status(隊(duì)列令牌狀態(tài))和time(到期時(shí)間或其他預(yù)定義時(shí)間)。

NoSQL數(shù)據(jù)庫(kù)的主主備份

現(xiàn)在我們考慮一下隊(duì)列的兩個(gè)主要功能—put和take。put就是寫入新數(shù)據(jù)。給定一些負(fù)載,put時(shí)自己設(shè)置好status和time,然后寫數(shù)據(jù),這就是建立一個(gè)新的元組。

至于take,是指建立一個(gè)基于索引的迭代器,挑出那些等待解決的任務(wù)(處于就緒狀態(tài)的任務(wù)),然后核查一下是不是該接收這些任務(wù)了,或者這些任務(wù)是否已經(jīng)到期了。如果沒有任務(wù),take就切換到wait模式。除了內(nèi)置Lua,Tarantool還有一些所謂的通道,這些通道本質(zhì)上是互聯(lián)光纖同步原語。任何光纖都可以建立一個(gè)通道然后說“我在這等著”,剩下的其他光纖可以喚醒這個(gè)通道然后給它發(fā)送信息。

等待中的函數(shù)(等待發(fā)布任務(wù)、等待指定時(shí)間或其他)建立一個(gè)通道,給通道貼上適當(dāng)?shù)臉?biāo)簽,將通道放置在某個(gè)地方,然后進(jìn)行監(jiān)聽。如果我們收到一個(gè)緊急的更新令牌,put會(huì)給通道發(fā)出通知,然后take接收更新任務(wù)。

Tarantool有一個(gè)特殊的功能:如果一個(gè)令牌被意外發(fā)布,或者一個(gè)更新令牌被take接收,或者只是出現(xiàn)接收任務(wù)的現(xiàn)象,以上三種情況Tarantool都可以跟蹤到客戶端中斷。我們將每一個(gè)連接與指定給該連接的任務(wù)聯(lián)系起來,并將這些映射關(guān)系保持在會(huì)話保存中。假設(shè)由于網(wǎng)絡(luò)中斷導(dǎo)致更新過程失敗,而且我們不知道這個(gè)令牌是否會(huì)被更新并被寫回到數(shù)據(jù)庫(kù)。于是,客戶端發(fā)生中斷了,搜索與失敗過程相關(guān)的所有任務(wù)的會(huì)話保存,然后自動(dòng)將它們釋放。隨后,任意已發(fā)布的任務(wù)都可以用同一個(gè)通道給另一個(gè)put發(fā)送信息,該put會(huì)快速接收和執(zhí)行任務(wù)。

實(shí)際上,具體實(shí)施方案并不需要太多代碼:

 

  1. function put(data) 
  2.     local t = box.space.queue:auto_increment({ 
  3.         ‘r’, -- [[ status ]] 
  4.         util.time(), -- [[ time ]] 
  5.         data -- [[ any payload ]] 
  6.     }) 
  7.  
  8.     return t 
  9. end 
  10.  
  11. function take(timeout) 
  12.     local start_time = util.time() 
  13.     local q_ind = box.space.tokens.index.queue 
  14.     local _,t 
  15.  
  16.     while true do 
  17.         local it = util.iter(q_ind, {‘r’}, {iterator = box.index.GE}) 
  18.         _,t = it() 
  19.         if t and t[F.tokens.status] ~= ‘t’ then 
  20.             break 
  21.         end 
  22.  
  23.         local left = (start_time + timeout) — util.time() 
  24.         if left <= 0 then return end 
  25.         t = q:wait(left
  26.         if t then break end 
  27.     end 
  28.     t = q:taken(t) 
  29.     return t 
  30. end 
  31.  
  32. function queue:taken(task) 
  33.     local sid = box.session.id() 
  34.     if self._consumers[sid] == nil then 
  35.         self._consumers[sid] = {} 
  36.     end 
  37.     local k = task[self.f_id] 
  38.     local t = self:set_status(k, ‘t’) 
  39.  
  40.     self._consumers[sid][k] = {util.time(), box.session.peer(sid), t} 
  41.     self._taken[k] = sid 
  42.     return t 
  43. end 
  44.  
  45. function on_disconnect() 
  46.     local sid = box.session.id 
  47.     local now = util.time() 
  48.  
  49.     if self._consumers[sid] then 
  50.         local consumers = self._consumers[sid] 
  51.         for k, rec in pairs(consumers) do 
  52.             time, peer, task = unpack(rec) 
  53.  
  54.             local v = box.space[self.space].index[self.index_primary]:get({k}) 
  55.             if v and v[self.f_status] == ‘t’ then 
  56.                 v = self:release(v[self.f_id]) 
  57.             end 
  58.         end 
  59.         self._consumers[sid] = nil 
  60.     end 
  61. end 

Put只是接收用戶想要插入隊(duì)列的所有數(shù)據(jù),并將其寫入某個(gè)空間,如果是一個(gè)簡(jiǎn)單的索引式FIFO隊(duì)列,設(shè)置好狀態(tài)和當(dāng)前時(shí)間,然后返回該任務(wù)。

接下來要和take有點(diǎn)關(guān)系了,但仍然比較簡(jiǎn)單。我們建立一個(gè)迭代器,等待接收新任務(wù)。Taken函數(shù)只需要將任務(wù)標(biāo)記成“已接收”,但有一點(diǎn)很重要,taken函數(shù)還能記住哪個(gè)任務(wù)是由哪個(gè)進(jìn)程接收的。On_disconnect函數(shù)可以發(fā)布某個(gè)特定連接,或者發(fā)布由某個(gè)特定用戶接收的所有任務(wù)。

是否有可選方案 ?

當(dāng)然有。我們本可以使用任意數(shù)據(jù)庫(kù),但是,不管我們選用什么數(shù)據(jù)庫(kù),我們都要建立一個(gè)隊(duì)列用來處理外部系統(tǒng)、處理更新等等問題。我們不能僅僅按需更新令牌,因?yàn)槟菢訒?huì)產(chǎn)生不可預(yù)估的工作量,不管怎樣,我們需要保持我們的系統(tǒng)充滿活力,但是那樣,我們就要將延期的任務(wù)也插入隊(duì)列,并且保證數(shù)據(jù)庫(kù)和隊(duì)列之間的一致性,我們還要被迫使用一個(gè)quorum的容錯(cuò)隊(duì)列。此外,如果我們把數(shù)據(jù)同時(shí)放在RAM和一個(gè)(考慮到工作量)可能要放入內(nèi)存的隊(duì)列中,那么我們就要消耗更多資源。

在我們的方案中,數(shù)據(jù)庫(kù)存儲(chǔ)令牌,隊(duì)列邏輯只需要占用7個(gè)字節(jié)(每個(gè)元組只需要7個(gè)額外的字節(jié),就可以搞定隊(duì)列邏輯!),如果使用其他的隊(duì)列形式,需要占用的空間就多得多了,大概是內(nèi)存容量的兩倍。

總結(jié)

首先,我們解決了連接中斷的問題,這個(gè)問題十分常見,使用上述的系統(tǒng)讓我們擺脫了這個(gè)困擾。

分片幫助我們擴(kuò)展內(nèi)存,然后,我們將連接數(shù)從二次方減少到了線性,優(yōu)化了業(yè)務(wù)任務(wù)的隊(duì)列邏輯:如果發(fā)生延期,更新我們所能更新的一切令牌,這些延期并非都是我們的故障引起的,有可能是Google、Microsoft或者其他服務(wù)端對(duì)OAuth服務(wù)提供商進(jìn)行改造,然后導(dǎo)致我們這邊出現(xiàn)大量的未更新的令牌。

去數(shù)據(jù)庫(kù)內(nèi)部運(yùn)算吧,走近數(shù)據(jù),你將擁有便利、高效、可擴(kuò)展和靈活的運(yùn)算體驗(yàn)!

責(zé)任編輯:未麗燕 來源: ITeye
相關(guān)推薦

2021-10-26 08:00:00

數(shù)據(jù)庫(kù)架構(gòu)技術(shù)

2015-10-22 16:26:59

MySQL數(shù)據(jù)庫(kù)雙主配置

2024-02-02 10:51:53

2023-11-27 07:23:39

2021-09-28 09:25:05

NoSQL數(shù)據(jù)庫(kù)列式數(shù)據(jù)庫(kù)

2011-10-09 09:38:03

OracleNoSQL

2020-10-31 22:01:40

NoSQL數(shù)據(jù)庫(kù)

2021-12-29 06:13:44

數(shù)據(jù)庫(kù)密碼數(shù)據(jù)泄露

2019-03-20 15:59:11

NoSQLRedis數(shù)據(jù)庫(kù)

2010-04-01 09:45:38

NoSQL

2019-07-08 10:36:34

數(shù)據(jù)庫(kù)WebNoSQL

2011-07-19 09:08:50

JavaNoSQL

2024-03-28 09:00:00

NoSQL數(shù)據(jù)庫(kù)

2022-02-14 09:00:00

SQLNoSQL數(shù)據(jù)庫(kù)

2010-03-16 14:05:19

Cassandra

2014-06-30 14:20:05

NoSQL數(shù)據(jù)庫(kù)

2019-09-11 15:10:01

NoSQLSQL數(shù)據(jù)庫(kù)

2011-09-01 10:23:47

Nginx負(fù)載均衡器負(fù)載均衡

2011-03-30 13:57:41

MySQL數(shù)據(jù)庫(kù)自動(dòng)備份

2011-03-31 14:34:46

cactimysql備份
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

蜜桃视频在线入口www| 精品久久久久久中文字幕人妻最新| 久草国产精品视频| 蝌蚪视频在线播放| 韩国视频一区二区| 欧美精品久久久久久久免费观看| 密臀av一区二区三区| 韩国中文字幕在线| 99久久国产综合精品女不卡| 日本免费久久高清视频| 午夜精品一区二区三级视频| 盗摄牛牛av影视一区二区| 日韩欧美有码在线| 国产一二三四五| 加勒比一区二区三区在线| 国产乱子伦视频一区二区三区 | 丁香六月色婷婷| 日韩国产欧美三级| 欧美超级免费视 在线| 亚洲激情视频小说| 91亚洲无吗| 欧美美女bb生活片| 国产欧美高清在线| av免费网站在线观看| 久久久久高清精品| 国产精品国产精品国产专区蜜臀ah | 国产精品色婷婷| 国产一区视频观看| 精品国产乱码一区二区三 | 色噜噜久久综合伊人一本| 波多野结衣在线免费观看| 欧美成人免费电影| 婷婷中文字幕一区三区| 伊人再见免费在线观看高清版 | 成人久久精品| 在线中文字幕一区| 免费日韩中文字幕| 牛牛电影国产一区二区| 亚洲视频在线观看一区| 亚洲韩国在线| 成人高清免费在线播放| 久久亚洲综合av| 久久精品magnetxturnbtih| 国产高清第一页| 国内精品第一页| 91精品在线一区| 国产精品久久久久毛片| 美女免费视频一区二区| 国产精品欧美激情| 五月天中文字幕| 日本色综合中文字幕| 国产精品69精品一区二区三区| 黄大色黄女片18免费| 国产精品日韩精品中文字幕| 亚洲激情视频在线观看| 精品国产乱码久久久久夜深人妻| 黄视频网站在线观看| 亚洲香肠在线观看| 人妻少妇精品无码专区二区| av电影院在线看| 五月天激情小说综合| 91丨porny丨探花| 国产激情视频在线看| 天天影视网天天综合色在线播放| 日韩欧美在线电影| 成人av毛片| 亚洲欧洲国产日本综合| 三年中国中文在线观看免费播放 | 久久99久久久精品欧美| 欧美色视频在线观看| 在线观看免费污视频| 日韩美女在线| 日韩免费性生活视频播放| 国产成人精品一区二区三区在线观看 | 激情婷婷综合网| 日韩毛片免费观看| 欧美精品久久久久久久多人混战| 男人和女人啪啪网站| 最新欧美色图| 欧美午夜寂寞影院| 国产在线观看中文字幕| 精品亚洲自拍| 亚洲人成在线观| 手机在线中文字幕| 在线观看亚洲| 国产精品成人免费视频| 一区二区www| 成人网页在线观看| 欧美性xxxx69| av毛片在线| 欧美性xxxx极品hd满灌| 91国内在线播放| 国产精品毛片av| 一本色道久久88亚洲综合88| 看片网站在线观看| 久久久综合网| 亚洲自拍另类欧美丝袜| 性xxxxbbbb| 亚洲精品欧美在线| 免费国产成人av| 51精品国产| 最近2019中文字幕大全第二页| 中文字幕被公侵犯的漂亮人妻| 成人性生交大片免费看中文视频| 6080亚洲精品一区二区| 国产又黄又粗又猛又爽的视频| 2023国产精华国产精品| 亚洲欧美日韩久久久久久| 永久av免费网站| 国产精品亚洲欧美| 96pao国产成视频永久免费| 日本成人一区二区三区| 亚洲欧美日韩在线不卡| 免费av网址在线| 成人台湾亚洲精品一区二区| 日韩中文字幕在线看| 亚洲黄色三级视频| 国产成人啪午夜精品网站男同| 国产成人精品一区二区三区福利| 国产视频在线观看免费| 国产日韩欧美在线一区| 久久这里只有精品8| 亚洲伦理网站| 一区二区三区国产在线观看| 国产免费av一区二区| 国产精品99久久久久久久vr| 亚洲免费视频一区| 欧美不卡高清一区二区三区| 亚洲国产成人91精品| 欧美精品久久久久性色| 精东粉嫩av免费一区二区三区| 91久久极品少妇xxxxⅹ软件| 国产午夜在线观看| 欧美性生交xxxxxdddd| 91丨porny丨九色| 亚洲91久久| 成人在线播放av| 欧美三级黄网| 欧美麻豆精品久久久久久| 五月天精品视频| 久久国产直播| 美乳视频一区二区| 中文字幕21页在线看| 日韩av网址在线| 精品在线播放视频| 91网页版在线| 欧美牲交a欧美牲交| 日韩极品少妇| 日本久久91av| jizz视频在线观看| 欧美三级乱人伦电影| 精品人体无码一区二区三区| 天使萌一区二区三区免费观看| 成人在线国产精品| 国产区在线观看| 欧美一区二区观看视频| 久久久www成人免费毛片| 丰满白嫩尤物一区二区| 精品无码国产一区二区三区av| 裤袜国产欧美精品一区| 亚洲天堂久久av| 奴色虐av一区二区三区| 亚洲国产成人午夜在线一区 | 美国美女黄色片| 可以免费看不卡的av网站| 欧美成熟毛茸茸复古| 韩国精品主播一区二区在线观看| 精品国产91亚洲一区二区三区婷婷| 欧美激情aaa| 日本免费新一区视频 | 九九亚洲视频| 日韩免费av片在线观看| 在线观看的av| 日韩精品一区二区在线| 日韩 欧美 综合| 中文字幕 久热精品 视频在线| 夫妻免费无码v看片| 精品国精品国产自在久国产应用| 欧美大片在线免费观看| 成人午夜福利视频| 一本大道综合伊人精品热热| 青青草华人在线视频| 国产成人在线影院| 18禁男女爽爽爽午夜网站免费| 51精品国产| 欧亚精品中文字幕| 黄网站app在线观看| 亚洲国产毛片完整版| 一区二区三区麻豆| 亚洲永久精品大片| 男生草女生视频| 国产成人av电影在线| 日本精品久久久久中文字幕| 91精品国产麻豆国产在线观看| 国产精品永久在线| 在线观看男女av免费网址| 日韩精品黄色网| 国产精品伊人久久| 色综合婷婷久久| 国产精品成人免费观看| 国产欧美精品一区| 少妇精品无码一区二区| 性高湖久久久久久久久| 女女同性女同一区二区三区按摩| 国产中文欧美日韩在线| 国产91精品久| 日韩av毛片| 中文字幕日韩欧美在线| 天堂网av在线播放| 欧美一二三四区在线| 国产熟妇一区二区三区四区| 亚洲一区免费视频| 少妇视频一区二区| 91丨九色丨黑人外教| 午夜影院免费版| 蜜桃久久久久久久| 欧美牲交a欧美牲交aⅴ免费真| 激情五月色综合国产精品| 成人动漫视频在线观看完整版| 久色国产在线| 日韩亚洲在线观看| 国产美女视频一区二区三区| 亚洲国产精品电影| 99精品免费观看| 欧美三级一区二区| 少妇高潮av久久久久久| 无吗不卡中文字幕| 国产午夜久久久| 亚洲精品综合在线| 97成人资源站| 亚洲色图欧洲色图婷婷| 日本成人免费在线观看| 欧美经典三级视频一区二区三区| 激情久久综合网| 久久精品国产一区二区三| 日本成人中文字幕在线| 夜夜精品视频| 免费看黄在线看| 红桃视频亚洲| 69sex久久精品国产麻豆| 国产一区视频在线观看免费| 国产免费一区二区三区四在线播放 | 亚洲免费黄色| 日本阿v视频在线观看| 91精品动漫在线观看| 自拍视频一区二区三区| 国产高清欧美| 国产三级中文字幕| 中出一区二区| 黄色一级片黄色| 欧美福利一区| 大陆av在线播放| 国产一级久久| 丰满少妇在线观看| 日本美女一区二区三区视频| 一区二区三区 日韩| 久久精品72免费观看| 91 视频免费观看| 国产精品性做久久久久久| 国内自拍偷拍视频| 99精品国产视频| 国产免费一区二区三区网站免费| 国产成人免费视频精品含羞草妖精| a√天堂在线观看| 国产精品永久| 九色91popny| 久久99久久99精品免视看婷婷 | 色噜噜色狠狠狠狠狠综合色一| 视频免费一区二区| 国产精品加勒比| 免费短视频成人日韩| 亚洲自拍三区| 国产精品chinese| 2022亚洲天堂| 美女视频黄a大片欧美| 自拍视频第一页| 91免费精品国自产拍在线不卡| 不卡的一区二区| 97se亚洲国产综合自在线观| 久久婷婷五月综合| 亚洲视频一区二区在线| 国产无遮挡免费视频| 在线观看亚洲精品视频| 999久久久久| 亚洲精品视频播放| 77导航福利在线| 久久久久久国产免费| 性欧美videohd高精| 91最新在线免费观看| 欧美综合自拍| 自拍偷拍视频在线| 亚洲视频1区| 欧美日韩理论片| 久久美女高清视频| 国产suv一区二区三区| 色婷婷激情综合| 精品人妻少妇AV无码专区 | 国产成人午夜视频网址 | 国产成人97精品免费看片| 欧美videos粗暴| 美女视频久久| 国产精品v日韩精品v欧美精品网站| 在线综合视频网站| 国产欧美一区二区色老头| 九九热免费在线观看| 播五月开心婷婷综合| 国产日产精品一区二区三区的介绍| 国产精品美女久久久久av爽李琼 | 欧美专区中文字幕| 久久99精品久久久野外观看| 欧美最大成人综合网| 国产综合婷婷| 99re6在线观看| 久久久91精品国产一区二区三区| 三上悠亚影音先锋| 亚洲二区在线视频| 国产99999| 日韩中文字幕国产| 精品国产第一福利网站| 国产精品久久久久久久免费大片| 欧美日韩一区二区三区不卡视频| 九九久久99| 欧美伊人影院| 国产一区二区在线观看免费视频| 国产一区999| 国产123在线| 日韩欧美在线观看视频| 天天干视频在线| 欧美激情一区二区三区高清视频 | 日韩欧美在线免费| 成人小说亚洲一区二区三区| 久久成人这里只有精品| 日韩福利影视| 一区精品视频| 久久9热精品视频| 色婷婷粉嫩av| 欧美女孩性生活视频| 成a人片在线观看www视频| 日本精品视频在线| 岳的好大精品一区二区三区| 中文字幕无码精品亚洲35| 成人18视频日本| 国产中文字幕免费| 亚洲国产婷婷香蕉久久久久久| 99免在线观看免费视频高清| 国产精品6699| 日韩精品久久| 爱豆国产剧免费观看大全剧苏畅 | 日本特黄久久久高潮| 妺妺窝人体色WWW精品| 欧美综合久久久| 又爽又大又黄a级毛片在线视频| 欧美激情喷水视频| 国产精品2023| 成人黄色av片| 91视视频在线直接观看在线看网页在线看 | 国产亚洲一二三区| 日本免费精品视频| 精品中文字幕久久久久久| 亚洲天堂资源| 亚洲国产精品久久久久久女王| 亚洲欧洲日本一区二区三区| jjzzjjzz欧美69巨大| 五月天一区二区三区| 亚洲欧美日韩动漫| 青草青草久热精品视频在线网站| 欧美久久亚洲| 国产曰肥老太婆无遮挡| 99久久免费国产| 最好看的日本字幕mv视频大全 | 亚洲天天影视| 91老司机精品视频| 一区在线视频观看| 97超碰在线资源| 欧美影片第一页| 国产丝袜在线| 国产区二精品视| 日本成人超碰在线观看| 91杏吧porn蝌蚪| 精品一区二区三区四区在线| 九色成人搞黄网站| 黄色成人在线免费观看| 久久久久久久久久看片| 国产又黄又大又粗的视频| 国色天香2019中文字幕在线观看| 成人影院网站ww555久久精品| 日韩中文字幕一区| 国产真实精品久久二三区| 国产成人一区二区三区影院在线| 精品国产区一区| 一呦二呦三呦精品国产| 成人毛片100部免费看| 久久久久九九视频| 国产夫妻在线观看| 人人做人人澡人人爽欧美| 一个色综合网| ass精品国模裸体欣赏pics| 91麻豆精品国产91久久久资源速度 | 91亚洲精华国产精华精华液| 亚洲精品毛片一区二区三区|