松花皮蛋的黑板報
  • 分享在京東工作的技術感悟,還有JAVA技術和業內最佳實踐,大部分都是務實的、能看懂的、可復現的

掃一掃
關注公眾號

ARTS-14-分布式系統之一致性和數據復制

博客首頁文章列表 松花皮蛋me 2019-06-16 17:33

ARTS的初衷

Algorithm: 主要是為了編程訓練和學習。

Review:主要是為了學習英文

Tip:主要是為了總結和歸納在日常工作中所遇到的知識點。學習至少一個技術技巧。在工作中遇到的問題,踩過的坑,學習的點滴知識。

Share:主要是為了建立影響力,能夠輸出價值觀。分享一篇有觀點和思考的技術文章

https://www.zhihu.com/question/301150832

一、Algorithm

Single Number

Given a non-empty array of integers, every element appears twice except for one. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Example 1:

Input: [2,2,1]
Output: 1
Example 2:

Input: [4,1,2,1,2]
Output: 4

class Solution {
    public int singleNumber(int[] nums) {
        //不需要額外內存,nums非空但是可能包括0
        //數值轉換為二進制后進行運算,0^0=0, 0^1=1, 1^0=0, 1^1=0
        //異或滿足交換律
        int ans =  nums[0];
        for(int i=1;i<nums.length;i++) {
            ans = ans^nums[i];
        }
        return ans;
    }
}

二、Review

1、一致性常見問題

這些問題離我們并不遙遠,數據分散在多處會導致數據不一致,必須盡可能地解決此問題,才能保證良好的用戶體驗,最終的期望是任何人、任何時間、任何地點、任何接入方式、任何服務,數據都是一致的

2、一致性模式

1)、順序一致性(Sequencial Consistency)

每個線程內部的指令都是按照程序規定的順序執行的(單個線程的視角)。線程執行的交錯順序可以是做任意的,但是所有線程所看見的整體程序總體執行順序都是一樣的(整體程序的視角)

2)、弱一致性-因果一致性(Casual Consistency)

如果節點A在更新完某個數據后通知了節點B,那么節點B之后對該數據的訪問和修改都是基于A更新后的值。于此同時,和節點A無因果關系的節點C的數據訪問則沒有這樣的限制

3)、弱一致性-入口一致性(Entry Consistency)

入口一致性要求每個普通的共享數據都要與某種同步變量如鎖(lock)或屏障(barrier)相關聯

進程2在沒有獲取”y”數據的訪問鎖時,讀取的值將為NIL(In the following figures, since Process2 does not hold the access right (= synchronous variable) to the data item “y”, the reading result becomes NIL)

4、弱一致性-最終一致性(Eventual consistency)

5)、弱一致性-以客戶為中心的一致性(Client-centric consistency model)

包括以下四種體現

(1)、單調讀一致性(Monotonic reading)

如果一個進程從系統中讀取出一個數據項X的某個值后,該進程對于X后續訪問都不應該返回更舊的值(If a process reads data item x, any subsequent reads on x by that process will either reply with the same value or reply with a newer value)

例子:任何時候你登錄郵箱服務,它都能保證你上次訪問服務器時可以讀取的郵件現在都可以查看

(2)、單調寫一致性(Monotonic writing)

一個系統要能夠保證來自同一個進程的寫操作被順序的執行,它類似以數據為中心的FIFO一致性,不過它強調的是在單一進程的順序約束而不是并發進程集(A write operation by one process to a data item x is completed before any subsequent write to x by the same process)

(3)、寫后讀一致性(Read Your Writes)

進程更新一個數據后,它總是能訪問到自身更新過的最新值,而不會看到舊值(The result of a write operation by a process to data item x is always observed by subsequent read operations by the same process)

例子:比如當你更新一個系統的管理密碼時,必須保證更新后的密碼無論你在任何地方登錄時都有效

(4)、讀后寫一致性(Writes Follow Reads)

同一個進程對數據項X執行的讀操作之后的寫操作,保證發生在與X讀取值相同或比之更新的值上(The result of a write operation by a process to data item x is always observed by subsequent read operations by the same process)

一致性模式描述的是嚴格一致性、因果一致性和順序一致性,保證了系統不會出現臟寫、臟讀、不可重復讀、幻讀、更新丟失的壞賬

