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

硬核”實戰(zhàn)分享:企業(yè)微服務(wù)架構(gòu)設(shè)計及實施的六大難點剖析

開發(fā) 架構(gòu)
現(xiàn)如今不管是傳統(tǒng)企業(yè)還是互聯(lián)網(wǎng)公司都在談?wù)撐⒎?wù),微服務(wù)架構(gòu)已經(jīng)成為了互聯(lián)網(wǎng)的熱門話題,同時,微服務(wù)的開發(fā)框架比如Dubbo、SpringCloud等也是在高頻迭代中,以滿足層出不窮的技術(shù)需求。

前言

現(xiàn)如今不管是傳統(tǒng)企業(yè)還是互聯(lián)網(wǎng)公司都在談?wù)撐⒎?wù),微服務(wù)架構(gòu)已經(jīng)成為了互聯(lián)網(wǎng)的熱門話題,同時,微服務(wù)的開發(fā)框架比如Dubbo、SpringCloud等也是在高頻迭代中,以滿足層出不窮的技術(shù)需求。當(dāng)企業(yè)遇到系統(tǒng)性能瓶頸、項目進(jìn)度推進(jìn)乏力、系統(tǒng)運維瓶頸的時候,都會試圖把微服務(wù)當(dāng)著一根救命稻草,認(rèn)為只要實施微服務(wù)架構(gòu)了,所有的問題都迎刃而解。然而,在實施微服務(wù)過程中出現(xiàn)的各種各樣問題如何優(yōu)雅的去解決呢?本文接下來將介紹如何以“硬核”的方式去解決微服務(wù)改造過程中遇到的難點問題。

[[323194]]

一、服務(wù)拆分粒度問題

服務(wù)到底怎么拆分合適

在微服務(wù)架構(gòu)中“服務(wù)”的定義是指分布式架構(gòu)下的基礎(chǔ)單元,包含了一組特定的功能。服務(wù)拆分是單體應(yīng)用轉(zhuǎn)化成微服務(wù)架構(gòu)的第一步,服務(wù)拆分是否合理直接影響到微服務(wù)架構(gòu)的復(fù)雜性、穩(wěn)定性以及可擴(kuò)展性。服務(wù)拆分過小,會導(dǎo)致不必要的分布式事務(wù)產(chǎn)生,而且整個調(diào)用鏈過程也會變長,反之,如果服務(wù)拆分過大,會逐步演變?yōu)閱误w應(yīng)用,不能發(fā)揮微服務(wù)的優(yōu)勢。判斷一個服務(wù)拆分的好壞,就看微服務(wù)拆分完成后是否具備服務(wù)的自治原則,如果把復(fù)雜單體應(yīng)用改造成一個一個松耦合式微服務(wù),那么按照業(yè)務(wù)功能分解模式進(jìn)行分解是最簡單的,只需把業(yè)務(wù)功能相似的模塊聚集在一起。比如:

  1. 用戶管理:管理用戶相關(guān)的信息,例如注冊、修改、注銷或查詢、統(tǒng)計等。
  2. 商品管理:管理商品的相關(guān)信息。

業(yè)務(wù)功能分解模式另外的優(yōu)勢在于在初級階段服務(wù)拆分不會太小,等到業(yè)務(wù)發(fā)展起來后可以再根據(jù)子域方式來拆分,把獨立的服務(wù)再拆分成更小的服務(wù),最后到接口級別服務(wù)。

 

以用戶管理舉例,在初始階段的做服務(wù)拆分的時候,把用戶管理拆分為用戶服務(wù),且具備了用戶的增刪改查功能,在互聯(lián)網(wǎng)中流量獲客是最貴的,運營團(tuán)隊通過互聯(lián)網(wǎng)投放廣告獲客,用戶在廣告頁上填寫手機號碼執(zhí)行注冊過程,如果此時注冊失敗或者注冊過程響應(yīng)時間過長,那么這個客戶就可能流失了,但是廣告的點擊費用產(chǎn)生了,無形中形成了資源的浪費。當(dāng)用戶規(guī)模上升之后需要對增刪改查功能做優(yōu)先級劃分,所以此時需要按方法維度來拆分服務(wù),把用戶服務(wù)拆分為用戶注冊服務(wù)(只有注冊功能),用戶基礎(chǔ)服務(wù)(修改、查詢用戶信息)。

 哪些功能需要被拆分成服務(wù)

無論是單體應(yīng)用重構(gòu)為微服務(wù)架構(gòu),還是在微服務(wù)架構(gòu)體系下有新增需求,都會面臨這些功能或者新增需求是否需要被拆分為服務(wù)。雖然沒有相關(guān)規(guī)定,但是可以遵循服務(wù)拆分的方法論:當(dāng)一塊業(yè)務(wù)不依賴或極少依賴其它服務(wù),有獨立的業(yè)務(wù)語義,為超過 2 個或以上的其他服務(wù)或客戶端提供數(shù)據(jù),應(yīng)該被拆分成一個獨立的服務(wù)模,而且拆分的服務(wù)要具備高內(nèi)聚低耦合。所謂的高內(nèi)聚是指一個組件中各個元素互相依賴的程度,是衡量某個模塊或者類中各個代碼片段之間關(guān)聯(lián)強度的標(biāo)準(zhǔn),比如用戶服務(wù),只會提供用戶相關(guān)的增刪改查信息,假如還關(guān)聯(lián)了用戶訂單相關(guān)的信息,那就說明這個功能不是高內(nèi)聚的功能,拆分的不好。

低耦合是指系統(tǒng)中每個組件很少知道或者不知道其他獨立組件的定義,其中的組件可以被其他提供相同功能的組件替代。

