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

一文講透微服務下如何保證事務的一致性

開發(fā) 架構
什么是事務?回答這個問題之前,我們先來看一個經(jīng)典的場景:支付寶等交易平臺的轉(zhuǎn)賬。假設小明需要用支付寶給小紅轉(zhuǎn)賬 100000 元,此時,小明帳號會少 100000 元,而小紅帳號會多 100000 元。

[[311568]]

 從本地事務到分布式事務的演變

什么是事務?回答這個問題之前,我們先來看一個經(jīng)典的場景:支付寶等交易平臺的轉(zhuǎn)賬。假設小明需要用支付寶給小紅轉(zhuǎn)賬 100000 元,此時,小明帳號會少 100000 元,而小紅帳號會多 100000 元。如果在轉(zhuǎn)賬過程中系統(tǒng)崩潰了,小明帳號少 100000 元,而小紅帳號金額不變,就會出大問題,因此這個時候我們就需要使用事務了。請參見圖 6-1。

 

這里,體現(xiàn)了事務一個很重要的特性:原子性。事實上,事務有四個基本特性:原子性、一致性、隔離性、持久性。其中,原子性,即事務內(nèi)的操作要么全部成功,要么全部失敗,不會在中間的某個環(huán)節(jié)結束。一致性,即使數(shù)據(jù)庫在一個事務執(zhí)行之前和執(zhí)行之后,數(shù)據(jù)庫都必須處于一致性狀態(tài)。如果事務執(zhí)行失敗,那么需要自動回滾到原始狀態(tài),換句話說,事務一旦提交,其他事務查看到的結果一致,事務一旦回滾,其他事務也只能看到回滾前的狀態(tài)。隔離性,即在并發(fā)環(huán)境中,不同的事務同時修改相同的數(shù)據(jù)時,一個未完成事務不會影響另外一個未完成事務。持久性,即事務一旦提交,其修改的數(shù)據(jù)將永久保存到數(shù)據(jù)庫中,其改變是永久性的。

本地事務通過 ACID 保證數(shù)據(jù)的強一致性。ACID是 Atomic(原子性)、Consistency(一致性)、 Isolation(隔離性)和 Durability(持久性)的縮寫 。在實際開發(fā)過程中,我們或多或少都有使用到本地事務。例如,MySQL 事務處理使用到 begin 開始一個事務,rollback 事務回滾,commit 事務確認。這里,事務提交后,通過 redo log 記錄變更,通過 undo log 在失敗時進行回滾,保證事務的原子性。筆者補充下,使用 Java 語言的開發(fā)者都接觸過 Spring。Spring 使用 @Transactional 注解就可以搞定事務功能。事實上,Spring 封裝了這些細節(jié),在生成相關的 Bean 的時候,在需要注入相關的帶有 @Transactional 注解的 bean 時候用代理去注入,在代理中為我們開啟提交/回滾事務。請參見圖6-2。

隨著業(yè)務的高速發(fā)展,面對海量數(shù)據(jù),例如,上千萬甚至上億的數(shù)據(jù),查詢一次所花費的時間會變長,甚至會造成數(shù)據(jù)庫的單點壓力。因此,我們就要考慮分庫與分表方案了。分庫與分表的目的在于,減小數(shù)據(jù)庫的單庫單表負擔,提高查詢性能,縮短查詢時間。這里,我們先來看下單庫拆分的場景。事實上,分表策略可以歸納為垂直拆分和水平拆分。垂直拆分,把表的字段進行拆分,即一張字段比較多的表拆分為多張表,這樣使得行數(shù)據(jù)變小。一方面,可以減少客戶端程序和數(shù)據(jù)庫之間的網(wǎng)絡傳輸?shù)淖止?jié)數(shù),因為生產(chǎn)環(huán)境共享同一個網(wǎng)絡帶寬,隨著并發(fā)查詢的增多,有可能造成帶寬瓶頸從而造成阻塞。另一方面,一個數(shù)據(jù)塊能存放更多的數(shù)據(jù),在查詢時就會減少 I/O 次數(shù)。水平拆分,把表的行進行拆分。因為表的行數(shù)超過幾百萬行時,就會變慢,這時可以把一張的表的數(shù)據(jù)拆成多張表來存放。水平拆分,有許多策略,例如,取模分表,時間維度分表等。這種場景下,雖然我們根據(jù)特定規(guī)則分表了,我們?nèi)匀豢梢允褂帽镜厥聞?。但是,庫?nèi)分表,僅僅是解決了單表數(shù)據(jù)過大的問題,但并沒有把單表的數(shù)據(jù)分散到不同的物理機上,因此并不能減輕 MySQL 服務器的壓力,仍然存在同一個物理機上的資源競爭和瓶頸,包括 CPU、內(nèi)存、磁盤 IO、網(wǎng)絡帶寬等。對于分庫拆分的場景,它把一張表的數(shù)據(jù)劃分到不同的數(shù)據(jù)庫,多個數(shù)據(jù)庫的表結構一樣。此時,如果我們根據(jù)一定規(guī)則將我們需要使用事務的數(shù)據(jù)路由到相同的庫中,可以通過本地事務保證其強一致性。但是,對于按照業(yè)務和功能劃分的垂直拆分,它將把業(yè)務數(shù)據(jù)分別放到不同的數(shù)據(jù)庫中。這里,拆分后的系統(tǒng)就會遇到數(shù)據(jù)的一致性問題,因為我們需要通過事務保證的數(shù)據(jù)分散在不同的數(shù)據(jù)庫中,而每個數(shù)據(jù)庫只能保證自己的數(shù)據(jù)可以滿足 ACID 保證強一致性,但是在分布式系統(tǒng)中,它們可能部署在不同的服務器上,只能通過網(wǎng)絡進行通信,因此無法準確的知道其他數(shù)據(jù)庫中的事務執(zhí)行情況。請參見圖6-3。

此外,不僅僅在跨庫調(diào)用存在本地事務無法解決的問題,隨著微服務的落地中,每個服務都有自己的數(shù)據(jù)庫,并且數(shù)據(jù)庫是相互獨立且透明的。那如果服務 A 需要獲取服務 B 的數(shù)據(jù),就存在跨服務調(diào)用,如果遇到服務宕機,或者網(wǎng)絡連接異常、同步調(diào)用超時等場景就會導致數(shù)據(jù)的不一致,這個也是一種分布式場景下需要考慮數(shù)據(jù)一致性問題。請參見圖6-4。