3、解決思路-ACID

最常見的實現方式是WAL(write ahead loging)技術,它并不直接寫入到系統文件中,而是寫入到另外一個稱為WAL的文件中;如果事務失敗,WAL中的記錄會被忽略,撤銷修改;如果事務成功,它將在隨后的某個時間被寫回到系統文件中,提交修改

4、解決思路-CAP

ARTS-13-分布式系統入門和實踐筆記

5、解決思路-BASE

基本可用、中間(軟)狀態、最終一致

6、常見解決方案

1)、兩階段提交-2PC

TM存在單點問題,而且會同步阻塞,產生資源鎖定,并發低的情況

2)、補償機制-TCC

針對每個操作,注冊一個與其對應的確認和補償(撤銷)操作,對業務侵入性大,需要設計復雜的重試、冪行、日記記錄模塊

3)、補償機制-Saga

流程:

(1)、訂單服務創建最終狀態未知的訂單記錄
(2)、訂單服務創建一個CreateOrderSaga負責協調訂單
(3)、CreateOrderSaga發送ReserveCredit指令至用戶服務
(4)、用戶服務接受到指令然后為此訂單預扣款,同時回復一條表明結果的信息
(5)、CreateOrderSaga接受到信息后,發送通過或拒絕指令到訂單服務
(6)、訂單服務接受到指令后修改其狀態

Saga可以看做是一個異步的、事件驅動的補償事務,由Sage工作流引擎協調,其適用于無需立刻返回業務發起方最終狀態的場景,但是它不保證隔離性

鏈接:https://github.com/eventuate-tram/eventuate-tram-sagas

4)、基于MQ-本地消息表

將分布式事務拆分成本地事務進行處理

5)、基于MQ-事務消息

6)、經典實現-Seata

一個典型的分布式事務過程:

(1)、TM 向 TC 申請開啟一個全局事務,全局事務創建成功并生成一個全局唯一的 XID
(2)、XID 在微服務調用鏈路的上下文中傳播
(3)、RM 向 TC 注冊分支事務,將其納入 XID 對應全局事務的管轄
(4)、TM 向 TC 發起針對 XID 的全局提交或回滾決議
(5)、TC 調度 XID 下管轄的全部分支事務完成提交或回滾請求

鏈接:https://github.com/seata/seata

7、數據復制

1)、服務端(Server Startup Replica)

2)、客戶端(Client Startup Replica)

緩存失效時長不宜過長

8、數據同步

需要數據多備份就意味著需要內容同步,常見的方式有

1)、 將更新通知傳輸到副本(Propagate only updates notifications)
2)、 將更新數據傳輸到副本(Transmit update data from one copy to another)
3)、 將更新操作傳輸到副本-推薦方式(Propagate update operations to other replicas)

比如mysql的主從復制過程

參考文章:
https://medium.com/mold-project/consistency-e3e0fe41358d
https://www.infoq.cn/article/G33hCC-QoSJPlkt4e64E

三、Tip

1、多module打包發現程序包不存在

使用maven-compiler-plugin替換spring-boot-maven-plugin插件

2、SpringBoot項目部署到非內嵌的tomcat容器

1)、移除(exclusions)默認的tomcat依賴包,因為springboot具有自動裝配特性的,它取決于開發人員在應用的ClassPath下的JAR文件依賴,同時項目的src/main/resource目錄下存在META-INF/spring.factories資源,并且配置EnableAutoConfiguration,那么SpringBoot會”嘗試”將其裝配
2)、引用tomcat依賴,推薦使用tomcat-servlet-api
3)、主類繼承SpringBootServletInitializer抽象類并重寫configure方法,SpringBootServletInitializer就是一個org.springframework.web.context.WebApplicationContext,它能讓我們使用外部的Servlet容器,容器啟動時會調用其onStartup(ServletContext servletContext)方法,首先配置各種servlet、filter、listener等,最后通過SpringApplicationBuilder構建并封裝SpringApplication對象,并調用SpringApplication的run方法

  @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebApplication.class);
    }

4)、修改pom.xml的packaging為war
5)、在application.properties中配置spring.main.web-application-type=none

四、Share

微服務架構之Dubbo-服務引用,解讀服務引用流程、Directory目錄服務、Forking調用解析

黑龙江6+1开奖结果查询