二、緩存到底怎么用才更有效

緩存需要在哪層增加

微服務(wù)架構(gòu)下,原本單體應(yīng)用被劃分為聚合層和原子服務(wù)層,每一層所負(fù)責(zé)的功能各不相同。

 

1、聚合層:收到終端請求后,聚合多個原子服務(wù)數(shù)據(jù),按接口要求把聚合后的數(shù)據(jù)返回給終端,需要注意點是聚合層不會和數(shù)據(jù)庫交互;

2、原子服層:數(shù)據(jù)庫交互層,實現(xiàn)數(shù)據(jù)的增刪改查,結(jié)合緩存和工具保障服務(wù)的高響應(yīng);要遵循單表原則,禁止2張以上的表做join查詢,如有分庫分表,那么對外要屏蔽具體規(guī)則,提供服務(wù)接口供外部調(diào)用。

如果使用到緩存,那么到底在聚合層加還是原子層加還是其他呢?應(yīng)該遵循“誰構(gòu)建,誰運維”這一理念,是否使用緩存應(yīng)該由對應(yīng)的開發(fā)人員自行維護(hù),也就是說聚合層和原子層都需要增加緩存。一般來說聚合層和原子層由不同的團(tuán)隊開發(fā),聚合層和業(yè)務(wù)端比較貼近,需要了解業(yè)務(wù)流程更好的服務(wù)業(yè)務(wù),和App端交互非常多,重點是合理設(shè)計的前后端接口,減少App和后端交互次數(shù)。原子服務(wù)則是關(guān)注性能,屏蔽數(shù)據(jù)庫操作,屏蔽分庫分表等操作。在聚合層推薦使用多級緩存,即本地緩存+分布式緩存,本地緩存不做緩存數(shù)據(jù)的變更,使用TTL自動過期時間來自動更新緩存內(nèi)的數(shù)據(jù)。

緩存使用過程中不可避免的問題

在使用緩存的時候不可避免的會遇到緩存穿透、緩存擊穿、緩存雪崩等場景,針對每種場景的時候需要使用不同的應(yīng)對策略,從而保障系統(tǒng)的高可用性。

1、緩存穿透:是指查詢一個一定不存在緩存key,由于緩存是未命中的時候需要從數(shù)據(jù)庫查詢,正常情況下查不到數(shù)據(jù)則不寫入緩存,就會導(dǎo)致這個不存在的數(shù)據(jù)每次請求都要到數(shù)據(jù)庫去查詢,造成緩存穿透,有2個方案可以解決緩存穿透:

1) 可以使用布隆過濾器方案,系統(tǒng)啟動的時候?qū)⑺汛嬖诘臄?shù)據(jù)哈希到一個足夠大的bitmap中,當(dāng)一個一定不存在的數(shù)據(jù)請求的時候,會被這個bitmap攔截掉,從而避免了對底層數(shù)據(jù)庫的查詢壓力。

  1. @Component 
  2. public class BloomFilterCache { 
  3.     public static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), 10000); 
  4.     @PostConstruct 
  5.     public  void init(){ 
  6. List<Integer> list=Lists.newArrayList(); //初始化加載所有的需要被緩存的數(shù)據(jù)ID 
  7.         list.forEach(id ->bloomFilter.put(id)); 
  8.     } 
  9. public  boolean addKey(Integer key){ 
  10.      return bloomFilter.put(key); 
  11.     public  boolean isCached(Integer key){ 
  12.         return bloomFilter.mightContain(key); 
  13.     } 

這里的BloomFilter選用guava提供的第三方包,服務(wù)啟動的時候,init方法會加載所有可以被緩存的數(shù)據(jù),把id都放入boolmFilter中,當(dāng)有新增數(shù)據(jù)的時候,執(zhí)行addKey把新增的數(shù)據(jù)放入BoolmFilter過濾器中。

當(dāng)在需要使用緩存的地方先調(diào)用isCached方法,如果返回true表示正常請求,否則拒絕。

2) 返回空值:如果一個查詢請求查詢數(shù)據(jù)庫后返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在,還是系統(tǒng)故障),仍然把這個空結(jié)果進(jìn)行緩存,但它的過期時間會很短,比如1分鐘,但是這種方法解決不夠徹底。