總結一下,當業(yè)務量級擴大之后的分庫,以及微服務落地之后的業(yè)務服務化,都會產(chǎn)生分布式數(shù)據(jù)不一致的問題。既然本地事務無法滿足需求,因此分布式事務就要登上舞臺。什么是分布式事務?我們可以簡單地理解,它就是為了保證不同數(shù)據(jù)庫的數(shù)據(jù)一致性的事務解決方案。這里,我們有必要先來了解下 CAP 原則和 BASE 理論。CAP 原則是 Consistency(一致性)、Availablity(可用性)和 Partition-tolerance(分區(qū)容錯性)的縮寫,它是分布式系統(tǒng)中的平衡理論。在分布式系統(tǒng)中,一致性要求所有節(jié)點每次讀操作都能保證獲取到最新數(shù)據(jù);可用性要求無論任何故障產(chǎn)生后都能保證服務仍然可用;分區(qū)容錯性要求被分區(qū)的節(jié)點可以正常對外提供服務。事實上,任何系統(tǒng)只可同時滿足其中二個,無法三者兼顧。對于分布式系統(tǒng)而言,分區(qū)容錯性是一個最基本的要求。那么,如果選擇了一致性和分區(qū)容錯性,放棄可用性,那么網(wǎng)絡問題會導致系統(tǒng)不可用。如果選擇可用性和分區(qū)容錯性,放棄一致性,不同的節(jié)點之間的數(shù)據(jù)不能及時同步數(shù)據(jù)而導致數(shù)據(jù)的不一致。請參見圖 6-5。


此時,BASE 理論針對一致性和可用性提出了一個方案,BASE 是 Basically Available(基本可用)、Soft-state(軟狀態(tài))和 Eventually Consistent(最終一致性)的縮寫,它是最終一致性的理論支撐。簡單地理解,在分布式系統(tǒng)中,允許損失部分可用性,并且不同節(jié)點進行數(shù)據(jù)同步的過程存在延時,但是在經(jīng)過一段時間的修復后,最終能夠達到數(shù)據(jù)的最終一致性。BASE 強調(diào)的是數(shù)據(jù)的最終一致性。相比于 ACID 而言,BASE 通過允許損失部分一致性來獲得可用性。

現(xiàn)在,業(yè)內(nèi)比較常用的分布式事務解決方案,包括強一致性的兩階段提交協(xié)議,三階段提交協(xié)議,以及最終一致性的可靠事件模式、補償模式,阿里的 TCC 模式。我們會在后面的章節(jié)中詳細介紹與實戰(zhàn)。

強一致性解決方案

二階段提交協(xié)議

在分布式系統(tǒng)中,每個數(shù)據(jù)庫只能保證自己的數(shù)據(jù)可以滿足 ACID 保證強一致性,但是它們可能部署在不同的服務器上,只能通過網(wǎng)絡進行通信,因此無法準確的知道其他數(shù)據(jù)庫中的事務執(zhí)行情況。因此,為了解決多個節(jié)點之間的協(xié)調(diào)問題,就需要引入一個協(xié)調(diào)者負責控制所有節(jié)點的操作結果,要么全部成功,要么全部失敗。其中,XA 協(xié)議是一個分布式事務協(xié)議,它有兩個角色:事務管理者和資源管理者。這里,我們可以把事務管理者理解為協(xié)調(diào)者,而資源管理者理解為參與者。

XA 協(xié)議通過二階段提交協(xié)議保證強一致性。

二階段提交協(xié)議,顧名思義,它具有兩個階段:第一階段準備,第二階段提交。這里,事務管理者(協(xié)調(diào)者)主要負責控制所有節(jié)點的操作結果,包括準備流程和提交流程。第一階段,事務管理者(協(xié)調(diào)者)向資源管理者(參與者)發(fā)起準備指令,詢問資源管理者(參與者)預提交是否成功。如果資源管理者(參與者)可以完成,就會執(zhí)行操作,并不提交,最后給出自己響應結果,是預提交成功還是預提交失敗。第二階段,如果全部資源管理者(參與者)都回復預提交成功,資源管理者(參與者)正式提交命令。如果其中有一個資源管理者(參與者)回復預提交失敗,則事務管理者(協(xié)調(diào)者)向所有的資源管理者(參與者)發(fā)起回滾命令。舉個案例,現(xiàn)在我們有一個事務管理者(協(xié)調(diào)者),三個資源管理者(參與者),那么這個事務中我們需要保證這三個參與者在事務過程中的數(shù)據(jù)的強一致性。首先,事務管理者(協(xié)調(diào)者)發(fā)起準備指令預判它們是否已經(jīng)預提交成功了,如果全部回復預提交成功,那么事務管理者(協(xié)調(diào)者)正式發(fā)起提交命令執(zhí)行數(shù)據(jù)的變更。請參見圖 6-6。

 

 

注意的是,雖然二階段提交協(xié)議為保證強一致性提出了一套解決方案,但是仍然存在一些問題。其一,事務管理者(協(xié)調(diào)者)主要負責控制所有節(jié)點的操作結果,包括準備流程和提交流程,但是整個流程是同步的,所以事務管理者(協(xié)調(diào)者)必須等待每一個資源管理者(參與者)返回操作結果后才能進行下一步操作。這樣就非常容易造成同步阻塞問題。其二,單點故障也是需要認真考慮的問題。事務管理者(協(xié)調(diào)者)和資源管理者(參與者)都可能出現(xiàn)宕機,如果資源管理者(參與者)出現(xiàn)故障則無法響應而一直等待,事務管理者(協(xié)調(diào)者)出現(xiàn)故障則事務流程就失去了控制者,換句話說,就是整個流程會一直阻塞,甚至極端的情況下,一部分資源管理者(參與者)數(shù)據(jù)執(zhí)行提交,一部分沒有執(zhí)行提交,也會出現(xiàn)數(shù)據(jù)不一致性。此時,讀者會提出疑問:這些問題應該都是小概率情況,一般是不會產(chǎn)生的?是的,但是對于分布式事務場景,我們不僅僅需要考慮正常邏輯流程,還需要關注小概率的異常場景,如果我們對異常場景缺乏處理方案,可能就會出現(xiàn)數(shù)據(jù)的不一致性,那么后期靠人工干預處理,會是一個成本非常大的任務,此外,對于交易的核心鏈路也許就不是數(shù)據(jù)問題,而是更加嚴重的資損問題。

三階段提交協(xié)議

二階段提交協(xié)議諸多問題,因此三階段提交協(xié)議就要登上舞臺了。三階段提交協(xié)議是二階段提交協(xié)議的改良版本,它與二階段提交協(xié)議不同之處在于,引入了超時機制解決同步阻塞問題,此外加入了預備階段盡可能提早發(fā)現(xiàn)無法執(zhí)行的資源管理者(參與者)并且終止事務,如果全部資源管理者(參與者)都可以完成,才發(fā)起第二階段的準備和第三階段的提交。否則,其中任何一個資源管理者(參與者)回復執(zhí)行,或者超時等待,那么就終止事務??偨Y一下,三階段提交協(xié)議包括:第一階段預備,第二階段準備,第二階段提交。請參見圖 6-7。

 

