1. 程式人生 > >一個可供參考的Java高併發非同步應用案例

一個可供參考的Java高併發非同步應用案例

泰康線上微信公眾號系泰康線上財產保險股份有限公司旗下平臺,希望可以通過持續不斷的創新,提升客戶對於保險的認知及體驗,通過對大資料技術的應用,精準的為客戶設計產品以及提供服務。泰康線上微信公眾號,現有1000多萬粉絲。在日常的運營中,藉助於紅包獎勵、卡券分享、訊息通知、微信分享等手段,通過好的內容,好的活動、好的產品以及相應的精準營銷來增強使用者的粘性和活躍度。

在日常運營中,公眾號會通過給使用者下發營銷或者科普類的訊息來通知客戶。 根據經驗,微信訊息下發後10分鐘後流量會逐步上升,30分鐘左右到達峰值,1個小時後會顯著下降。在這個時間段內,系統的壓力會很大。

在系統設計和改進中,系統的很多場景使用非同步進行實現,一方面能縮短主流程的時間處理,另一方面能夠通過非同步佇列進行一定程度的削峰。今天重點介紹單個JVM內的非同步優化實踐,不涉及分散式時的非同步優化實踐。在非同步執行時,可以呼叫遠端的服務叢集來實現一定的任務分解。

部署示意圖

整個系統都部署在公有云上,虛擬機器上有部署1個Nginx,4個Tomcat,Nginx使用隨機的方式負載均衡到Tomcat上面。虛機之間通過LB將客戶請求轉發到Nginx上面負載均衡,Nginx再將請求分配到tomcat應用伺服器上。


由多臺應用伺服器,對外服務提供Rest服務,在每個Tomcat內部使用非同步佇列。同時由一臺控制伺服器,進行非同步任務的補償任務和管理功能。Tomcat和Redis使用多級快取來降低對Redis的壓力,並減少依賴。

為什麼要在虛機上部署Nginx將請求轉發到Tomcat,而不是由LB直接轉發到Tomcat。這是因為LB能夠支援的IP個數是有限的。

典型的使用者場景

在公眾號的運營過程中,典型的事件包括:

  • 傳送簡訊驗證碼

  • 購買成功或者抽獎成功簡訊通知

  • 卡券或優惠券發放

  • 發放微信紅包

  • 微信訊息通知

  • 訂單流程處理

  • 定時批處理(比如資料同步)

  • 工作流性質的非同步任務(未完成非同步任務補償)

面詳細說明不同場景能夠非同步的原因:

  1. 不同場景(使用者註冊,使用者購買產品等)下的簡訊驗證碼傳送,可以使用非同步方式傳送: 一方面是因為客戶這個時效性要求沒有那樣高,另一方面在特定時間範圍內使用者沒有收到驗證碼,使用者可以點選再次傳送驗證碼。

  2. 購買成功或者抽獎成功後簡訊或者郵件通知,可以通過非同步的方式進行。 因為涉及使用者的利益,要謹慎對待。一方面一定要把資料先存到資料庫或者日誌裡面(注意資訊保安^-^,別存敏感明文資訊或者加密儲存),然後再放入到非同步佇列中執行。

    另一個方面,要考慮到應用服務意外停止時,沒有傳送成功資料的補償機制。 這種情況不常見,並且為了減少耦合和當前非同步程式的複雜度。我們使用單獨的服務上部署非同步任務補償程式,來掃描未完成的任務,並且進行重放(一定要注意嚴謹性)。

  3. 優惠券和卡券的發放,跟購買成功或抽獎成功的方式類似。\u000b可以在當前活動高峰後延時發放,並且使用非同步的方式進行。

  4. 微信紅包,因為需要跟微信進行互動,並且微信會通知客戶紅包的情況,可以使用非同步的方式進行。 當涉及資金或者禮品時,一定要謹慎對待設計,並且需要有方便進行非同步任務停止和啟動的功能。

  5. 微信訊息通知,因為跟微信進行互動,成功後微信進行通知,可以使用非同步。 這個跟簡訊驗證碼類似。

  6. 訂單流程處理,可以使用非同步,因為涉及到後續步驟可以使用簡單工作流來完成。有幾個開源的框架可以參考。

  7. 資料同步或者非同步任務補償,因為是延時處理,可以使用非同步進行處理。在使用時,可以配合定時任務,比如cron4j來週期性的進行補償。適合後面總-分-總的任務處理模式。