2、緩存擊穿:緩存key在某個時間點過期的時候,剛好在這個時間點對這個Key有大量的并發(fā)請求過來,請求命中緩存失敗后會通過DB加載數(shù)據(jù)并回寫到緩存,這個時候大并發(fā)的請求可能會瞬間把后端DB壓垮,解決方案也很簡單通過加鎖的方式讀取數(shù)據(jù),同時寫入緩存。

  1. Object [] objects={0,1,2,3,4,5,6,7,8,9}; 
  2.     public List<String> getData(Integer id) throws InterruptedException { 
  3.         List<String> result = new ArrayList<String>(); 
  4.         result = getDataFromCache(id); 
  5.         if (result.isEmpty()) { 
  6.                 int objLength= objects.length; 
  7.                 synchronized (objects[id% objects.length]) { 
  8.                     result = getDataFromDB(id); 
  9.                     setDataToCache(result); 
  10.                } 
  11.               }  
  12.         return result; 

這里加鎖的方法使用的是Object數(shù)組,是希望因不同的id不會因為從數(shù)據(jù)庫加載數(shù)據(jù)被阻塞,例如id=1、id=2、id=3的key同時在緩存中消失,微服務(wù)路由策略剛好都把這些請求都路由到同一臺機器上,假設(shè)查詢DB需要50毫秒,如果僅使用synchronized(object){……}則id=3的請求會被阻塞,需要等等150毫秒才能返回結(jié)果,但是使用上述方法則只需要50毫秒出結(jié)果。其中objects數(shù)據(jù)的大小可以根據(jù)DB能承載的并發(fā)量以及原子服務(wù)數(shù)量綜合考慮。

3、緩存雪崩:是指在設(shè)置緩存時使用了相同的過期時間,導(dǎo)致緩存在某一時刻同時失效,所有的查詢都請求到數(shù)據(jù)庫上,導(dǎo)致應(yīng)用系統(tǒng)產(chǎn)生各種故障,這樣情況稱之為緩存雪崩,可以通過限流的方式來限制請求數(shù)據(jù)庫的次數(shù)。

三、串行化并行解決效率問題

一個應(yīng)用功能被拆分成多個服務(wù)之后,原本調(diào)用一個接口就能完成的功能如今變成需要調(diào)用多個服務(wù),如果按順序逐個調(diào)用的話,使用微服務(wù)改造后的接口會比原始接口響應(yīng)時間更長,因此要把原本串行調(diào)用的服務(wù)修改為并行調(diào)用,同時原本通過SQL的join多表聯(lián)合查詢操作變成單表操作,然后在聚合層的內(nèi)存中做拼接。

 

例如接口A,需要調(diào)用S1(耗時200毫秒),S2(耗時180毫秒),S3(耗時320毫秒)這3個接口,使用串行調(diào)用方式,那么接口A累計耗時=SUM(S1+S2+S3)=700毫秒。為了讓響應(yīng)時間更短,就需要把這些串行調(diào)用的方式更改為并行調(diào)用的方式,并行調(diào)用方式調(diào)用接口A累計耗時為MAX(S1,S2,S3)=320毫秒。可以使用jdk8提供的CompletableFuture方法,偽代碼如下:

  1. CompletableFuture<DTOS1> futureS1 = CompletableFuture.supplyAsync(() -> { 
  2.         S1接口 },executor); 
  3. CompletableFuture<DTOS2> futureS2 = CompletableFuture.supplyAsync(() -> { 
  4.         S2接口  },executor); 
  5. CompletableFuture<DTOS3> futureS3 = CompletableFuture.supplyAsync(() -> { 
  6.         S3接口 },executor); 
  7. CompletableFuture.allOf(futureS1, futureS2, futureS3).get(500, TimeUnit.MILLISECONDS); 

此時就把原本串聯(lián)調(diào)用的服務(wù)變成并行調(diào)用,節(jié)約了接口請求時間,但卻引發(fā)一個新的問題,內(nèi)部接口調(diào)用換成網(wǎng)絡(luò)RPC調(diào)用,會導(dǎo)致服務(wù)調(diào)用的不確定性,引起接口不穩(wěn)定。

四、服務(wù)的熔斷降級處理

把內(nèi)部接口調(diào)用替換為RPC調(diào)用,在調(diào)用過程中可能會出現(xiàn)網(wǎng)絡(luò)抖動、網(wǎng)絡(luò)異常,當(dāng)服務(wù)提供方(Provide)變得不可用或者響應(yīng)慢時,也會影響到服務(wù)調(diào)用方的服務(wù)性能,甚至可能會使得服務(wù)調(diào)用方占滿整個線程池,導(dǎo)致這個應(yīng)用上其它的服務(wù)也受影響,從而引發(fā)更嚴(yán)重的雪崩效應(yīng)。因此需要梳理所有服務(wù)提供者并把服務(wù)分級,同時引入了Hystrix或則Sentinel做服務(wù)熔斷和降級處理,目的如下:

降級目的:業(yè)務(wù)高峰期的生活,去掉非核心鏈路,保障主流程正常運行;

熔斷目的:防止應(yīng)用程序不斷地嘗試可能超時或者失敗的服務(wù),能達(dá)到應(yīng)用程序正常執(zhí)行而不需要等待下游修正服務(wù)。

熔斷器需要做以下設(shè)置:

設(shè)置錯誤率:可以設(shè)置每個服務(wù)錯誤率到達(dá)制定范圍后開始熔斷或降級;

具備人工干預(yù):可以人工手動干預(yù),主動觸發(fā)降級服務(wù);

設(shè)置時間窗口:可配置化來設(shè)置熔斷或者降級觸發(fā)的統(tǒng)計時間窗口;

具備主動告警:當(dāng)接口熔斷之后,需要主動觸發(fā)短信告知當(dāng)前熔斷的接口信息;

以Sentinel為例,它提供了很多微服務(wù)框架的適配器,如果是Dubbo應(yīng)用,提供了SentinelDubboConsumerFilter和SentinelDubboProviderFilter等Filter,企業(yè)零開發(fā)即可快速接入Sentinel完成對服務(wù)的保護(hù),只需要在工程的pom.xml里面引入

  1. <dependency> 
  2.     <groupId>com.alibaba.csp</groupId> 
  3.     <artifactId>sentinel-apache-dubbo-adapter</artifactId> 
  4.     <version>1.7.2</version> 
  5. </dependency> 

如果是Spring Cloud,只需要在pom.xml里面引入以下內(nèi)容即可快速接入

  1. <dependency> 
  2.     <groupId>com.alibaba.cloud</groupId> 
  3.     <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> 
  4. </dependency> 

這里需要注意2點:

1) 要先梳理服務(wù)做好服務(wù)分級,降級、熔斷是針對非核心流程,如核心流程處理能力不滿足業(yè)務(wù)需要,則需要擴(kuò)充或者優(yōu)化核心流程;

