当前位置: 首页 > news >正文

最佳实践:如何基于消息服务MNS实现严格有序队列

问题背景
阿里 消息 服务 提供的队列(queue)主要特点是高可靠、高可用、高并发。每个队列的 数据 都会被持久化三份到阿里云的飞天分布式平台;其中每个队列至少有2台 服务器 向外提供服务;同时每台服务器都支持高并发访问。这些分布式特性,也导致了消息服务队列无法像传统单机队列那样保证严格的消息FIFO特点,只能做到基本有序。


我们的队列如果同时有多个消息发送者(sender),由于并发和网络延迟不一等问题,消息的严格顺序本身就是失去了意义,因为在这种情况下,我们根本无法获知消息在多个sender上的实际发送顺序和消息到达服务器端的真实顺序。同样的,当有多个接收者并发接收消息时,其真正的处理顺序也是不可获知的。

因此,我们认为只有一个发送者(一个进程,可以是多个线程), 一个接收者时,消息顺序才有意义,也只有在这种情况下我们能够感知和记录消息的真实发送顺序和消息的真实接收顺序。

解决方案
基于上述假设,同时为了满足部分用户对于消息消费顺序性的要求,我们设计了下面的方案,确保消息按照用户发送顺序被接收和消费。
主要步骤:
1.消息在发送端进行染色,加上SeqId(例如:#num#)
2.消息在接收端进行还原,并根据SeqId 排序后返回给上层,同时对于已经receive的消息会有后台线程保证消息不会被重复消费。
3.为了避免因为发送者fail,或者接收者fail,导致seqid 丢失。seqid 会被持久存储到本地磁盘文件。
   当然也可以存储到其他存储或 数据库 :例如OSS,OTS, RDS
240_1365541074971606_dcf0b3cd382d9d5.png
程序说明
附件提供了python版的方案实现(依赖MNS Python SDK)。其中,主要提供了OrderedQueueWrapper 类(oredered_queue.py文件),可以将普通的mns queue包装成有序queue。
OrderedQueueWrapper  提供两个方法:SendMessageInOrder()和ReceiveMessageInOrder()。send中对消息进行染色,receive还原消息,并且按顺序返回给接收者。

另外,send_message_in_order.py和receive_message_in_order.py提供了发送者和接收者使用OrderedQueueWrapper的程序示例。
send_message_in_order.py:
    #init orderedQueue
    seqIdConfig = {"localFileName":"/tmp/mns_send_message_seq_id"}   # 指定持久化发送SeqId的磁盘文件。
    seqIdPS = LocalDiskStorage(seqIdConfig)
    orderedQueue = OrderedQueueWrapper(myQueue, sendSeqIdPersistStorage = seqIdPS)
    orderedQueue.SendMessageInOrder(message)

receive_message_in_order.py:
    #init orderedQueue
    seqIdConfig = {"localFileName":"/tmp/mns_receive_message_seq_id"} #指定持久化接收SeqId的磁盘文件
    seqIdPS = LocalDiskStorage(seqIdConfig)
    orderedQueue = OrderedQueueWrapper(myQueue, receiveSeqIdPersistStorage = seqIdPS)
    recv_msg = orderedQueue.ReceiveMessageInOrder(wait_seconds)


运行方法:
1.配置send_message_in_order.py 和receive_message_in_order.py 中下列 配置
g_endpoint,g_accessKeyId,g_accessKeySecret,g_testQueueName 
2.运行send_message_in_order.py
3.运行receive_message_in_order.py (可以不用等步骤2程序运行完成)
发送程序会发送20条消息,接收程序会按顺序消费20条消息
240_1365541074971606_9530b6f93c549f4.png


也可以运行oredered_queue.py (需配置endpoint 和AK)的测试case对比普通mns queue的区别:
运行命令:$python oredered_queue.py
非严格有序:(整体有序,部分相邻消息无序,同时侧面证明MNS 的单个queue同时有多个服务器在提供服务)
240_1365541074971606_0a406a4c540529a.png



严格有序:
240_1365541074971606_4971ecb1f2f1a91.png

注意事项:
1.本帖主要目的是展示顺序消息的解决方案,本帖中的代码未经过严格测试,不建议不加测试直接用于生产环境。同时程序仓促完成,难免由瑕疵,欢迎回帖指正。
2.正常情况下,发送端和接收端的seqid应该和queue中的消息(染色)匹配,当出现删除queue重新创建等 操作 时,请注意磁盘文件中的seqid 是否和queue中的真实情况相符,同时建议不要往染色的消息队列里发送非染色消息。
3.队列的消息有效期设置过短或者每条消息的实际处理结果都有可能会对消息有序性造成影响,在您的程序中需要对这些情况所导致的的乱序现象进行处理。


示例程序下载:
zip.gif ordered_queue_wrapper.tar.gz (4 K) 

相关文章:

  • Android Material Design-Creating Lists and Cards(创建列表和卡)-(三)
  • 自己写一个切换桌面的文件
  • GTK+重拾--07 GTK+中的事件
  • eclipse报错: Unhandled event loop exception No more handles
  • CMS 回收器的两次 STW
  • Linux指令--rcp,scp
  • Asp.net 使用正则和网络编程抓取网页数据(有用)
  • Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]【转】
  • 用百度推荐提升PV和收益的小方法
  • [C++]四种方式求解最大子序列求和问题
  • libserialport: cross-platform library for accessing serial ports
  • Linux USB驱动框架分析(2)【转】
  • 安卓android.support.design使用中的问题
  • swift锁屏播放,音乐进度更新,专辑,歌手名显示
  • srxboys 今日说 !
  • (ckeditor+ckfinder用法)Jquery,js获取ckeditor值
  • co.js - 让异步代码同步化
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • Java基本数据类型之Number
  • js作用域和this的理解
  • leetcode-27. Remove Element
  • React Native移动开发实战-3-实现页面间的数据传递
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • win10下安装mysql5.7
  • 闭包,sync使用细节
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 前端技术周刊 2019-02-11 Serverless
  • 前嗅ForeSpider中数据浏览界面介绍
  • 如何设计一个比特币钱包服务
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 找一份好的前端工作,起点很重要
  • 自制字幕遮挡器
  • ​​​​​​​sokit v1.3抓手机应用socket数据包: Socket是传输控制层协议,WebSocket是应用层协议。
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • ​secrets --- 生成管理密码的安全随机数​
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • ###STL(标准模板库)
  • #《AI中文版》V3 第 1 章 概述
  • #HarmonyOS:Web组件的使用
  • (07)Hive——窗口函数详解
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (六)c52学习之旅-独立按键
  • (没学懂,待填坑)【动态规划】数位动态规划
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (一)VirtualBox安装增强功能
  • .net core Swagger 过滤部分Api
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET 材料检测系统崩溃分析
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .Net的DataSet直接与SQL2005交互
  • @requestBody写与不写的情况
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • [【JSON2WEB】 13 基于REST2SQL 和 Amis 的 SQL 查询分析器