三階段提交協(xié)議很好的解決了二階段提交協(xié)議帶來的問題,是一個非常有參考意義的解決方案。但是,極小概率的場景下可能會出現(xiàn)數(shù)據(jù)的不一致性。因為三階段提交協(xié)議引入了超時機制,如果出現(xiàn)資源管理者(參與者)超時場景會默認提交成功,但是如果其沒有成功執(zhí)行,或者其他資源管理者(參與者)出現(xiàn)回滾,那么就會出現(xiàn)數(shù)據(jù)的不一致性。

最終一致性解決方案

TCC 模式

二階段提交協(xié)議和三階段提交協(xié)議很好的解決了分布式事務的問題,但是在極端情況下仍然存在數(shù)據(jù)的不一致性,此外它對系統(tǒng)的開銷會比較大,引入事務管理者(協(xié)調(diào)者)后,比較容易出現(xiàn)單點瓶頸,以及在業(yè)務規(guī)模不斷變大的情況下,系統(tǒng)可伸縮性也會存在問題。注意的是,它是同步操作,因此引入事務后,直到全局事務結束才能釋放資源,性能可能是一個很大的問題。因此,在高并發(fā)場景下很少使用。因此,阿里提出了另外一種解決方案:TCC 模式。注意的是,很多讀者把二階段提交等同于二階段提交協(xié)議,這個是一個誤區(qū),事實上,TCC 模式也是一種二階段提交。

TCC 模式將一個任務拆分三個操作:Try、Confirm、Cancel。假如,我們有一個 func() 方法,那么在 TCC 模式中,它就變成了 tryFunc()、confirmFunc()、cancelFunc() 三個方法。

  1. tryFunc (); 
  2.  
  3. confirmFunc (); 
  4.  
  5. cancelFunc (); 

在 TCC 模式中,主業(yè)務服務負責發(fā)起流程,而從業(yè)務服務提供 TCC 模式的 Try、Confirm、Cancel 三個操作。其中,還有一個事務管理器的角色負責控制事務的一致性。例如,我們現(xiàn)在有三個業(yè)務服務:交易服務,庫存服務,支付服務。用戶選商品,下訂單,緊接著選擇支付方式進行付款,然后這筆請求,交易服務會先調(diào)用庫存服務扣庫存,然后交易服務再調(diào)用支付服務進行相關的支付操作,然后支付服務會請求第三方支付平臺創(chuàng)建交易并扣款,這里,交易服務就是主業(yè)務服務,而庫存服務和支付服務是從業(yè)務服務。請參見圖 6-8。

 

我們再來梳理下,TCC 模式的流程。第一階段主業(yè)務服務調(diào)用全部的從業(yè)務服務的 Try 操作,并且事務管理器記錄操作日志。第二階段,當全部從業(yè)務服務都成功時,再執(zhí)行 Confirm 操作,否則會執(zhí)行 Cancel 逆操作進行回滾。請參見圖 6-9。

 

現(xiàn)在,我們針對 TCC 模式說說大致業(yè)務上的實現(xiàn)思路。首先,交易服務(主業(yè)務服務)會向事務管理器注冊并啟動事務。其實,事務管理器是一個概念上的全局事務管理機制,可以是一個內(nèi)嵌于主業(yè)務服務的業(yè)務邏輯,或者抽離出的一個 TCC 框架。事實上,它會生成全局事務 ID 用于記錄整個事務鏈路,并且實現(xiàn)了一套嵌套事務的處理邏輯。當主業(yè)務服務調(diào)用全部的從業(yè)務服務的 try 操作,事務管理器利用本地事務記錄相關事務日志,這個案例中,它記錄了調(diào)用庫存服務的動作記錄,以及調(diào)用支付服務的動作記錄,并將其狀態(tài)設置成“預提交”狀態(tài)。這里,調(diào)用從業(yè)務服務的 Try 操作就是核心的業(yè)務代碼。那么, Try 操作怎么和它相對應的 Confirm、Cancel 操作綁定呢?其實,我們可以編寫配置文件建立綁定關系,或者通過 Spring 的注解添加 confirm 和 cancel 兩個參數(shù)也是不錯的選擇。當全部從業(yè)務服務都成功時,由事務管理器通過 TCC 事務上下文切面執(zhí)行 Confirm 操作,將其狀態(tài)設置成“成功”狀態(tài),否則執(zhí)行 Cancel 操作將其狀態(tài)設置成“預提交”狀態(tài),然后進行重試。因此,TCC 模式通過補償?shù)姆绞奖WC其最終一致性。