針對這些“無處不在的非同步”,後面詳細分析其內在模型。

無處不在的非同步

下圖包含了4種典型的非同步佇列模型(圖片來源於網路):


一個生產者生產資料,一個消費者消費資料,一般用在後臺處理的業務邏輯中。

  • 一個生產者生產資料,多個消費者消費資料(這裡面有兩種情況:同一個訊息,可以被多個消費者分別消費。或者多個消費者組成一個組,一個消費者消費一個數據)。

  • 多個生產者生產資料,單個消費者消費資料,可以用在限流或者排隊等候單一資源處理的場景中。

  • 多個生產者分別生產資料,多個消費者消費資料(這裡面有兩種情況:同一個訊息,可以被多個消費者分別消費。或者多個消費者組成一個組,一個消費者消費一個數據)。


總分總任務模型:特別適第一個執行緒取出一批資料放到佇列中(比如select);由多個執行緒分別執行業務邏輯;執行後的結果由一個執行緒來執行(比如update操作,這樣能夠防止資料庫鎖)

這是從技術上分析的幾種常見模型,在實踐中涉及怎樣選擇框架。

  1. 使用堵塞佇列的執行緒池

  2. 使用固定步長或固定時間的佇列

  3. 使用Disruptor

  4. 使用MQ或Kafka

使用執行緒池實現非同步 (支援多生產者,多消費者)


特點:可以使用JDK自帶的執行緒池實現非同步,程式設計簡單,資料多。建議在併發量小的場景下優先選擇。

使用Guava Queues (支援多生產者單消費者)


特點:非同步批量佇列,在佇列到達指定長度,或者到達指定時間後,批量進行資料處理。適合於對響應時間要求低,能夠容忍一定的資料丟失的場景。比如短小文字資料的批量儲存。

在經過一段時間調研後,我們發現Disruptor更能滿足我們需要。

首先介紹一下Disruptor的強悍的效能。





這張圖包含我列舉的上述的非同步佇列模型景,因此很有代表意義。Disruptor因為使用無鎖的佇列方式,具有很高的效能。具體的原理不詳述,大家可以搜尋看到。Disruptor支援上面典型場景,並且靈活使用Disruptor的工作流機制,能簡化程式設計。

  • 英文文章入門:https://github.com/LMAX-Exchange/disruptor/wiki/Getting-Started

  • 中文的demo連結:http://my.oschina.net/u/2273085/blog/507735?p=1

  • 併發框架Disruptor相關譯文:http://ifeve.com/disruptor/

再貼一下官方的測試結果。


下面從程式碼層面說明disruptor的幾種用法。

使用Disruptor(單生產者多消費者)


Disruptor 提供了多個 WaitStrategy的實現,每種策略都具有不同效能和優缺點,根據實際執行環境的 CPU 的硬體特點選擇恰當的策略,並配合特定的 JVM的配置引數,能夠實現不同的效能提升。 例如,BlockingWaitStrategy、SleepingWaitStrategy、YieldingWaitStrategy 等,其中:

  • BlockingWaitStrategy 是最低效的策略,但其對CPU的消耗最小並且在各種不同部署環境中能提供更加一致的效能表現;

  • SleepingWaitStrategy 的效能表現跟 BlockingWaitStrategy 差不多,對 CPU的消耗也類似,但其對生產者執行緒的影響最小,適合用於非同步日誌類似的場景;

  • YieldingWaitStrategy的效能是最好的,適合用於低延遲的系統。在要求極高效能且事件處理線數小於 CPU邏輯核心數的場景中,推薦使用此策略;例如,CPU開啟超執行緒的特性。

我們現在使用BlockingWaitStrategy這種模式。

使用Disruptor(多生產者多消費者)


使用Disruptor(多生產者多消費者)


這個例子中,使用類似執行緒池的消費組處理資料。

多步模式工作流:Disruptor



使用非同步後的煩惱

煩惱一: 資料丟失的風險

解決方式:先寫日誌或資料庫,後放入非同步佇列.

煩惱二:對其他系統的壓力變大

解決方式:使用一定的限流和熔斷,對其他系統進行保護。

煩惱三:資料儲存後非同步任務未執行

