1. 程式人生 > >Java使用訊息佇列還是直接使用執行緒池ExecutorService非同步處理?

Java使用訊息佇列還是直接使用執行緒池ExecutorService非同步處理?

說說這兩種的區別,各自適合什麼場景?

用執行緒池ExecutorService非同步處理:我理解ExecutorService其實也是內部使用了佇列(如LinkedBlockingQueue),所以從設計上,其實和使用中間價的訊息佇列是差不多一致的。只是這裡應用伺服器既充當生產者又充當消費者,也是訊息佇列中間價的實現者。這種應該適合非分散式的架構,比如簡單的只有一臺伺服器。

使用訊息佇列:訊息佇列(指activeMQ,rabbitMQ,kafaKa,Redis等)因為一般都是中介軟體,部署在其他機器,需要一定的網路消耗。
本著解耦的目的,使用後者更合理,因為應用伺服器一般記憶體也不會太多,佇列長度不易太長。讓應用伺服器只處理邏輯比較合理。適合分散式架構。

1.使用JDK提供的非同步框架ExecutorService

threadPool.execute(new Runnable() {
    @Override
    public void run() {
        // 這裡是非同步處理的,比較耗時的邏輯,比如資料庫操作
        userService.setDefaultAddressId(user.getUserId(), bookingForm.getAddressId());
    }
});

2.將訊息傳送到訊息佇列,如使用redisList簡單實現,然後後臺執行緒消費訊息。

// 生產訊息
redisTemplate.opsForList().leftPush(LOG_MQ_KEY, JsonUtil.beanToJson(httpRequestLog));

// 後臺執行緒非同步消費訊息
String popValue = redisTemplate.opsForList().rightPopAndLeftPush(LOG_MQ_KEY, TEMP_LOG_MQ_KEY);

MQ可以更加有擴充套件性, 支援的場景更多, 而且支援訊息自動的持久化, 建議你看看 RabbitMQ 和 AMQP 協議, JMS 可以學但是沒 AMQP 更加通用, redis的MQ還是不要用了, 那只是一個附帶的功能, kafka 是大資料領域的不適合做核心業務功能, 只適合資料統計類應用的傳送資料, 因為他不確保訊息100%不丟失, 如此大的資料量丟一條無所謂的, 不會對統計結果造成影響, 但速度和吞吐量高很多

執行緒池就不一樣了, 目前執行狀態你無法知道, msg的消費率是多少都不知道, 訊息轉發啊, 訊息拒絕啊, 都的自己實現, 而且是單機版的, 我目前用他來做一級轉發, 就是用他來將 event 非同步傳送出去, 而不是讓他非同步做一些很繁重的工作, 舉例: 
註冊使用者service方法, 當事務結束後, 傳送 RegisterUserEvent, 這個傳送就是用java執行緒池(如spring的), 然後 RegisterUserListener 監聽到了這個 event 就傳送 msg 到 Rabbit MQ, 之後對註冊使用者這個Topic感興趣的應用都可以訂閱, 比如送積分的服務, 送優惠券的服務, 開闢雲盤空間的服務等等

java領域有很多這種類比, ehcache 和 redis對比做快取啊, java併發庫 和redis鎖對比並發啊等等, 都可以提出你這型別的問題

最初設計時,建議用ExecutorService,但最好用定時器把佇列數量打出來,這樣就能對阻塞情況有所瞭解。

當伺服器負荷升高、執行緒池阻塞到危及程式正常執行時,可以考慮升級為中介軟體。(其實,很少有網站的訪問量能達到這種負荷的,要麼是程式本身有Bug。)

儘量用ExecuteService,如果不是涉及到:

  1. 跨服務業務。比如訂單、支付
  2. 業務去耦合。比如有些情況上級業務不用知道下級執行是否成功,比如log日誌等

使用Mq會帶來設計上的複雜性:網路抖動怎麼辦?最大佇列長度怎麼設定?超時時間又設定多少?Qos又設定為多少?消費者多少個比較合適?channel cache size又該設定為多少?業務線可能都是用同一個Mq,你佔資源太多,或者設計不當導致整個Mq故障(比如你不確認訊息),開發同志們難道不來撕你麼?

為什麼非要多加個元件呢?能不用盡量不用