2) 降級是動態(tài)配置后立即生效,而非手動去修改源代碼后再發(fā)布服務(wù)服務(wù);

五、接口冪等處理

在分布式環(huán)境中,網(wǎng)絡(luò)環(huán)境比較復(fù)雜,如前端操作抖動、APP自動重試、網(wǎng)絡(luò)故障、消息重復(fù)、響應(yīng)速度慢等原因,對接口的重復(fù)調(diào)用概率會比單體應(yīng)用環(huán)境下更大,所以說重復(fù)消息在分布式環(huán)境中很難避免,所以在分布式架構(gòu)中,要求所有的調(diào)用過程必須具備冪等性,即用戶對于同一操作發(fā)起的一次請求或者多次請求的結(jié)果是一致的,不會因為多次點擊而產(chǎn)生了副作用。接口的冪等性實際上就是接口可重復(fù)調(diào)用,在調(diào)用方多次調(diào)用的情況下,接口最終得到的結(jié)果是一致的。冪等的處理方案有多種,比如冪等表、樂觀鎖、token令牌,但是在實際過程中并不是每個場景都需要做冪等處理。例如有些場景自身具備冪等性

  1. select * from user_order where order_num=? 

無論查詢多次其結(jié)果不會因為查詢次數(shù)導(dǎo)致結(jié)果有影響,所以select的操作天然具備冪等性,無需處理。

  1. update sys_user set user_state=1 where user_id=? 

直接賦值型的update語句操作多次不會影響結(jié)果,所以此類update操作也天然具備冪等性。

但是當(dāng)以下語句多次調(diào)用的時候會引起數(shù)據(jù)不一致,因此需要對冪等處理

  1. insert into user_order(id,order_num,user_id) values(?,?,?) 
  2.  
  3. update user_point set point = score +20 where user_id=? 

唯一主鍵機制:這個機制是利用了數(shù)據(jù)庫的主鍵唯一約束的特性,解決了在insert場景時冪等問題。但主鍵的要求不是自增的主鍵,而是需要業(yè)務(wù)生成全局唯一的主鍵,如果有分庫分表了那么唯一主鍵機制就沒有效果了。

冪等表:利用數(shù)據(jù)庫唯一索引做防重處理,當(dāng)?shù)谝淮尾迦胧菦]有問題的,第二次在進(jìn)行插入會因為唯一索引報錯,從而達(dá)到攔截的目的。

樂觀鎖:通過version來判斷當(dāng)前請求的數(shù)據(jù)是否有變動,例如

  1. update user_point set point = point + 20, version = version + 1 where user_id=100 and version=20 

Token令牌:為防止重復(fù)提交, 為每次請求生成請求唯一鍵,服務(wù)端對每個唯一鍵進(jìn)行生命周期管控,規(guī)定時間內(nèi)只允許一次請求,非第一次請求都屬于重復(fù)提交,后端要給出單獨生成token令牌接口,前端要在每次調(diào)用時候先獲取token令牌。

無論是唯一主鍵機制還是冪等表都存在唯一鍵的要求,以電商下單場景為例,看看如何來做冪等處理。例如用戶在App下單后,下單請求首先通過Nginx反向代理,轉(zhuǎn)發(fā)到聚合層,聚合層再調(diào)用原子服務(wù),其中訂單號為全局唯一。這種場景訂單號誰來生成,如何來保障用戶下單的冪等性呢?

 

  • 假設(shè)原子服務(wù)生成訂單號:如果聚合層第一次調(diào)用原子服務(wù)超時了,此時原子服務(wù)已經(jīng)生成了訂單號為A并寫入訂單表。因第一次超時,聚合層會再次發(fā)送請求調(diào)用原子服務(wù),此時原子服務(wù)再生成訂單號B并寫入訂單表,導(dǎo)致一次下單生成2份訂單數(shù)據(jù)。
  • 假設(shè)聚合層生成訂單號:如果訂單號是聚合層生成,理論上多次調(diào)用原子層都是同一個訂單號,具備冪等性,但是如何Nginx重復(fù)調(diào)用聚合層的話,仍然會導(dǎo)致一次申請多個訂單的情況。
  • 假設(shè)Nginx生成訂單號:如果Nginx生成訂單號,理論上多次調(diào)用原聚合層都是同一個訂單號,具備冪等性,但是如何App端重復(fù)調(diào)用Nginx的話,任然會導(dǎo)致一次申請多個訂單的情況。
  • 假設(shè)App生成訂單號:最后只能是App針對每一次下單生成一個訂單號,并和請求報文一起發(fā)送給后端。因為每個App根據(jù)規(guī)則生成訂單號可能會導(dǎo)致訂單號重復(fù)。

比較優(yōu)雅的解決方案是App在下單的時候生成以一串針對該用戶唯一的序列(sequenceId)和下單請求一起發(fā)送到后端,聚合層首先判斷sequenceId是否存在,如存在則直接返回成功,否則生成訂單號并把sequenceId寫入緩存,然后調(diào)用原子服務(wù)插入訂單數(shù)據(jù),如果原子服務(wù)寫入訂單成功則刪除緩存中的sequenceId。通過這里例子可以看到,在微服務(wù)中解決任何問題不能僅看一小塊,需要從全局角度來看待問題。

六、如何保障數(shù)據(jù)一致性