解決方式:使用非同步任務補償的方式,定期從資料庫中獲取資料,放到佇列中進行執行,執行後更新資料狀態位。

煩惱四:怎樣佇列長設定和消費者數量

解決方式:使用實際的壓力測試來獲得佇列長度。或者使用排隊論的數學公式得到初步的值,然後進行實際壓測。

最後介紹一下專案中的經驗:

  • 量力而行:根據業務特點進行技術選型,業務量小盡量避免使用非同步。有所為,有所不為

  • 資料說話:非同步時一定要進行必要的壓力測試

  • 先找出系統的關鍵點:優化單體系統內的效能,再通過整體系統分解來全域性優化

  • 根據團隊和專案的特點選擇框架。

相關推薦

一個參考Java併發非同步應用案例

泰康線上微信公眾號系泰康線上財產保險股份有限公司旗下平臺,希望可以通過持續不斷的創新,提升客戶對於保險的認知及體驗,通過對大資料技術的應用,精準的為客戶設計產品以及提供服務。泰康線上微信公眾號,現有1000多萬粉絲。在日常的運營中,藉助於紅包獎勵、卡券分享、訊息通知、微信

一個參考的面向大型集團公司的雲平臺架構解析

在過去的二十多年中,很多國內的大型集團公司都已經建立了非常龐大的業務資訊系統,包括 OA 系統、ERP 系統、CRM 系統、HRM 系統以及各種行業應用系統,為了保證這些業務資訊系統的長期穩定執行,還建設了一批支撐型資訊系統,如監控系統、身份認證系統、安全執行中心等。這些資訊系統通常在建設期間獨立

貝聊架構師林毅:一個參考的系統部署工具

說到系統部署工具,大的網際網路公司基本上是自己研發,一鍵自動部署到數百臺到數千臺伺服器, 比如 twitter 開源的 Murder。小的公司可能使用一些開源工具,比如 Jenkins、Puppet、Ansible 結合一些指令碼進行。 開源的部署工具有 Capistrano、瓦力等,線上部署的有

一個中小團隊參考的微服務架構技術棧

半成品 離職 ota check 定制 db2 最佳實踐 嚴重 應用 一個可供中小團隊參考的微服務架構技術棧 聊聊架構 2018-05-07 作者 楊波 作者 | 楊波編輯 | 張浩 近年,Spring Cloud 儼然已經成為微服務開發的主流技術棧,在國內

Java併發解決方案之非同步處理