TCC 的實現(xiàn)框架有很多成熟的開源項目,例如 tcc-transaction 框架。(關于 tcc-transaction 框架的細節(jié),可以閱讀:https://github.com/changmingxie/tcc-transaction)tcc-transaction 框架主要涉及 tcc-transaction-core、tcc-transaction-api、tcc-transaction-spring 三個模塊。其中,tcc-transaction-core 是 tcc-transaction 的底層實現(xiàn),tcc-transaction-api 是 tcc-transaction 使用的 API,tcc-transaction-spring 是 tcc-transaction 的 Spring 支持。tcc-transaction 將每個業(yè)務操作抽象成事務參與者,每個事務可以包含多個參與者。參與者需要聲明 try / confirm / cancel 三個類型的方法。這里,我們通過 @Compensable 注解標記在 try 方法上,并定義相應的 confirm / cancel 方法。

  1.  // try 方法 
  2.  @Compensable(confirmMethod = "confirmRecord", cancelMethod = "cancelRecord", transactionContextEditor = MethodTransactionContextEditor.class) 
  3.  @Transactional 
  4.  public String record(TransactionContext transactionContext, CapitalTradeOrderDto tradeOrderDto) {} 
  5.   
  6.  // confirm 方法 
  7.  @Transactional 
  8.  public void confirmRecord(TransactionContext transactionContext, CapitalTradeOrderDto tradeOrderDto) {} 
  9.    
  10.  // cancel 方法 
  11.  @Transactional 
  12.  public void cancelRecord(TransactionContext transactionContext, CapitalTradeOrderDto tradeOrderDto) {} 

對于 tcc-transaction 框架的實現(xiàn),我們來了解一些核心思路。tcc-transaction 框架通過 @Compensable 切面進行攔截,可以透明化對參與者 confirm / cancel 方法調(diào)用,從而實現(xiàn) TCC 模式。這里,tcc-transaction 有兩個攔截器,請參見圖 6-10。

  • org.mengyun.tcctransaction.interceptor.CompensableTransactionInterceptor,可補償事務攔截器。
  • org.mengyun.tcctransaction.interceptor.ResourceCoordinatorInterceptor,資源協(xié)調(diào)者攔截器。

這里,需要特別關注 TransactionContext 事務上下文,因為我們需要遠程調(diào)用服務的參與者時通過參數(shù)的形式傳遞事務給遠程參與者。在 tcc-transaction 中,一個事務 org.mengyun.tcctransaction.Transaction可以有多個參與者 org.mengyun.tcctransaction.Participant 參與業(yè)務活動。其中,事務編號 TransactionXid 用于唯一標識一個事務,它使用 UUID 算法生成,保證唯一性。當參與者進行遠程調(diào)用時,遠程的分支事務的事務編號等于該參與者的事務編號。通過事務編號的關聯(lián) TCC confirm / cancel 方法,使用參與者的事務編號和遠程的分支事務進行關聯(lián),從而實現(xiàn)事務的提交和回滾。事務狀態(tài) TransactionStatus 包含 :嘗試中狀態(tài) TRYING(1)、確認中狀態(tài) CONFIRMING(2)、取消中狀態(tài) CANCELLING(3)。此外,事務類型 TransactionType 包含 :根事務 ROOT(1)、分支事務 BRANCH(2)。當調(diào)用 TransactionManager#begin() 發(fā)起根事務時,類型為 MethodType.ROOT,并且事務 try 方法被調(diào)用。調(diào)用 TransactionManager#propagationNewBegin() 方法,傳播發(fā)起分支事務。該方法在調(diào)用方法類型為 MethodType.PROVIDER 并且 事務 try 方法被調(diào)用。調(diào)用 TransactionManager#commit() 方法提交事務。該方法在事務處于 confirm / cancel 方法被調(diào)用。類似地,調(diào)用 TransactionManager#rollback() 方法,取消事務。請參見圖 6-11。

此外,對于事務恢復機制,tcc-transaction 框架基于 Quartz 實現(xiàn)調(diào)度,按照一定頻率對事務進行重試,直到事務完成或超過最大重試次數(shù)。如果單個事務超過最大重試次數(shù)時,tcc-transaction 框架不再重試,此時需要手工介入解決。

這里,我們要特別注意操作的冪等性。冪等機制的核心是保證資源唯一性,例如重復提交或服務端的多次重試只會產(chǎn)生一份結果。支付場景、退款場景,涉及金錢的交易不能出現(xiàn)多次扣款等問題。事實上,查詢接口用于獲取資源,因為它只是查詢數(shù)據(jù)而不會影響到資源的變化,因此不管調(diào)用多少次接口,資源都不會改變,所以是它是冪等的。而新增接口是非冪等的,因為調(diào)用接口多次,它都將會產(chǎn)生資源的變化。因此,我們需要在出現(xiàn)重復提交時進行冪等處理。那么,如何保證冪等機制呢?事實上,我們有很多實現(xiàn)方案。其中,一種方案就是常見的創(chuàng)建唯一索引。在數(shù)據(jù)庫中針對我們需要約束的資源字段創(chuàng)建唯一索引,可以防止插入重復的數(shù)據(jù)。但是,遇到分庫分表的情況是,唯一索引也就不那么好使了,此時,我們可以先查詢一次數(shù)據(jù)庫,然后判斷是否約束的資源字段存在重復,沒有的重復時再進行插入操作。注意的是,為了避免并發(fā)場景,我們可以通過鎖機制,例如悲觀鎖與樂觀鎖保證數(shù)據(jù)的唯一性。這里,分布式鎖是一種經(jīng)常使用的方案,它通常情況下是一種悲觀鎖的實現(xiàn)。但是,很多人經(jīng)常把悲觀鎖、樂觀鎖、分布式鎖當作冪等機制的解決方案,這個是不正確的。除此之外,我們還可以引入狀態(tài)機,通過狀態(tài)機進行狀態(tài)的約束以及狀態(tài)跳轉(zhuǎn),確保同一個業(yè)務的流程化執(zhí)行,從而實現(xiàn)數(shù)據(jù)冪等。

補償模式

上節(jié),我們提到了重試機制。事實上,它也是一種最終一致性的解決方案:我們需要通過最大努力不斷重試,保證數(shù)據(jù)庫的操作最終一定可以保證數(shù)據(jù)一致性,如果最終多次重試失敗可以根據(jù)相關日志并主動通知開發(fā)人員進行手工介入。注意的是,被調(diào)用方需要保證其冪等性。重試機制可以是同步機制,例如主業(yè)務服務調(diào)用超時或者非異常的調(diào)用失敗需要及時重新發(fā)起業(yè)務調(diào)用。重試機制可以大致分為固定次數(shù)的重試策略與固定時間的重試策略。除此之外,我們還可以借助消息隊列和定時任務機制。消息隊列的重試機制,即消息消費失敗則進行重新投遞,這樣就可以避免消息沒有被消費而被丟棄,例如 RocketMQ 可以默認允許每條消息最多重試 16 次,每次重試的間隔時間可以進行設置。定時任務的重試機制,我們可以創(chuàng)建一張任務執(zhí)行表,并增加一個“重試次數(shù)”字段。這種設計方案中,我們可以在定時調(diào)用時,獲取這個任務是否是執(zhí)行失敗的狀態(tài)并且沒有超過重試次數(shù),如果是則進行失敗重試。但是,當出現(xiàn)執(zhí)行失敗的狀態(tài)并且超過重試次數(shù)時,就說明這個任務永久失敗了,需要開發(fā)人員進行手工介入與排查問題。

除了重試機制之外,也可以在每次更新的時候進行修復。例如,對于社交互動的點贊數(shù)、收藏數(shù)、評論數(shù)等計數(shù)場景,也許因為網(wǎng)絡抖動或者相關服務不可用,導致某段時間內(nèi)的數(shù)據(jù)不一致,我們就可以在每次更新的時候進行修復,保證系統(tǒng)經(jīng)過一段較短的時間的自我恢復和修正,數(shù)據(jù)最終達到一致。需要注意的是,使用這種解決方案的情況下,如果某條數(shù)據(jù)出現(xiàn)不一致性,但是又沒有再次更新修復,那么其永遠都會是異常數(shù)據(jù)。

定時校對也是一種非常重要的解決手段,它采取周期性的進行校驗操作來保證。關于定時任務框架的選型上,業(yè)內(nèi)比較常用的有單機場景下的 Quartz,以及分布式場景下 Elastic-Job、XXL-JOB、SchedulerX 等分布式定時任務中間件。關于定時校對可以分為兩種場景,一種是未完成的定時重試,例如我們利用定時任務掃描還未完成的調(diào)用任務,并通過補償機制來修復,實現(xiàn)數(shù)據(jù)最終達到一致。另一種是定時核對,它需要主業(yè)務服務提供相關查詢接口給從業(yè)務服務核對查詢,用于恢復丟失的業(yè)務數(shù)據(jù)。現(xiàn)在,我們來試想一下電商場景的退款業(yè)務。在這個退款業(yè)務中會存在一個退款基礎服務和自動化退款服務。此時,自動化退款服務在退款基礎服務的基礎上實現(xiàn)退款能力的增強,實現(xiàn)基于多規(guī)則的自動化退款,并且通過消息隊列接收到退款基礎服務推送的退款快照信息。但是,由于退款基礎服務發(fā)送消息丟失或者消息隊列在多次失敗重試后的主動丟棄,都很有可能造成數(shù)據(jù)的不一致性。因此,我們通過定時從退款基礎服務查詢核對,恢復丟失的業(yè)務數(shù)據(jù)就顯得特別重要了。

可靠事件模式

在分布式系統(tǒng)中,消息隊列在服務端的架構中的地位非常重要,主要解決異步處理、系統(tǒng)解耦、流量削峰等場景。多個系統(tǒng)之間如果同步通信很容易造成阻塞,同時會將這些系統(tǒng)會耦合在一起。因此,引入了消息隊列,一方面解決了同步通信機制造成的阻塞,另一方面通過消息隊列進行業(yè)務解耦。請參見圖 6-12。

可靠事件模式,通過引入可靠的消息隊列,只要保證當前的可靠事件投遞并且消息隊列確保事件傳遞至少一次,那么訂閱這個事件的消費者保證事件能夠在自己的業(yè)務內(nèi)被消費即可。這里,請讀者思考,是否只要引入了消息隊列就可以解決問題了呢?事實上,只是引入消息隊列并不能保證其最終的一致性,因為分布式部署環(huán)境下都是基于網(wǎng)絡進行通信,而網(wǎng)絡通信過程中,上下游可能因為各種原因而導致消息丟失。

其一,主業(yè)務服務發(fā)送消息時可能因為消息隊列無法使用而發(fā)生失敗。對于這種情況,我們可以讓主業(yè)務服務(生產(chǎn)者)發(fā)送消息,再進行業(yè)務調(diào)用來確保。一般的做法是,主業(yè)務服務將要發(fā)送的消息持久化到本地數(shù)據(jù)庫,設置標志狀態(tài)為“待發(fā)送”狀態(tài),然后把消息發(fā)送給消息隊列,消息隊列收到消息后,也把消息持久化到其存儲服務中,但并不是立即向從業(yè)務服務(消費者)投遞消息,而是先向主業(yè)務服務(生產(chǎn)者)返回消息隊列的響應結果,然后主業(yè)務服務判斷響應結果執(zhí)行之后的業(yè)務處理。如果響應失敗,則放棄之后的業(yè)務處理,設置本地的持久化消息標志狀態(tài)為“結束”狀態(tài)。否則,執(zhí)行后續(xù)的業(yè)務處理,設置本地的持久化消息標志狀態(tài)為“已發(fā)送”狀態(tài)。

  1. public void doServer (){ 
  2.       
  3. // 發(fā)送消息 
  4.  
  5. send (); 
  6.       
  7. // 執(zhí)行業(yè)務 
  8.      
  9. exec 
  10. ();  
  11.      
  12. // 更新消息狀態(tài) 
  13.  
  14. updateMsg (); 
  15.  

此外,消息隊列發(fā)生消息后,也可能從業(yè)務服務(消費者)宕機而無法消費。絕大多數(shù)消息中間件對于這種情況,例如 RabbitMQ、RocketMQ 等引入了 ACK 機制。注意的是,默認的情況下,采用自動應答,這種方式中消息隊列會發(fā)送消息后立即從消息隊列中刪除該消息。所以,為了確保消息的可靠投遞,我們通過手動 ACK 方式,如果從業(yè)務服務(消費者)因宕機等原因沒有發(fā)送 ACK,消息隊列會將消息重新發(fā)送,保證消息的可靠性。從業(yè)務服務處理完相關業(yè)務后通過手動 ACK 通知消息隊列,消息隊列才從消息隊列中刪除該持久化消息。那么,消息隊列如果一直重試失敗而無法投遞,就會出現(xiàn)消息主動丟棄的情況,我們需要如何解決呢?聰明的讀者可能已經(jīng)發(fā)現(xiàn),我們在上個步驟中,主業(yè)務服務已經(jīng)將要發(fā)送的消息持久化到本地數(shù)據(jù)庫。因此,從業(yè)務服務消費成功后,它也會向消息隊列發(fā)送一個通知消息,此時它是一個消息的生產(chǎn)者。主業(yè)務服務(消費者)接收到消息后,最終把本地的持久化消息標志狀態(tài)為“完成”狀態(tài)。說到這里,讀者應該可以理解到我們使用“正反向消息機制”確保了消息隊列可靠事件投遞。當然,補償機制也是必不可少的。定時任務會從數(shù)據(jù)庫掃描在一定時間內(nèi)未完成的消息并重新投遞。請參見圖 6-13。

注意的是,因為從業(yè)務服務可能收到消息處理超時或者服務宕機,以及網(wǎng)絡等原因?qū)е露㈥犃惺詹坏较⒌奶幚斫Y果,因此可靠事件投遞并且消息隊列確保事件傳遞至少一次。這里,從業(yè)務服務(消費者)需要保證冪等性。如果從業(yè)務服務(消費者)沒有保證接口的冪等性,將會導致重復提交等異常場景。此外,我們也可以獨立消息服務,將消息服務獨立部署,根據(jù)不同的業(yè)務場景共用該消息服務,降低重復開發(fā)服務的成本。

了解了“可靠事件模式”的方法論后,現(xiàn)在我們來看一個真實的案例來加深理解。首先,當用戶發(fā)起退款后,自動化退款服務會收到一個退款的事件消息,此時,如果這筆退款符合自動化退款策略的話,自動化退款服務會先寫入本地數(shù)據(jù)庫持久化這筆退款快照,緊接著,發(fā)送一條執(zhí)行退款的消息投遞到給消息隊列,消息隊列接受到消息后返回響應成功結果,那么自動化退款服務就可以執(zhí)行后續(xù)的業(yè)務邏輯。與此同時,消息隊列異步地把消息投遞給退款基礎服務,然后退款基礎服務執(zhí)行自己業(yè)務相關的邏輯,執(zhí)行失敗與否由退款基礎服務自我保證,如果執(zhí)行成功則發(fā)送一條執(zhí)行退款成功消息投遞到給消息隊列。最后,定時任務會從數(shù)據(jù)庫掃描在一定時間內(nèi)未完成的消息并重新投遞。這里,需要注意的是,自動化退款服務持久化的退款快照可以理解為需要確保投遞成功的消息,由“正反向消息機制”和“定時任務”確保其成功投遞。此外,真正的退款出賬邏輯在退款基礎服務來保證,因此它要保證冪等性,及出賬邏輯的收斂。當出現(xiàn)執(zhí)行失敗的狀態(tài)并且超過重試次數(shù)時,就說明這個任務永久失敗了,需要開發(fā)人員進行手工介入與排查問題。請參見圖 6-14。

總結一下,引入了消息隊列并不能保證可靠事件投遞,換句話說,由于網(wǎng)絡等各種原因而導致消息丟失不能保證其最終的一致性,因此,我們需要通過“正反向消息機制”確保了消息隊列可靠事件投遞,并且使用補償機制盡可能在一定時間內(nèi)未完成的消息并重新投遞。

開源項目的分布式事務實現(xiàn)解讀

開源項目中對分布式事務的應用有很多值得我們學習與借鑒的地方。本節(jié),我們就來對其實現(xiàn)進行解讀。

RocketMQ

Apache RocketMQ 是阿里開源的一款高性能、高吞吐量的分布式消息中間件。在歷年雙 11 中,RocketMQ 都承擔了阿里巴巴生產(chǎn)系統(tǒng)全部的消息流轉(zhuǎn),在核心交易鏈路有著穩(wěn)定和出色的表現(xiàn),是承載交易峰值的核心基礎產(chǎn)品之一。RocketMQ 同時存在商用版 MQ 可在阿里云上購買(https://www.aliyun.com/product/ons),阿里巴巴對于開源版本和商業(yè)版本,主要區(qū)別在于:會開源分布式消息所有核心的特性,而在商業(yè)層面,尤其是云平臺的搭建上面,將運維管控、安全授權、深度培訓等納入商業(yè)重中之重。

Apache RocketMQ 4.3 版本正式支持分布式事務消息。RocketMQ 事務消息設計主要解決了生產(chǎn)者端的消息發(fā)送與本地事務執(zhí)行的原子性問題,換句話說,如果本地事務執(zhí)行不成功,則不會進行 MQ 消息推送。那么,聰明的你可能就會存在疑問:我們可以先執(zhí)行本地事務,執(zhí)行成功了再發(fā)送 MQ 消息,這樣不就可以保證事務性的?但是,請你再認真的思考下,如果 MQ 消息發(fā)送不成功怎么辦呢?事實上,RocketMQ 對此提供一個很好的思路和解決方案。RocketMQ 首先會發(fā)送預執(zhí)行消息到 MQ,并且在發(fā)送預執(zhí)行消息成功后執(zhí)行本地事務。緊接著,它根據(jù)本地事務執(zhí)行結果進行后續(xù)執(zhí)行邏輯,如果本地事務執(zhí)行結果是 commit,那么正式投遞 MQ 消息,如果本地事務執(zhí)行結果是 rollback,則 MQ 刪除之前投遞的預執(zhí)行消息,不進行投遞下發(fā)。注意的是,對于異常情況,例如執(zhí)行本地事務過程中,服務器宕機或者超時,RocketMQ 將會不停的詢問其同組的其他生產(chǎn)者端來獲取狀態(tài)。請參見圖 6-15。

至此,我們已經(jīng)了解了 RocketMQ 的實現(xiàn)思路,如果對源碼實現(xiàn)感興趣的讀者,可以閱讀

  1. org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl
  2. #sendMessageInTransaction。 

ServiceComb

ServiceComb 基于華為內(nèi)部的 CSE(Cloud Service Engine) 框架開源而來,它提供了一套包含代碼框架生成,服務注冊發(fā)現(xiàn),負載均衡,服務可靠性(容錯熔斷,限流降級,調(diào)用鏈追蹤)等功能的微服務框架。其中,ServiceComb Saga 是一個微服務應用的數(shù)據(jù)最終一致性解決方案。

Saga 拆分分布式事務為多個本地事務,然后由 Saga 引擎負責協(xié)調(diào)。如果整個流程正常結束,那么業(yè)務成功完成;如果在這過程中實現(xiàn)出現(xiàn)部分失敗,那么Saga 引擎調(diào)用補償操作。Saga 有兩種恢復的策略 :向前恢復和向后恢復。其中,向前恢復對失敗的節(jié)點采取最大努力不斷重試,保證數(shù)據(jù)庫的操作最終一定可以保證數(shù)據(jù)一致性,如果最終多次重試失敗可以根據(jù)相關日志并主動通知開發(fā)人員進行手工介入。向后恢復對之前所有成功的節(jié)點執(zhí)行回滾的事務操作,這樣保證數(shù)據(jù)達到一致的效果。

Saga 與 TCC 不同之處在于,Saga 比 TCC 少了一個 Try 操作。因此,Saga 會直接提交到數(shù)據(jù)庫,然后出現(xiàn)失敗的時候,進行補償操作。Saga 的設計可能導致在極端場景下的補償動作比較麻煩,但是對于簡單的業(yè)務邏輯侵入性更低,更輕量級,并且減少了通信次數(shù),請參見圖 6-16。

 

ServiceComb Saga 在其理論基礎上進行了擴展,它包含兩個組件:alpha 和 omega。alpha 充當協(xié)調(diào)者,主要負責對事務的事件進行持久化存儲以及協(xié)調(diào)子事務的狀態(tài),使其得以最終與全局事務的狀態(tài)保持一致。omega 是微服務中內(nèi)嵌的一個 agent,負責對網(wǎng)絡請求進行攔截并向 alpha 上報事務事件,并在異常情況下根據(jù) alpha 下發(fā)的指令執(zhí)行相應的補償操作。在預處理階段,alpha 會記錄事務開始的事件;在后處理階段,alpha 會記錄事務結束的事件。因此,每個成功的子事務都有一一對應的開始及結束事件。在服務生產(chǎn)方,omega 會攔截請求中事務相關的 id 來提取事務的上下文。在服務消費方,omega 會在請求中注入事務相關的 id來傳遞事務的上下文。通過服務提供方和服務消費方的這種協(xié)作處理,子事務能連接起來形成一個完整的全局事務。注意的是,Saga 要求相關的子事務提供事務處理方法,并且提供補償函數(shù)。這里,添加 @EnableOmega 的注解來初始化 omega 的配置并與 alpha 建立連接。在全局事務的起點添加 @SagaStart 的注解,在子事務添加 @Compensable 的注解指明其對應的補償方法。使用案例:https://github.com/apache/servicecomb-saga/tree/master/saga-demo

  1.  @EnableOmega 
  2.  public class Application{ 
  3.  public static void main(String[] args) { 
  4.       SpringApplication.run(Application.class, args); 
  5.     } 
  6.  } 
  7.    
  8.  @SagaStart 
  9.  public void xxx() { } 
  10.   
  11.   
  12.  @Compensable 
  13.  public void transfer() { } 

現(xiàn)在,我們來看一下它的業(yè)務流程圖,請參見圖 6-17。

 

 

責任編輯:華軒 來源: 服務端思維
相關推薦

2023-11-06 09:06:54

分布式一致性數(shù)據(jù)

2023-10-08 08:29:31

2021-03-04 06:49:53

RocketMQ事務

2024-04-10 10:34:34

Cache系統(tǒng)GPU

2022-10-19 12:22:53

并發(fā)扣款一致性

2024-11-07 22:57:30

2025-11-11 02:11:00

微服務分布式事務

2025-02-10 03:00:00

2022-08-29 08:38:00

事務一致性

2019-08-30 12:46:10

并發(fā)扣款查詢SQL

2025-03-27 08:20:54

2020-08-05 08:46:10

NFS網(wǎng)絡文件系統(tǒng)

2024-12-26 15:01:29

2024-01-10 08:01:55

高并發(fā)場景悲觀鎖

2023-09-07 08:11:24

Redis管道機制

2020-10-28 11:15:24

EPaxos分布式性算法

2020-07-24 13:54:54

分布式一致性技術

2019-09-05 08:43:34

微服務分布式一致性數(shù)據(jù)共享

2023-01-14 17:36:39

微服務注冊中心數(shù)據(jù)

2020-04-01 15:50:17

TiDBMySQL數(shù)據(jù)庫
點贊
收藏

51CTO技術棧公眾號

欧美人与性动xxxx| 久久久久久久久免费| 久久久久日韩精品久久久男男| 无码人妻aⅴ一区二区三区玉蒲团| 9999在线视频| 国产精品污www在线观看| 99久久精品久久久久久ai换脸| 影音先锋亚洲天堂| 天天天综合网| 亚洲精品小视频在线观看| 国产精品视频中文字幕| 日韩伦理在线| 亚洲男人的天堂一区二区| 欧美韩国日本精品一区二区三区| 黄色一区二区视频| 亚洲成色精品| 久久这里有精品视频| 黄色正能量网站| 美女日韩一区| 欧美亚洲综合色| 香港三级韩国三级日本三级| 免费在线观看av网站| 久久综合久色欧美综合狠狠| 91中文字幕在线| 天天爱天天做天天爽| 激情亚洲网站| 欧美精品一区二区免费| 污污视频网站在线免费观看| 亚欧洲精品视频在线观看| 91精品国产综合久久小美女| 手机看片福利盒子久久| 91福利区在线观看| 久久日韩粉嫩一区二区三区| 国产精品久久久久久久久久久久冷 | 给我免费播放日韩视频| 欧美另类高清zo欧美| www.国产区| 在线观看特色大片免费视频| 一区二区久久久久| 五月天在线免费视频| 日p在线观看| 国产亚洲精久久久久久| 精品一卡二卡三卡四卡日本乱码 | 日本最新中文字幕| 亚洲手机视频| 欧美国产精品人人做人人爱| 波多野结衣不卡视频| 午夜激情久久| 久久久999国产精品| 911国产在线| 天天操综合网| 久久成人精品视频| 我要看一级黄色录像| 秋霞欧美视频| 日韩最新中文字幕电影免费看| 夜夜春很很躁夜夜躁| 精品久久成人| 少妇精69xxtheporn| 国产午夜精品久久久久久久久| 精品高清久久| 中文字幕在线视频日韩| 少妇愉情理伦三级| 婷婷综合视频| 欧美国产日本在线| 国产精品2020| 免费亚洲网站| 国产精品极品美女粉嫩高清在线| 加勒比在线一区| 男女男精品网站| 成人午夜激情网| 亚洲美女性生活| 91污在线观看| 日韩影视精品| 成人在线观看免费网站| 亚洲综合丝袜美腿| 1024精品视频| 激情小说亚洲| 日韩精品中文字幕在线一区| 国产清纯白嫩初高中在线观看性色| 岛国精品一区| 国产香蕉精品视频一区二区三区| 天堂av网手机版| 中文字幕日韩一区二区不卡| 高清欧美性猛交xxxx| 日韩综合在线观看| 国产一区二区三区av电影 | 欧美资源在线观看| 久草热在线观看| 国产精品中文有码| 欧美精品在线一区| 久cao在线| 欧美日韩精品国产| 中文字幕第100页| 国产成人精品福利| 国产一区二区三区高清在线观看| 欧美成人综合色| 巨乳诱惑日韩免费av| 91av免费看| 三级在线观看| 一区二区三区四区视频精品免费 | 国产精品成人aaaa在线| 天堂av在线一区| 不卡一区二区三区四区五区| 九色蝌蚪在线| 亚洲成av人片观看| 亚洲综合日韩欧美| 丝袜美腿一区二区三区动态图| 色婷婷**av毛片一区| 99久在线精品99re8热| 精品一区二区三区不卡| 欧美日韩亚洲在线| 蜜臀av在线| 欧美精品久久99| 中国美女乱淫免费看视频| 狠狠爱成人网| 成人乱色短篇合集| 成人在线观看免费| 欧美性videos高清精品| 性猛交╳xxx乱大交| 99久久99视频只有精品| 国产精品国产三级国产aⅴ浪潮 | 亚洲欧洲美洲国产香蕉| 欧美成人精品h版在线观看| 波多野结衣电车痴汉| 99视频热这里只有精品免费| 成人区一区二区| 国产精品一区三区在线观看| 一区二区三区天堂av| 可以在线观看av的网站| 成人福利在线看| 国产女人18毛片| 香蕉久久一区| 深夜福利91大全| 日韩xxx视频| 久久久久久久av麻豆果冻| 精品久久一二三| 99a精品视频在线观看| 久久91亚洲人成电影网站| 97精品人妻一区二区三区香蕉| 国产精品亲子伦对白| 99热手机在线| 久久中文亚洲字幕| 国产精品日日做人人爱| 337p日本欧洲亚洲大胆鲁鲁| 欧美性淫爽ww久久久久无| 亚洲高潮女人毛茸茸| 日韩精品免费视频人成| 日本免费高清一区| 3d欧美精品动漫xxxx无尽| 亚洲视频视频在线| 中文字幕免费高清网站| 国产目拍亚洲精品99久久精品| 美女网站免费观看视频| 日本欧美视频| 91亚洲人电影| 性欧美ⅴideo另类hd| 精品国产精品网麻豆系列| 精品在线视频免费| 久久婷婷综合激情| 一区二区三区国产免费| 欧美日韩一区二区三区视频播放| 国产精品自产拍在线观| 国产美女在线观看| 精品久久久久久久久久久久久久久久久| 欧美色图一区二区| 不卡一二三区首页| 色一情一乱一伦一区二区三区日本| 禁果av一区二区三区| 国产在线精品成人一区二区三区| 黄色网址视频在线观看| 亚洲精品一区二区三区蜜桃下载| 日韩av综合在线| 久久蜜桃一区二区| 在线不卡一区二区三区| 亚洲激情一区二区三区| 久久在线观看| 97超级碰在线看视频免费在线看| 欧美性孕妇孕交| 欧美美女一区二区三区| 国产一级二级三级视频| 久久久久成人黄色影片| 99re6在线观看| 亚洲经典自拍| 亚洲三区在线观看| 久久97久久97精品免视看秋霞| 国产精品爱啪在线线免费观看| 超碰在线最新| 亚洲欧美另类自拍| jizz国产视频| 欧美视频日韩视频| 日本三级免费看| 国产精品人人做人人爽人人添| 成人啪啪18免费游戏链接| 日韩高清欧美激情| 800av在线免费观看| 狠狠操综合网| 国产欧美精品一区二区三区| 欧美成人免费全部网站| 午夜精品视频在线| 美女隐私在线观看| 亚洲欧美另类人妖| 亚洲精品无码专区| 欧美日韩在线观看一区二区| 香蕉免费毛片视频| 亚洲猫色日本管| 男人的天堂av网| caoporen国产精品视频| 性久久久久久久久久久久久久| 国产一区二区精品| 男人的天堂avav| 婷婷精品进入| 日韩久久久久久久| 亚州av日韩av| 国产综合第一页| 久久九九精品视频| 国产日韩欧美电影在线观看| 日韩电影免费看| 午夜精品一区二区三区av| 91精品久久| 久久久国产精品亚洲一区| av中文字幕在线| 精品视频久久久久久久| 蜜臀av中文字幕| 欧美一级视频精品观看| 国产精品一区二区人人爽| 欧美亚洲一区二区在线| 中文字幕超碰在线| 午夜电影网一区| 精品一区二区三区四| 亚洲三级视频在线观看| 情侣偷拍对白清晰饥渴难耐| 亚洲国产精品传媒在线观看| 国产中年熟女高潮大集合| 97se亚洲国产综合自在线观| 97精品人妻一区二区三区蜜桃| 国产成人精品亚洲777人妖| 久久久久久久久久一区二区| 青青草视频一区| 香港日本韩国三级网站| 日本不卡视频在线观看| 91制片厂毛片| 久久精品国产免费| 成人日韩在线视频| 狠狠狠色丁香婷婷综合久久五月| 高清av免费看| 韩国三级中文字幕hd久久精品| 亚欧美在线观看| 国产综合久久久久久鬼色| 亚洲色图欧美自拍| 国产成人av一区二区三区在线观看| 亚洲一区二区中文字幕在线观看| 国产一区二区免费看| 日本一区二区三区在线免费观看| 国产原创一区二区三区| 国产高潮失禁喷水爽到抽搐| 成人av综合一区| 人人妻人人藻人人爽欧美一区| 国产日韩欧美一区二区三区乱码 | 成人免费在线观看av| 亚洲欧洲精品一区二区三区波多野1战4| 日韩精品一区二区久久| 免费观看黄色大片| 激情婷婷欧美| 欧美亚洲日本在线观看| 精品在线播放午夜| 波多野结衣三级视频| av福利精品导航| 亚洲无人区码一码二码三码的含义| 国产精品你懂的| 69av视频在线| 精品久久久免费| 中文亚洲av片在线观看| 91精品久久久久久久99蜜桃 | 欧美成人一级| 精品一区二区国产| 色999日韩| 波多野结衣av一区二区全免费观看| 99亚洲视频| 欧美精品久久久久久久久25p| 国产成人超碰人人澡人人澡| 亚洲黄色在线网站| 国产精品传媒视频| 日韩美女视频网站| 欧美日韩高清一区| 五月天婷婷在线播放| 日韩视频免费在线观看| 高清毛片在线观看| 国产欧美日韩综合精品| 久久九九热re6这里有精品| 日韩欧美精品一区二区三区经典| 国产一区清纯| 黄色国产小视频| 粉嫩av一区二区三区粉嫩| 人人妻人人澡人人爽| 亚洲一区在线观看网站| 国产情侣小视频| 337p日本欧洲亚洲大胆色噜噜| 国产日本在线| 97在线看免费观看视频在线观看| 国产综合色激情| 久久精品五月婷婷| 欧美日韩综合| 中文字幕 91| 91视频观看视频| 青青草原国产视频| 欧美日韩免费在线视频| 欧美中文在线| 国a精品视频大全| 亚洲日本免费电影| 日产精品一线二线三线芒果| 黄色亚洲在线| 九九热视频免费| 国产免费观看久久| 中文字幕黄色片| 亚洲第一福利网站| www久久日com| 91精品久久久久久久| 精品久久久久久久久久久aⅴ| 黄色一级在线视频| 国产成人h网站| 特级片在线观看| 这里只有精品99re| 一本一道波多野毛片中文在线| 欧美一级电影免费在线观看| 国产在线播放精品| 国产美女永久无遮挡| 狠狠色狠狠色综合日日91app| 手机av在线不卡| 欧美三电影在线| 色三级在线观看| 国产精自产拍久久久久久| 精品黄色一级片| 午夜精品在线免费观看| 欧美国产精品中文字幕| 亚洲成熟少妇视频在线观看| 亚洲精品永久免费精品| 亚洲午夜天堂| 欧美最大成人综合网| 日韩xxx高潮hd| 久久精品人人做人人爽97 | 色婷婷激情一区二区三区| 偷拍精品一区二区三区| 97色在线观看| 亚洲免费成人av在线| 欧美日韩激情视频在线观看| 99re亚洲国产精品| 国产精品人人人人| 国产一区二区三区18| julia一区二区三区中文字幕| 色综合666| 久久 天天综合| 欧美性猛交xxxxx少妇| 欧美成人精精品一区二区频| 蜜桃成人365av| 精品中文字幕人| 日韩中文字幕麻豆| 免费精品在线视频| 欧美一区二区免费观在线| 日本不卡影院| 久久久久一区二区| 日韩在线a电影| 波多野结衣在线网址| 日韩免费视频线观看| 国产高清中文字幕在线| 日本不卡在线观看| 韩国午夜理伦三级不卡影院| 久久综合成人网| 日韩成人高清在线| 欧美videos粗暴| 国产又粗又猛又爽又黄的网站| 99riav久久精品riav| 在线观看中文字幕2021| 欧美日韩爱爱视频| 自拍自偷一区二区三区| 亚洲综合日韩欧美| 亚洲图片欧美色图| 粉嫩一区二区三区国产精品| 91色视频在线观看| 国产精品亚洲欧美| 波多野结衣喷潮| 日韩黄色av网站| 日韩成人精品一区二区三区| 蜜臀av无码一区二区三区| 久久久天堂av| 成 人片 黄 色 大 片| 欧美在线视频免费| 正在播放日韩欧美一页| 3d动漫精品啪啪一区二区下载| 欧美日韩的一区二区| 美女91在线看| 中文字幕第一页亚洲| 91视频.com| 亚洲第一天堂影院| 国产精品视频免费观看www| 亚洲高清久久| www.97视频| 亚洲视频在线看| 东京久久高清| 久久婷五月综合| 色哟哟精品一区|