因事物所具備的四大特性ACID(原子性、一致性、隔離性、持久性),使用事物是保障數(shù)據(jù)一致性的有效手段。例如用戶在平臺上下單訂購某種業(yè)務(wù)的時候,需要涉及到訂單服務(wù),積分服務(wù),在單體模式下這種業(yè)務(wù)非常容易實現(xiàn),通過事務(wù)即可完成,偽代碼如下:

  1. @Transaction  
  2. public Boolean createOrder(OrderDTO order){ 
  3. 創(chuàng)建訂單 
  4. 增加積分 

然而在微服務(wù)的情況下,原本通過簡單事務(wù)處理的卻變得非常復(fù)雜,訂單、積分被拆分為不同的服務(wù)部署在獨立的服務(wù)器上,并且數(shù)據(jù)存在在不同的數(shù)據(jù)庫中,傳統(tǒng)的事物處理模式已經(jīng)失效,這里又引出了分布式框架下數(shù)據(jù)的一致性要求。在談數(shù)據(jù)一致性要求的時候有2個非常重要的理論即CAP定理和Base理論:

1、CAP定理:C表示一致性,也就是所有用戶看到的數(shù)據(jù)是一樣的,A表示可用性,是指總能找到一個可用的數(shù)據(jù)副本,P表示分區(qū)容錯性,能夠容忍網(wǎng)絡(luò)中斷等故障。

2、BASE理論:BA指的是基本業(yè)務(wù)可用性,支持分區(qū)失敗,當(dāng)分布式系統(tǒng)出現(xiàn)故障的時候,允許損失一部分可用性,例如在電商大促的時候,對一些非核心鏈路的功能進(jìn)行降級處理來提高系統(tǒng)的可用性,S表示柔性狀態(tài),允許系統(tǒng)存在中間狀態(tài),這個中間狀態(tài)不會影響系統(tǒng)整體可用性。比如,數(shù)據(jù)庫讀寫分離,寫庫同步到讀庫(主庫同步到從庫)會有一個延時,E表示最終一致性,數(shù)據(jù)最終是一致的,例如主從同步雖然有短暫的數(shù)據(jù)不一致情況,但是最終數(shù)據(jù)還是一致的。

分布式系統(tǒng)中最重要的是讓系統(tǒng)穩(wěn)定并滿足業(yè)務(wù)需求,而不是追求高度抽象,絕對的系統(tǒng)特性。針對分布式事物目前開源方案有阿里巴巴開源的無侵入分布式解決方案Seata,它為用戶提供了 AT、TCC、SAGA 和 XA 事務(wù)模式,為用戶打造一站式的分布式解決方案,例如最簡單的AT模式,特點就是對業(yè)務(wù)無入侵式,分二階段提交,通過簡單配置并在接口上增加@GlobalTransactional即可完成分布式事物,但是在性能上有衰減。在實際中可以通過本地事務(wù)和發(fā)送MQ消息這種柔性事物方式來解決分布式事物所面臨的問題,既能保障服務(wù)的穩(wěn)定性又能保障調(diào)用效率的高效性,在MQ可以使用Apache的RocketMQ所提供的事物消息和本地事物表結(jié)合。其中以下概念需要理解下:

1、半事務(wù)消息:暫不能投遞的消息,發(fā)送方已經(jīng)成功地將消息發(fā)送到了消息隊列服務(wù)端,但是服務(wù)端未收到生產(chǎn)者對該消息的二次確認(rèn),此時該消息被標(biāo)記成“暫不能投遞”狀態(tài),處于該種狀態(tài)下的消息即半事務(wù)消息。

2、消息回查:由于網(wǎng)絡(luò)閃斷、生產(chǎn)者應(yīng)用重啟等原因,導(dǎo)致某條事務(wù)消息的二次確認(rèn)丟失,消息隊列服務(wù)端通過掃描發(fā)現(xiàn)某條消息長期處于“半事務(wù)消息”時,需要主動向消息生產(chǎn)者詢問該消息的最終狀態(tài)(Commit 或是 Rollback),該詢問過程即消息回查。

整個流程如下:聚合服務(wù)收到創(chuàng)建訂單請求的時候,會發(fā)送一個事務(wù)性的MQ消息,注意這里的消息只是發(fā)送到消息隊列,并沒有收到生產(chǎn)者的確認(rèn),因此消息處于半事物狀態(tài),消息隊列收到消息后會回調(diào)生產(chǎn)者,這個時候就可以完成本地事物(寫訂單表,寫日志表),如果事物提交成功,則把發(fā)送確認(rèn)消息給MQ。針對下單這種情況,必須要考慮以下幾種異常:

1、 App調(diào)用下單接口,此時發(fā)送MQ消息異常則直接返回下單失敗,App需要重新點擊下單

2、 MQ回調(diào)生產(chǎn)者的時候,生產(chǎn)者開始寫入訂單數(shù)據(jù),此時事物發(fā)生異常,則返回UNKNOW狀態(tài),不要返回ROLLBACK_MESSAGE,因為App已經(jīng)收到下單成功的通知了,不允許再出現(xiàn)下單失敗的情況;

3、 MQ長時間(默認(rèn)1分鐘,時間可調(diào)整)沒有收到生產(chǎn)者確認(rèn)提交消息,會進(jìn)行消息的回查

相關(guān)代碼具體如下:

  1. public class TransactionOrderProducer { 
  2.     public void init(){ 
  3.         producer = new TransactionMQProducer(group); 
  4.         producer.setTransactionListener(orderTransactionListener); 
  5.         this.start(); 
  6.     } 
  7.     //事務(wù)消息發(fā)送 
  8.     public TransactionSendResult send(String data, String topic) throws MQClientException { 
  9.         Message message = new Message(topic,data.getBytes()); 
  10.         return this.producer.sendMessageInTransaction(message, null); 
  11.     } 

當(dāng)消息隊列收到消息后,會回調(diào)orderTransactionListener的executeLocalTransaction方法,在這個方法里面createOrder會執(zhí)行訂單入庫的操作,同時會在日志表總記錄一條數(shù)據(jù)。

  1. public class OrderTransactionListener implements TransactionListener { 
  2.     @Override 
  3. public LocalTransactionState executeLocalTransaction(Message message, Object o) {   
  4.         LocalTransactionState state; 
  5.         try{ 
  6.             String order = new String(message.getBody());          
  7.             orderService.createOrder(order,message.getTransactionId()); 
  8.             state = LocalTransactionState.COMMIT_MESSAGE; 
  9.         }catch (Exception e){ 
  10.             state = LocalTransactionState.UNKNOW; 
  11.         } 
  12.         return state; 
  13.     } 
  14.     @Override 
  15.     public LocalTransactionState checkLocalTransaction(MessageExt messageExt) { 
  16.         LocalTransactionState state; 
  17.         String transactionId = messageExt.getTransactionId(); 
  18.         if (transactionService.check(transactionId)){ 
  19.             state = LocalTransactionState.COMMIT_MESSAGE; 
  20.         }else { 
  21.             String body = new String(messageExt.getBody()); 
  22.             OrderDTO order = JSONObject.parseObject(body, OrderDTO.class); 
  23.             try { 
  24.                 orderService.createOrder(order, messageExt.getTransactionId()); 
  25.             }catch (Exception e){ 
  26.                 return LocalTransactionState.UNKNOW; 
  27.             } 
  28.             state = LocalTransactionState.COMMIT_MESSAGE; 
  29.         } 
  30.         return state; 
  31.     } 

積分服務(wù)只需要消費普通MQ的消息即可完成分布式事物,在這里把原先要求一致性的事物寫入訂單和增加積分轉(zhuǎn)換為先寫入訂單,積分服務(wù)消費MQ來增加積分,達(dá)到柔性事物的機制。

結(jié)語

以上六種常見問題是在實施微服務(wù)中最容易遇到的問題,當(dāng)然解決辦法也是因人而異,但是遇到問題的時候不能僅僅去看一個點,比如冪等問題,如果僅看一個技術(shù)點的話,很難優(yōu)雅的處理冪等問題。總的來說實施微服務(wù)不難,因為已經(jīng)有很多成功案例可以借鑒,遇到問題的時候多去想,從多個角度去考慮,從全局去考慮。

 潘志偉,某金融企業(yè),擁有十多年從業(yè)經(jīng)驗,精通微服務(wù)架構(gòu),精通大數(shù)據(jù),擁有億級用戶平臺架構(gòu)經(jīng)驗,萬級并發(fā)的API網(wǎng)關(guān)經(jīng)驗。

責(zé)任編輯:武曉燕 來源: twt企業(yè)IT社區(qū)
相關(guān)推薦

2020-10-19 10:34:56

CIOERP技術(shù)

2025-03-27 00:25:55

微服務(wù)架構(gòu)技術(shù)

2020-09-04 15:07:54

網(wǎng)絡(luò)威脅情報CTI網(wǎng)絡(luò)攻擊

2022-10-19 14:23:17

2019-08-02 08:50:47

API架構(gòu)微服務(wù)

2019-01-07 08:00:00

2021-04-01 14:54:12

云計算邊緣計算物聯(lián)網(wǎng)

2013-08-27 09:32:56

私有云實施混合云公有云

2017-07-04 14:57:40

微服務(wù)paasdocker

2022-01-17 11:29:42

數(shù)字化轉(zhuǎn)型企業(yè)技術(shù)

2022-11-11 10:48:55

AQS源碼架構(gòu)

2023-09-25 12:40:00

架構(gòu)師數(shù)字化轉(zhuǎn)型

2009-09-15 16:53:50

2014-03-19 09:13:54

2022-02-25 15:56:44

云計算架構(gòu)基礎(chǔ)設(shè)施

2016-08-24 16:23:36

服務(wù)架構(gòu)

2025-08-22 07:38:23

2010-10-19 14:57:25

谷歌云計算

2025-07-31 06:20:00

2010-08-05 14:44:29

數(shù)據(jù)中心停機成本
點贊
收藏

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

亚洲激情自拍| av在线播放一区二区| 91一区一区三区| 日本久久91av| 秋霞欧美一区二区三区视频免费| 精品成人18| 欧美日韩激情视频8区| 日韩亚洲视频在线| 精品国产乱码一区二区三 | 久久众筹精品私拍模特| 国产精品va在线播放我和闺蜜| 欧美一级片在线视频| 啪啪国产精品| 91精品国产丝袜白色高跟鞋| 国产日产欧美视频| 黄色成人影院| 久久久久久久久久看片| 亚洲淫片在线视频| 啪啪小视频网站| 影音先锋在线一区| www.亚洲男人天堂| 秘密基地免费观看完整版中文 | 欧洲国内综合视频| 日韩精品一区在线视频| 在线观看免费网站黄| 99久久婷婷国产综合精品电影| 国产欧美日韩最新| 无码人妻精品一区二| 韩国欧美一区| 另类视频在线观看| 久久久久久久久久久久| 亚洲专区**| 欧美一区二区成人6969| 日日干夜夜操s8| 免费观看成人性生生活片| 亚洲第一av色| 日韩一二区视频| 精品国产丝袜高跟鞋 | 中日韩一级黄色片| 国产一区二区三区网| 亚洲第一区在线| 先锋资源在线视频| 欧美美女福利视频| 欧美色网一区二区| 韩国一区二区av| 秋霞伦理一区| 欧美日韩视频免费播放| 国产96在线 | 亚洲| 国精一区二区三区| 亚洲一区二区三区影院| 欧美人与动牲交xxxxbbbb| 看女生喷水的网站在线观看| 1024精品合集| 久久久一二三四| 黄色片免费在线观看| 中文字幕一区在线| 一级黄色免费在线观看| 成人影欧美片| 亚洲精品视频自拍| avove在线观看| 羞羞视频在线观看免费| 亚洲情趣在线观看| 日韩精品一区二区三区电影| a级影片在线| 亚洲大片免费看| 日韩精品―中文字幕| 小早川怜子影音先锋在线观看| 欧美日韩国产页| 国产高清精品在线观看| 三上悠亚国产精品一区二区三区| 欧美色欧美亚洲高清在线视频| 精品一区二区中文字幕| 欧美大胆性生话| 欧美午夜电影一区| 亚洲免费999| 激情不卡一区二区三区视频在线| 亚洲网站免费| 亚洲第一av色| 成人在线免费观看av| 忘忧草在线影院两性视频| 午夜av一区二区三区| 久久综合九色综合88i| 一区二区三区短视频| 日韩欧中文字幕| 亚洲欧洲日本精品| 日韩中文字幕视频网| 亚洲成人精品视频| 中文字幕第4页| 天天影视综合| 久久免费福利视频| 日韩精品视频免费播放| 三级在线观看一区二区 | 日韩欧美激情| 精品乱码亚洲一区二区不卡| 熟女俱乐部一区二区视频在线| 99re66热这里只有精品8| 欧美俄罗斯性视频| 黄色在线免费观看| 国产一区二区三区日韩 | 亚洲精品成人在线播放| 粉嫩av一区二区| 国产一区二区三区三区在线观看 | 高清av一区二区三区| 色综合久久久久网| 免费成人黄色大片| 久久久久久久蜜桃| 一级黄色片免费| 日韩 欧美一区二区三区| 亚洲free性xxxx护士hd| 青青青草网站免费视频在线观看| 亚洲欧洲精品一区二区三区不卡| 大陆av在线播放| av成人在线播放| 亚洲电影免费观看| 性生交大片免费全黄| 宅男噜噜噜66国产日韩在线观看| 成人免费午夜电影| 国产福利在线| 天天综合网 天天综合色| 亚洲天堂av一区二区三区| 天美av一区二区三区久久| 久久亚洲国产精品成人av秋霞| 久久久久久91亚洲精品中文字幕| 国产精品自在在线| 西游记1978| 美女福利一区二区三区| 久久久久av| 美国十次综合久久| 欧美日韩精品在线播放| 91欧美一区二区三区| 免费不卡中文字幕在线| 成人在线高清| 美女任你摸久久| 免费精品视频一区| 国语对白在线刺激| 激情成人在线视频| 亚洲xxxxx| 福利在线播放| 欧美性生交xxxxxdddd| 亚洲精品乱码久久久久久蜜桃欧美| 日韩一区二区中文| 国产精品7m视频| 蜜桃视频在线观看视频| 欧美性videos高清精品| av网页在线观看| av中文字幕一区二区三区| av中文字幕第一页| 深爱激情五月婷婷| 久久国产三级| 91精品国产91综合久久蜜臀| 色综合99久久久无码国产精品| 国产精品久久久久久模特| 国产欧美日韩一区二区三区| 国产第一页在线视频| 欧美成人vps| 国产在线综合网| kk眼镜猥琐国模调教系列一区二区| 日本a在线天堂| 99香蕉久久| 97在线观看视频| 亚洲日本国产精品| 黑人一区二区三区| 欧美大片在线观看| 欧美一级高潮片| 不卡一区二区三区四区| 国产免费黄色小视频| 日韩美女国产精品| 国产97在线|亚洲| 夜级特黄日本大片_在线 | 天堂8在线天堂资源bt| 加勒比色老久久爱综合网| 午夜欧美大片免费观看| 六十路在线观看| 欧美日韩国产乱码电影| 麻豆一区产品精品蜜桃的特点| va亚洲va日韩不卡在线观看| 亚洲爆乳无码专区| 97视频热人人精品免费| 操人视频欧美| 中文字幕av一区二区三区佐山爱| 中文字幕日韩欧美在线| 国产福利小视频| 天天操天天色综合| youjizz亚洲女人| 国产精品小仙女| 丝袜人妻一区二区三区| 第一sis亚洲原创| 粉嫩高清一区二区三区精品视频| 性感女国产在线| 久久精品99久久久久久久久| 亚洲免费不卡视频| 欧美亚洲综合另类| 国产真人真事毛片| 欧美国产精品一区| 欧美性生交xxxxx| 日韩在线观看一区二区| 亚洲成人动漫在线| 国产中文精品久高清在线不| 亚洲在线观看视频| 91看片一区| 欧美激情视频一区| 一广人看www在线观看免费视频| 亚洲人123区| 电影午夜精品一区二区三区 | 日韩欧美在线观看免费| www.日韩在线| 一区二区三区网址| 亚洲精品专区| 小说区视频区图片区| 国产欧美高清视频在线| 国产精品久久久久av福利动漫| 成人在线观看免费视频| 97精品久久久中文字幕免费| 老司机精品视频在线观看6| 亚洲欧美国产高清va在线播| 亚洲精品一区二区三区不卡| 欧美三级中文字| 精品不卡一区二区| 亚洲sss视频在线视频| 日本少妇aaa| 国产嫩草影院久久久久| 国产精品揄拍100视频| 丁香啪啪综合成人亚洲小说 | 久久夜色精品国产欧美乱极品| 手机在线视频一区| 青青青伊人色综合久久| 农村妇女精品一二区| 最新日韩av| 无码av天堂一区二区三区| 午夜精品999| 致1999电视剧免费观看策驰影院| 国产aⅴ精品一区二区三区久久| 国产精品久久久久久免费观看| 精品视频一区二区三区在线观看| 国产精品自拍偷拍| 日韩欧美精品一区二区综合视频| 日本成人黄色片| 亚洲精品mv| 欧洲成人性视频| 不卡av影片| 欧美综合一区第一页| 在线视频cao| 日本高清不卡的在线| 自拍一区在线观看| 国产91精品网站| 日韩毛片免费观看| 国产成人一区二| 国产一区二区三区朝在线观看| 日本在线精品视频| 久久久人成影片一区二区三区在哪下载| 51久久精品夜色国产麻豆| 黄色大片在线| 2018日韩中文字幕| 成人美女大片| 国产精品久久久久久网站| 国产福利亚洲| 成人精品视频99在线观看免费| а天堂中文最新一区二区三区| 91精品视频免费| 91欧美极品| 久久66热这里只有精品| 一区二区导航| 天堂精品一区二区三区| 欧美h版在线| 手机在线视频你懂的| 欧美私人啪啪vps| 国产精品无码人妻一区二区在线| aⅴ色国产欧美| 欧美成人黑人猛交| 久久69国产一区二区蜜臀| 超级砰砰砰97免费观看最新一期| 国产91精品免费| 日本一区二区三区网站| 中文字幕av一区二区三区免费看 | 精品久久久久久亚洲国产300 | 亚洲欧洲综合网| 亚洲精品高清在线观看| 色婷婷在线观看视频| 在线观看国产日韩| 国产日产亚洲系列最新| 亚洲成人久久网| av在线天堂| 欧美国产日韩一区二区| 波多视频一区| 亚洲精品免费在线视频| 丝袜美腿一区二区三区动态图| 图片区小说区区亚洲五月| 欧美精选在线| 成年人在线看片| 国产精品资源在线看| 成人无码www在线看免费| 国产精品久久三区| 久久精品人妻一区二区三区| 色婷婷av一区二区三区gif| 国产乱码精品一区二区| 亚洲福利视频在线| 无遮挡的视频在线观看| 国语自产精品视频在线看一大j8 | 日韩va亚洲va欧美va清高| 偷拍日韩校园综合在线| 在线免费观看日韩视频| 亚洲成色777777在线观看影院| √天堂资源地址在线官网| 午夜精品久久久久久久久久久久久| 成人在线视频观看| 精品久久久久久亚洲| 久久久久久免费视频| 男人日女人bb视频| 国产精品一品视频| 9.1片黄在线观看| 欧美日韩国产色视频| 精品国产va久久久久久久| 中文字幕av日韩| 在线视频超级| 国产欧美日韩亚洲| 午夜亚洲福利| 最新国产黄色网址| 久久久91精品国产一区二区精品| 久久免费精彩视频| 91精品欧美综合在线观看最新| 黄色网址在线播放| 777午夜精品福利在线观看| 日韩一区二区三区色| 尤物一区二区三区| 日本欧美一区二区三区| 五级黄高潮片90分钟视频| 亚洲福利电影网| 性生活视频软件| 欧美成人午夜视频| 99久久99九九99九九九| 亚洲人久久久| 日韩中文欧美在线| 欧美做受高潮6| 色综合夜色一区| 国产小视频在线| 欧美一区二区三区精品电影| 久久精品国产亚洲blacked| 9色porny| av福利精品导航| 国产精品视频久久久久久久| 亚洲白虎美女被爆操| 国精产品一区一区三区mba下载| 91在线观看网站| 伊人青青综合网| 欧美熟妇另类久久久久久多毛| 亚洲日本丝袜连裤袜办公室| 97人妻人人澡人人爽人人精品| 色婷婷久久av| 国产乱码精品一区二区三区亚洲人| 中文字幕一区二区三区乱码| 激情另类小说区图片区视频区| 在线视频这里只有精品| 8v天堂国产在线一区二区| 毛片在线看网站| 91久久偷偷做嫩草影院| 欧美精品一卡| 老熟妇精品一区二区三区| 欧美日韩亚洲网| 国产福利第一视频在线播放| 国产精自产拍久久久久久| 午夜激情久久| 风韵丰满熟妇啪啪区老熟熟女| 亚洲成人精品影院| 神马精品久久| 国产精选久久久久久| 最新精品国产| 99久久人妻无码中文字幕系列| 精品久久久久久久久久久| av资源网站在线观看| 91在线免费看网站| 亚洲人体偷拍| 性の欲びの女javhd| 欧美一区二区三级| av剧情在线观看| 日韩视频在线观看国产| 国产美女视频91| 六月丁香在线视频| 中文字幕久久亚洲| 精品国产乱码一区二区三区 | 国产成人自拍网站| 亚洲第一精品久久忘忧草社区| 欧美精选视频一区二区| 男女啪啪免费观看| 久久亚洲综合色| 国产日本精品视频| 日本视频久久久| 91精品1区| 无码熟妇人妻av| 欧美一区二区三区免费在线看| 国产精品电影| 一区二区三区四区欧美日韩| 成人妖精视频yjsp地址| 中文字幕第2页| 国内精品小视频| 国产精品久久久久久久久久10秀| 中文字幕第3页| 欧美老女人第四色| 性欧美xxx69hd高清| 穿情趣内衣被c到高潮视频| 2017欧美狠狠色|