(() -> { // 請求1 CompletableFuture<List<Integer>> completionStage1 = CompletableFuture.supplyAsync(() -> { //

一個創業公司參考的雲網絡視覺化與安全解決方案

作者簡介: 張天鵬(Neeke),雲杉網路聯合創始人兼CTO 負責公司的產品和技術研發工作,曾任美國 Juniper 公司高階研發經理,負責當時世界最大防火牆 SRX 的研發。專注於 SDN、NFV 和雲端計算領域的相關產品和技術,對於 SDN 在雲端計算業務中的實施和應用有豐富的經驗。 一、背景

java併發系統之非同步非阻塞

在做電商系統時,流量入口如首頁、活動頁、商品詳情頁等系統承載了網站的大部分流量,而這些系統的主要職責包括聚合資料拼裝模板、熱點統計、快取、下游功能降級開關、託底資料等等。其中聚合資料需要呼叫其它多個系統服務獲取資料、拼裝資料/模板然後返回給前端,聚合資料來源主要有依賴系統

聊聊java併發系統之非同步非阻塞

幾種呼叫方式 同步阻塞呼叫 即序列呼叫,響應時間為所有服務的響應時間總和; 半非同步(非同步Future) 執行緒池,非同步Future,使用場景:併發請求多服務,總耗時為最長響應時間;提升總響應時間,但是阻塞主請求執行緒,高併發時依然會造成執行緒數過多,CPU上下文切換; 全非同步(Cal

Java併發解決方案(參考文)

對於我們開發的網站,如果網站的訪問量非常大的話,那麼我們就需要考慮相關的併發訪問問題了。而併發問題是絕大部分的程式設計師頭疼的問題,但話又說回來了,既然逃避不掉,那我們就坦然面對吧~今天就讓我們一起來研究一下常見的併發和同步吧。 為了更好的理解併發和同步,我們需要先明白兩個重要的概念:同步和

Java併發之同步非同步

1、概念理解: 2、同步的解決方案: 1).基於程式碼 synchronized 關鍵字  修飾普通方法:作用於當前例項加鎖,進入同步程式碼前要獲得當前例項的鎖。  修飾靜態方法:作用於當前類物件加鎖,進入同步程式碼前要獲得當前類物件的鎖。     修飾程式碼塊:指定加鎖物

【轉】聊聊java併發系統之非同步非阻塞

在做電商系統時,流量入口如首頁、活動頁、商品詳情頁等系統承載了網站的大部分流量,而這些系統的主要職責包括聚合資料拼裝模板、熱點統計、快取、下游功能降級開關、託底資料等等。其中聚合資料需要呼叫其它多個系統服務獲取資料、拼裝資料/模板然後返回給前端,聚合資料來源主要有依賴系統/服務、快取、資料庫等;而系統之間

實戰Java併發程式設計.epub

    【下載地址】 在過去單核CPU時代,單任務在一個時間點只能執行單一程式,隨著多核CPU的發展,並行程式開發就顯得尤為重要。 《實戰Java高併發程式設計》主要介紹基於Java的並行程式設計基礎、思路、方法和實戰。第一,立足於併發程式基礎,詳細介紹Ja

Java 併發專案筆記

maven 配置與安裝 下載maven 檔案 解壓之後,將檔案移動到\Applications資料夾內 使用cd ~ 進入根目錄資料夾 用ls -a列出資料夾內的所有檔案,找到一個名稱為.bash_profile的檔案,開啟該檔案來配置環境變數 export JAVA_HOME=/Library/Jav

SpringBoot實現Java併發秒殺系統之併發優化

秒殺系統架構的設計和優化分析,以我一個小菜雞,目前是說不出來的o(╥﹏╥)o。 因此呢,我這裡僅從本專案已經實現的優化來介紹一下: 本專案中做到了以下優化: 秒殺介面採用md5加密方式防刷。 訂單表使用聯合主鍵方式,限制一個使用者只能購買該商品一次。 配合Spring事務

2018最新實戰Java併發程式設計

在過去單核CPU時代,單任務在一個時間點只能執行單一程式,隨著多核CPU的發展,並行程式開發就顯得尤為重要。《實戰Java高併發程式設計》主要介紹基於Java的並行程式設計基礎、思路、方法和實戰。第一,立足於併發程式基礎,詳細介紹Java中進行並行程式設計的基本方法。第二,進一步詳細介紹JDK中對並

高階java併發,高效能,分散式,可用,負載均衡,系統架構實戰

Java併發程式設計(一): 併發程式設計的挑戰本文主要內容出自《Java併發程式設計的藝術》一書,是對該書內容的歸納和理解,有興趣的朋友請購買正版閱讀全部內容。 併發程式設計的目的是為了讓程式執行的更快,但是並不是啟動更多的執行緒,就能讓程式最大限度的併發執行。在進行併發程式設計時,如果希望通過多執行

JAVA併發多執行緒必須懂的50個問題

ImportNew  首頁所有文章資訊Web架構基礎技術書籍教程Java小組工具資源  Java執行緒面試題 Top 50  2014/08/21 | 分類: 基礎技術 | 27 條評論 | 標籤: 多執行緒, 面試題  分享到: 692  本文由

Java併發程式設計之synchronized關鍵字(二)

上一篇文章講了synchronized的部分關鍵要點,詳見:Java高併發程式設計之synchronized關鍵字(一) 本篇文章接著講synchronized的其他關鍵點。 在使用synchronized關鍵字的時候,不要以字串常量作為鎖定物件。看下面的例子: public class

Java併發程式設計之synchronized關鍵字(一)

首先看一段簡單的程式碼: public class T001 { private int count = 0; private Object o = new Object(); public void m() { //任何執行緒要執行下面這段程式碼

實戰Java併發程式設計(五、並行模式與演算法)

5.1單例模式 單例模式:是一種常用的軟體設計模式,在它的核心結構中值包含一個被稱為單例的特殊類。一個類只有一個例項,即一個類只有一個物件例項。  對於系統中的某些類來說,只有一個例項很重要,例如,一個系統中可以存在多個列印任務,但是隻能有一個正在工作的任務;售票時,一共有100張票,可有有