【原創】modb 功能設計之「多級 modb 之間的同步」


      modb 在最初設計中採用的是兩級模型,但很快就遇到了多級同步的需求。解決多級同步問題首先須要引入多級路由 key ,即將原來兩級模型中的單個 key 值擴展爲 key 的 array ,具體變化以下:

兩級使用的數據格式
{
    "src" : "172.16.80.111", 
    "keys" : "key_1",
    "app" : "A",
    "state" : "transfer"
    "sql" : "insert into users values(?,?,?)";
    "sql-args" : [1, 2, "abc"]
}
多級使用的數據格式
{
    "src" : "172.16.80.111", 
    "keys" : ["key_1","key_2"]
    "app" : "A",
    "sql" : "insert into users values(?,?,?)";
    "sql-args" : [1, 2, "abc"]
}
而在 modb 的業務邏輯處理中也須要增長相應的處理,具體以下:

      假設處理的是三級數據同步狀況,分別爲 modb-A 、modb-B 和 modb-C 三級平臺域(分別位於三級服務域中),且 A 是 B 的上級,B 是 C 的上級。A 級平臺域中某業務對數據進行了變動,而後須要將此變動信息同步到 B 和 C 級平臺域。


經過數據操做入口進行數據變動後,將發送以下消息給 modb-A:
{
    "src" : "172.16.80.111", 
    "keys" : ["key_B","key_C"]
    "app" : "A",
    "sql" : "insert into users values(?,?,?)";
    "sql-args" : [1, 2, "abc"]
}
modb-A 接收到此消息後(此時 A 級平臺域的數據庫已經發生了變動),並根據配置將
  • 向同在 A 級的其餘平臺域進行消息轉發;
  • 根據 key 值進行對下級的路由轉發;
在進行消息轉發前,modb-A 還會對消息內容作以下修改:
{
    "src" : "172.16.80.111", 
    "keys" : ["key_C"]
    "app" : "A",
    "sql" : "insert into users values(?,?,?)";
    "sql-args" : [1, 2, "abc"]
}
即從 keys 數組中移除 key_B 。

      modb-B 在接收到上述消息後,將從中提取出 sql 內容進行執行,並對 keys 數組內容進行檢查,看是否還有其餘 key 的存在,如有,則代表須要繼續進行向下級的路由轉發。        
      modb-B 從新獲取到該消息後(此時 B 級平臺域的數據庫已經獲得了更新),首先檢測 keys 數組中是否還有其餘 key 存在,如有,則在進行轉發前會對消息內容作以下修改:
      (這裏 modb-B 前後兩次做爲 consumer 收到 rabbitmq 消息是由於分別訂閱了遠端和本地的 queue 所致,好處是處理起來模型統一  
{
    "src" : "172.16.80.111", 
    "keys" : []
    "app" : "A",
    "sql" : "insert into users values(?,?,?)";
    "sql-args" : [1, 2, "abc"]
}
即從 keys 數組中移除 key_C 。

      modb-C 接收到上述消息後,將從中提取 sql 內容進行執行,並對 keys 數組內容進行檢查,看是否還有其餘 key 的存在,若沒有,則代表已再也不須要繼續進行路由。
      modb-C 從新獲取到該消息後(此時 C 級平臺域的數據庫已經獲得了更新),首先檢測 keys 數組中是否還有其餘 key 存在,若沒有,則只須要對相同服務域中的平臺域進行廣播,而無需進行下一級轉發。

      上述模型的優勢是簡單,僅經過配置就能夠完成多級關係的數據同步功能;缺點是存在單點,不具備動態變動上下級關係的能力,須要經過其餘方式進行後續配置。

可能遇到的異常狀況:
  • rabbitmq 服務器異常 -- 業務更新本地數據庫成功後,將發送通知消息到 rabbitmq 服務器,須要業務端可以判斷出「服務器不可用」狀態,並觸發重傳等操做;
  • modb 進程異常 -- 業務更新本地數據庫成功後,發送通知消息到 rabbitmq 服務器,若要求在 modb 進程異常的狀況下消息不丟失,則須要 rabbitmq 啓用對消息的持久化功能,而且最好取消掉 exclusive 和 auto_delete 等相關屬性的設置,可能還須要處理當 queue 不存在時消息被 blackholed 的狀況;
  • Atlas 異常 -- 若在業務還沒有成功更新本地數據庫前發生 Atlas 異常,則要求業務可以告之當前狀況下「沒法創建數據庫鏈接」;若在業務成功更新本地數據庫後發生 Atlas 異常,此時向外部 modb 同步當前更新沒有問題,但沒法同步外部 modb 對本地數據庫的更新。(可能的一種解決辦法:令 modb 支持緩存功能,當發現 Atlas 異常時則將更新消息放入緩存隊列,並在每次接收到新的更新消息時觸發一次針對 Atlas 是否恢復的檢測。若 Atlas 已經恢復,則將緩存隊列中的內容順序執行

      上述問題並未針對「異常狀況下對 數據庫進行操做時可能遇到的問題」 進行深刻的說明,具體問題必定會更加複雜。一點體會:若想真正的把數據庫同步功能作好,最起碼須要深刻理解數據一致性的相關理論,如有一個成熟的框架可使用就更加完美了。
相關文章
相關標籤/搜索