直播電商原始碼,利用Kotlin+RocketMQ 實現延時訊息

zhibo系統開發發表於2021-10-19

直播電商原始碼,利用Kotlin+RocketMQ 實現延時訊息的相關程式碼

一. 延時訊息

延時訊息是指訊息被髮送以後,並不想讓消費者立即拿到訊息,而是等待指定時間後,消費者才拿到這個訊息進行消費。

使用延時訊息的典型場景,例如:

在電商系統中,使用者下完訂單30分鐘內沒支付,則訂單可能會被取消。

在電商系統中,使用者七天內沒有評價商品,則預設好評。

這些場景對應的解決方案,包括:

輪詢遍歷資料庫記錄

JDK 的 DelayQueue

ScheduledExecutorService

基於 Quartz 的定時任務

基於 Redis 的 zset 實現延時佇列。

除此之外,還可以使用訊息佇列來實現延時訊息,例如 RocketMQ。

二. RocketMQ

RocketMQ 是一個分散式訊息和流資料平臺,具有低延遲、高效能、高可靠性、萬億級容量和靈活的可擴充套件性。RocketMQ 是2012年阿里巴巴開源的第三代分散式訊息中介軟體。

三. RocketMQ 實現延時訊息

3.1 業務背景

我們的系統完成某項操作之後,會推送事件訊息到業務方的介面。當我們呼叫業務方的通知介面返回值為成功時,表示本次推送訊息成功;當返回值為失敗時,則會多次推送訊息,直到返回成功為止(保證至少成功一次)。

當我們推送失敗後,雖然會進行多次推送訊息,但並不是立即進行。會有一定的延遲,並按照一定的規則進行推送訊息。

例如:1小時後嘗試推送、3小時後嘗試推送、1天后嘗試推送、3天后嘗試推送等等。因此,考慮使用延時訊息實現該功能。

3.2 生產者(Producer)

生產者負責產生訊息,生產者向訊息伺服器傳送由業務應用程式系統生成的訊息。

首先,定義一個支援延時傳送的 AbstractProducer。

abstract class AbstractProducer :ProducerBean() {
    var producerId: String? = null
    var topic: String? = null
    var tag: String?=null
    var timeoutMillis: Int? = null
    var delaySendTimeMills: Long? = null
    val log = LogFactory.getLog(this.javaClass)
    open fun sendMessage(messageBody: Any, tag: String) {
        val msgBody = JSON.toJSONString(messageBody)
        val message = Message(topic, tag, msgBody.toByteArray())
        if (delaySendTimeMills != null) {
            val startDeliverTime = System.currentTimeMillis() + delaySendTimeMills!!
            message.startDeliverTime = startDeliverTime
            log.info( "send delay message producer startDeliverTime:${startDeliverTime}currentTime :${System.currentTimeMillis()}")
        }
        val logMessageId = buildLogMessageId(message)
        try {
            val sendResult = send(message)
            log.info(logMessageId + "producer messageId: " + sendResult.getMessageId() + "\n" + "messageBody: " + msgBody)
        } catch (e: Exception) {
            log.error(logMessageId + "messageBody: " + msgBody + "\n" + " error: " + e.message, e)
        }
    }
    fun buildLogMessageId(message: Message): String {
        return "topic: " + message.topic + "\n" +
                "producer: " + producerId + "\n" +
                "tag: " + message.tag + "\n" +
                "key: " + message.key + "\n"
    }
}

根據業務需要,增加一個支援重試機制的 Producer

@Component
@ConfigurationProperties("mqs.ons.producers.xxx-producer")
@Configuration
@Data
class CleanReportPushEventProducer :AbstractProducer() {
    lateinit var delaySecondList:List<Long>
    fun sendMessage(messageBody: CleanReportPushEventMessage){
        //重試超過次數之後不再發事件
        if (delaySecondList!=null) {
            if(messageBody.times>=delaySecondList.size){
                return
            }
            val msgBody = JSON.toJSONString(messageBody)
            val message = Message(topic, tag, msgBody.toByteArray())
            val delayTimeMills = delaySecondList[messageBody.times]*1000L
            message.startDeliverTime =  System.currentTimeMillis() + delayTimeMills
            log.info( "messageBody: " + msgBody+ "startDeliverTime: "+message.startDeliverTime )
            val logMessageId = buildLogMessageId(message)
            try {
                val sendResult = send(message)
                log.info(logMessageId + "producer messageId: " + sendResult.getMessageId() + "\n" + "messageBody: " + msgBody)
            } catch (e: Exception) {
                log.error(logMessageId + "messageBody: " + msgBody + "\n" + " error: " + e.message, e)
            }
        }
    }
}

在 CleanReportPushEventProducer 中,超過了重試的次數就不會再傳送訊息了。

每一次延時訊息的時間也會不同,因此需要根據重試的次數來獲取這個delayTimeMills 。

通過 System.currentTimeMillis() + delayTimeMills 可以設定 message 的 startDeliverTime。然後呼叫 send(message) 即可傳送延時訊息。

以上就是 直播電商原始碼,利用Kotlin+RocketMQ 實現延時訊息的相關程式碼,更多內容歡迎關注之後的文章


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69978258/viewspace-2838099/,如需轉載,請註明出處,否則將追究法律責任。

相關文章