ViewService——一種保證客戶端與服務端同步的方法

簡介

在分佈式系統中,最多見的場景就是主備架構。可是若是主機不幸宕機,如何正確的通知客戶端當先後端服務器的情況成爲一個值得研究的問題。本文描述了一種簡單的模型用於解決此問題。php

背景

以一個分佈式的Key-Value數據庫爲背景。數據庫對外提供3個接口數據庫

Get(key)
Put(key, value)
Append(key, value)後端

客戶端對數據庫的操做請求必須發往主機, 只有當主機不可訪問(主機宕機或網絡問題)時,備機代替主機,而且再從集羣中選一個新的機器做爲備機。服務器

問題來了 客戶端如何知道當前誰是主機誰是備機?網絡

目的

爲了保證客戶端與服務器就誰是主機誰是備機這個問題達成共識。架構

總體架構

Architecture

爲了解決這個問題,咱們在Server和Clint中間加入一個ViewServer。viewserver的做用至關於一箇中介。舉個例子,當客戶端想要執行Put操做時,須要先向viewserver詢問當前的Primary是誰,隨後客戶端根據viewserver的回覆將Put請求發到相應的server。分佈式

View

viewserver返回給客戶端的信息須要包含至少3條信息:spa

  1. 當前主機是誰code

  2. 當前備機是誰server

  3. 當前狀態的版本號
    咱們將這3個信息稱爲viewserver的當前View。

typedef struct View {
  Viewnum int
  Primary string
  Backup string
}

Server

在多個server中,只有一個主機,一個備機,其他的server都處於空閒狀態。全部的server都須要每隔一段時間向viewserver發送Ping消息,以證實本身還活着。而且經過Ping的返回值,獲得當前viewserver認爲的主機和備機是誰。這樣,若是主機和備機都正常,在一段時間以後,後端server都會有一致的主機和備機。

Client

在操做後端server以前,先訊問viewserver當前主機是誰.

ViewServer

viewserver的功能比較複雜,主要負責:

  1. 回覆客戶端當前View

  2. 檢測後端的server的存活狀況

  3. 保證當前主機獲得最新的View

在檢測後端server存活狀況時,有幾種狀況

  1. 主機Primary失聯

  2. 備機Backup失聯

  3. 空閒機器失聯

當檢測到主機或者備機失聯時,viewserver應該對當前View作調整。若是主機失聯,則把備機選作主機,而後從空間機器中挑選一個做爲備機。若是備機失聯,只從空閒機器中選擇一個做爲備機便可。可是,這兩種狀況都須要對View的版本號進行增長。這個View版本號只有後端server關心,客戶端只關心當前主機。加入這個版本號的目的,主要是爲了確保當前主機獲得了最新的View。好比備機的更換會須要主機向備機作數據拷貝,若是主機得不到這個消息,整個主備系統就失效了。

ViewService.jpg

上圖描述了兩臺server與viewserver之間的通訊.
每次server端Ping須要包含一個參數,用於表示當前這個server所瞭解到了View版本號.

  1. 在初始狀態,server1向viewserver發送Ping,而且用0作爲參數.因爲初始狀態viewserver尚未選擇主機和備機,因此先到先得,選擇server1爲主機.因而返回給server1的View爲[server1, NULL, 1], 表示當前主機爲server1, 備機爲NULL, 望的到的版本號爲1(但願一段時間後當前的主機Primary以這個新版本號發起Ping).

  2. server2此時加入了集羣,向viewserver發送了Ping. 因爲server2與server1沒有聯繫,因此Ping的參數仍是用0,表示這是新加入的機器.雖然此時viewserver發現又有了一臺機器加入,而且當前只有主機,沒有備機,可是還不能選擇server2作爲備機.由於server1尚未用1作爲參數發起Ping, 說明viewserver當前的這個View(主機爲server1,備機爲NULL)可能尚未被當前主機(server1)收到.所以返回給server2的View爲[server1, NULL, 1].

  3. server1順利收到viewserver返回的View,得知viewserver想要版本號爲1的Ping, 因而隔一個PingInerval再向viewserver發起Ping,同時以1爲參數. viewserver順利收到這個Ping, 發現正是本身但願獲得的(當前主機以新版本號發起的Ping), 而且瞭解到一個事實:當前主機server1已經知道了當前最新的主備狀況.因而viewserver將View的版本號更新.返回給server1[server1, NULL, 2].

  4. server2在一個PingInterval後再次向viewser發起Ping, 由於以前一次Ping返回的ViewNum爲1, 所以用1爲參數.當viewserver順利收到Ping時,因爲viewserver知道當前主機server1以經得到了它目前保存的這個狀態,所以將server2選爲備機, 構成了一個新的狀態(主機爲server1, 備機爲server2), 這個狀態尚未任何server知道, 當前的主機server1顯然也不知道.所以ViewNum不能更新.因而返回[server1, server2, 2]給server2.

  5. server1向viewserver發起Ping(2), viewserver經過這個Ping得知當前主機server1以經得到了本身最新的狀態.而後server1失聯.

  6. server2向viewserver發起Ping(2)

在長期沒有的到server1的Ping後,viewserver會認爲server1以經不能繼續對外提供服務了,因而選擇備機server2作爲主機,若是有其餘空閒機器,能夠從中選一個作爲新的備機.viewserver之因此選擇server2作爲備機是由於肯定server2能夠萬全代替以經失聯的server1, 由於server2作爲備機這個信息server1以經收到了,確保server2的狀態與server1相同是server1的工做,好比主機會向備機發送數據作數據同步.

存在的問題

If the view service has not yet received an acknowledgment for the current view from the primary of the current view, the view service should not change views even if it thinks that the primary or backup has died. That is, the view service may not proceed from view X to view X+1 if it has not received a Ping(X) from the primary of view X.

qc1iu|語言玩家

相關文章
相關標籤/搜索