本文将介绍以下内容:
稳定的消息传送
事务和系统一致性
处理错误队列问题
消息大小和计时
本文使用以下技术:
WCF、MSMQ
设计分布式系统一直都是个挑 战。有了功能日益强大的 CLR、高效的 Visual Studio 以及框架中建立的细粒度控制(如 Windows Communication Foundation (WCF)),开发人员便拥有了构建可扩展系统所需的全部工具 。遗憾的是,这些还不够。
在处理大型分布式系统时,我的团队发现开发可处理故障且不丢失数据的可靠系统远不是那么简单。 这并不是工具集失效,而是需要以极特殊的方式来使用这些工具才能实现既可扩展又可靠的系统。
HTTP 和消息丢失
团队面对的第一个难题就是消息丢失。刚开始设计我们的系统时,我们 已决定使用 HTTP 传输基于 WCF 的服务。作为消息处理的一部分,我们的服务会经常向数据库中写入数 据。这里没有谴责的意思,但很多系统都是这样设计的。
在系统进入配置环境之前,已经过了非 常严格的压力测试 – 系统在繁重负荷下运行了一周时间。压力测试的结果表明我们的系统发生了 消息丢失。
在分析事因的过程中,我们确定丢失的主要是那些包含订单信息的消息 - 这并不令人 惊讶,因为系统中的大部分负荷都与订单信息有关。但让我们惊奇的是所有这些消息丢失都是在一个 10 分钟的时间间隔内发生的。此后,系统又正常运行了。
在研究了多方面的日志文件后,我们发现 ,这一周中发布了一个关键的 Windows 补丁,而配置实验室中的服务器自己在自动安装了该补丁后重新 启动。考虑到这个新发现蕴藏的信息 – 服务器会不时重新启动 – 我们意识到不能忽略这一 点。系统将需要连续运行数年并需要经受住多次服务器升级和重新启动的考验。
通过 HTTP 处理 消息时,服务会打开一个针对数据库的事务,尝试写入数据,然后提交该事务。正常情况下,此操作会成 功执行。如果消息处理服务器重新启动了中间事务,数据库会检测到该事务超时,并回滚其更改,从而保 持其状态一致。但当服务器再次启动后,原始消息的数据既不会出现在内存中也不会出现在服务器的网络 处理堆栈中 – 该消息将会丢失。
对于订单处理系统,这就意味着经济损失。任何人都很难 接受在空中交通控制系统中出现这样噩梦般的情形 - “飞机 A 与飞机 B 正处于碰撞航向” 这一事件丢失。