拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

短消息中心业务功能拆解:状态机、队列与SMPP实战

短消息中心业务功能拆解:状态机、队列与SMPP实战

简介:这份技术类PPT围绕短消息中心(SMS Center)的核心业务功能展开,面向通信工程、网络运维、移动核心网及增值业务初学者,适合作为培训课件或自学入门材料。内容从短消息提交、转发、优先级与有效期管理讲起,细致说明提交验证、发送失败后的永久性/临时性错误分类、Alert_SC触发、周期重发与定时触发等重试机制,并覆盖状态报告、PPS/用户/号段/虚拟短消息鉴权、GB13000汉字透明传输、虚拟短消息中心、存储转发/数据报/交互三种调度方式,以及节日高负荷模式和省网短消息协同等场景,能帮助读者把单条消息流程与系统级调度串联起来。整个资源包只有1个文件,类型为pptx,大小约444KB,结构紧凑,可离线阅读或用于团队内训。当前已有77人学习下载,适合需要快速理解短消息中心业务功能、排查消息发送流程或做技术方案梳理的读者。

1. 短消息中心业务功能:一份 PPT 背后要面对的真实系统

我刚入行通信时,拿到一份《试谈短消息中心业务功能.pptx》,以为只是介绍短信收发。后来才明白,标题里“业务功能”四个字,背后是一套需要同时处理消息生命周期、状态报告、重试策略、优先级排队和路由的工程系统。短消息中心(SMSC)上游接行业网关或集团客户,下游接运营商核心网,任何一个功能点没定清楚,上线后都会转化成用户投诉和运维救火。这篇从一线工程视角,把这个PPT里该讲清楚的功能盘出来,并落到可执行的参数、协议验证和排查路径,适合刚接手短信平台的产品经理、协议开发、运维以及决定技术方案的技术负责人。

2. 把业务功能拆成模块:状态机、队列与路由才是中心

一份《试谈短消息中心业务功能》的PPT,如果只是罗列“能发短信、能收短信、能查状态”,那它解决不了任何问题。真正决定短信中心能不能扛住线上流量的是三件事:消息状态怎么流转,消息队列怎么排队,消息路由怎么选。业务功能不是一个个孤立的接口,而是一条流水线。

2.1 短信中心的六个核心业务功能

我习惯把一条消息从进来到最终消失画成一条流水线。流水线上至少要有六个功能模块:短消息接收、存储转发、状态报告、优先级调度、有效期管理和黑白名单过滤。再加上现代短信中心一定还会有的流量控制,一共六个。这个清单可以拿来对照PPT,看它有没有漏掉关键项。

业务功能职责常见误解
短消息接收接收来自行业客户或短信网关的提交请求,校验来源、长度、协议格式以为接收就是HTTP接口,忽略了协议头解析和重复消息判定
存储转发把消息写入数据库或内存队列,再按目标号段选择下发网元以为立刻发出,忽略了对方手机关机时需要等待
状态报告从MSC/HLR收回执,关联原消息后回传给上游最容易漏,漏了第二天对账全乱
优先级调度普通通知和银行验证码分开排队,高优先生效以为优先级参数传了就行,内部没做队列分级
有效期管理控制消息在中心存活多久,超时直接丢弃设了48小时,却没考虑重试窗口,导致消息在过期前反复重试
黑白名单与流量控制拦截营销号段、退订用户、敏感内容,以及在拥塞时限制提交速率只做发送侧拦截,不覆盖状态报告回执路径

这张表基本覆盖了PPT里“业务功能”一节该写的主要内容。实际做需求评审时,我会要求每个功能必须回答三个问题:谁触发、失败怎么办、有没有日志能证明它执行了。只有PPT功能描述没有这些答案,开发就没办法落地。

2.2 消息状态机:从提交到发送成功,中间有多少个状态

短信中心的下行消息状态至少应该有八个:已接收、校验通过、排队中、已下发、已送达、下发失败、重试中、已过期。状态多会被人说繁琐,但没有状态机,你没法回答“这批短信到底哪条没发出去、现在停在哪一步”。

状态转换的规则是这样:消息进来先校验,校验失败直接返回错误码,成功则落库并进入排队;调度器把消息投递给下游网元,收到下发成功的响应后置为已下发,收到手机终端的最终回执后置为已送达;如果下发响应的失败码是“临时失败”,进入重试中,重试超过上限或者超过有效期,置为已过期。整个状态机里,最容易忽略的是“已下发”和“已送达”是两回事:下发成功只代表MSC接受了,不代表用户手机收到了消息。PPT里如果只画一个“发送成功”,后面做状态报告对接时必翻车。

想把这个逻辑理清楚,可以按状态表逐格检查。列写当前状态,行写触发事件,例如“提交、下发响应、状态报告、超时”。然后检查每个事件在每个状态下有没有明确动作。大多数短信中心的状态机 bug 都是因为“已过期”状态没有定义收到状态报告时怎么处理。比如消息已经过期,结果迟到的状态报告还是把消息从“已过期”改成了“已送达”,这条记录就再也对不上了。

2.3 为什么不能把业务功能等同于API接口

常见的PPT会把业务功能做成一张API列表:发送短信、查询状态、接收回执。这样做会让人误以为短信中心只是一个接口服务。但真实的短消息中心还要处理两类消息:下行MT(Mobile Terminated)和上行MO(Mobile Originated)。MT从业务网关来,MO从手机用户来,中间必须有一个消息分发层把两者转译成内部的事件。上行消息可以做短信回复、二次确认、退订管理,这些是业务规则,不是简单的“接口”。

另一个理由是协议适配。同一个业务功能,在不同网络环境下对接方式不一样:短信中心对外提供SMPP协议接口,国内运营商级互联又可能用CMPP、SGIP或SMGP。如果没有把业务功能独立成层,而是把协议处理跟业务逻辑揉在一起,后面要加一个“能路由到异网”的功能点,只能改核心代码。我的习惯是:PPT里提到的所有功能,在系统设计图上至少用三层表示——接入层、业务逻辑层、发送通道层。业务功能落在中间层,协议和接口只是出入口。

这样做还有一个好处:中间层可以无状态地扩缩容。接入层收到消息后交给业务层,业务层落库并投递到队列,发送通道层负责跟外部网元打交道。即使通道层抖动,业务层仍然可以继续接收新消息,不会一堵全堵。短信中心的业务功能,本质上就是要设计好这条分层流水线。

3. 把 PPT 里的业务功能变成可落地配置:需求梳理与参数设计

这份PPT如果要落成一个可开发、可验收的方案,不能只停留在“支持短信发送”这种描述。我拿到这类材料的第一件事,先把业务功能拆成需求条目,再定义参数,最后转成测试用例。三个步骤做完,功能就不再是口号了。

3.1 用一张业务功能清单启动需求评审

第一个步骤是画业务功能清单。先别急着谈技术选型,逐条标记功能名、触发方、输入输出、异常分支。不要以为PPT里写了“支持短信状态查询”就够了,要往下追问:查询范围是中心缓存还是历史库?状态报告是主动推送,还是上游定时拉取?逾期多久不算等?这些都是需求,不定义清楚,开发和测试会各自理解。

一张可用的清单至少要有下面这几列:

功能编号功能名称触发方正常路径异常路径验收标准
F01下行MT提交业务网关或集团客户校验通过后落库,返回消息ID校验失败返回错误码提交成功率100%,重复消息在10秒内去重
F02状态报告回推下游网元上报更新原消息状态,并推送调用方推送失败进入补推队列状态报告推送失败后自动重试2次
F03上行MO接收手机用户回复解析关键字,匹配路由到业务系统无匹配规则则丢弃或进人工上行消息不丢失,路由时延小于200毫秒
F04流量控制核心网压力过高返回“稍后再试”或进入排队超过阈值直接拒绝不会对下游形成重试风暴

用这张表做需求评审,比逐页过PPT效率高得多。评审时重点看异常分支。PPT通常只画晴天路径,而短信中心的工程工作全在雨天路径上。比如F01的“重复消息去重”:很多中心只做了内存去重,重启后就失效,那这个功能就算没实现。

3.2 关键参数怎么设:重试次数、有效期和队列深度

短信中心有四个参数直接影响线上表现,必须在PPT定稿前确定。我一般会在设计文档里给一张参数配置表,而不是直接写死在代码里。

第一个是最大重试次数。同一个消息下发失败,不能无限重试。行业客户自有网关,建议不超过3次;银行类验证码可以只重试1次;通知类营销类可以到5次。不要图省事给所有业务一个值,要按业务类型建参数表。

第二个是重试间隔。第一次失败到第二次重试之间隔多久?我常用退避策略:1分钟、2分钟、4分钟、8分钟,到最大重试次数后停。如果间隔太短,比如10秒,手机关机后恢复,重试会全部撞在MSC拥塞上,变成互相伤害。间隔太长又有风险,消息还没重试就过了有效期。

第三个是有效期(validity period)。运营商短信中心对有效期有上限,一般不超过48小时;但很多业务其实希望2小时有效,比如验证码。需要在提交方参数和中心配置之间做一次“取较小值”的转换。必须明确规则:上游传了有效期,按上游;没传,按中心默认。如果不做这一步,临期消息的重试策略会完全不可控。

第四个是队列深度。单个队列最多积压多少条消息,超过后是丢弃还是拒绝。我的经验值:队列深度按节点每秒处理能力的10倍配置。比如单节点每秒处理500条,队列深度不要低于5000,但超过5万就要触发告警,说明下游堵了。如果队列设得太大,一条慢路径会把整条消息链路拖死。

下面是一个配置示例,我习惯把参数写成独立配置文件,运行期可热加载:

smsc: max_retry: 3 retry_interval: [1, 2, 4, 8] validity_period: 86400 queue_depth: 50000 high_priority_queue_depth: 20000 flow_control_enabled: true blacklist_check_enabled: true

这段配置的含义是:默认有效期24小时,单队列积压最多5万条,高优先级队列2万条,重试间隔按1、2、4、8分钟递增。注意retry_interval必须与max_retry配合,数组长度要大于等于最大重试次数,否则重试策略会出现“到次数后仍按最后一个间隔继续跑”的隐藏问题。

3.3 从 PPT 幻灯片推导出开发和测试用例

PPT里的每一页“业务功能”都应该能转化成至少一个测试用例。方法很简单:取某个功能描述,抽出主语、动作、期望结果,用下面的模板套。

用例名称:UC-F02-001 状态报告回推成功 前置条件:测试消息已提交,消息ID为已知值,指定接收方号码为正常开机状态
操作步骤:

  1. 调用下行提交接口发送一条短信;
  2. 使用SMPP模拟工具构造deliver_sm状态报告,状态为DELIVRD;
  3. 检查上游回调接口是否收到状态通知。
    预期结果:状态报告关联到原消息ID,回调接口收到状态码DELIVRD,记录状态为已送达。

这个用例看起来简单,但很多短信中心会在这里翻车。特别是步骤2里,模拟工具构造的deliver_sm如果不带正确的消息ID格式,中心不知道怎么关联,只能丢弃。类似这样,把PPT里每个功能点都落到用例,开发完成后对照执行,就是最朴素的验收方式。实践中我还会再加两条“破坏性用例”:重启短信中心看消息是否持久化不丢,拔掉下游连接看消息是否进入重试而不是丢失。

4. 协议对接与业务功能验证:用 SMPP 把中心跑起来

业务功能要落地,必须能通过协议对接验证。短信中心对外最常见的协议是SMPP,理解SMPP的交互过程,再去看CMPP/SGIP这些国内协议就很容易。

4.1 最小对接流程:bind、submit_sm、deliver_sm

对接一个支持SMPP的短信中心,至少要走通三个PDU:bind(鉴权)、submit_sm(提交下行)、deliver_sm(接收状态报告或上行)。下面给一段Python脚本演示最小流程,用smpplib这个常见库。环境里如果没有装,可以找团队已有的测试账号按需安装,代码按实际环境改参数。

import smpplib.client client = smpplib.client.Client('127.0.0.1', 2776) client.connect() client.bind_system(system_id='demo', password='secret') pdu = smpplib.commands.SubmitSM( source_addr='10001', destination_addr='13900000000', short_message='hello smsc'.encode(), registered_delivery=1, # 请求状态报告 data_coding=0, # ASCII validity_period=None # 使用中心默认有效期 ) client.send_pdu(pdu)

逻辑说明:第一步bind_system完成鉴权并建立会话,不绑定后面所有PDU都会失败;第二步构造SubmitSM,registered_delivery=1是关键,它告诉短信中心下发完成后要回状态报告。如果你在PPT里承诺了“状态报告回执”,这个位置必须置位;否则中心不回推,功能缺失就很隐蔽。validity_period=None表示完全使用中心配置,如果业务方要自定义,这里可以填SMPP绝对时间格式,必须带时区。

参数说明:source_addr和destination_addr分别是主叫与被叫,国内短信中心常要求被叫不带+86;data_coding=0表示ASCII,中文需要改成8(UCS2)。注意上面脚本省略了错误码处理和回调注册,只能用来验证联调,不能直接上生产。生产环境还要处理连接保活(EnquireLink定时器)和超时重连,否则网线抖动一次就会中断会话,状态报告全部积压。

4.2 验证状态报告和重试的模拟方法

短信中心业务功能里最难模拟的是状态报告,因为真实终端回执需要入网手机配合测试,效率太低。我一般用两种方式覆盖。

第一种,用SMPP协议的模拟终端脚本。在下行消息提交后,等几秒模拟MSC回一个deliver_sm,内容里带上消息ID和最终状态DELIVRD。这个脚本可以验证中心的状态机能不能把消息ID和状态关联回原消息,并推送上游。

import smpplib.client client = smpplib.client.Client('127.0.0.1', 2776) client.connect() client.bind_receiver(system_id='mock_msc', password='secret') pdu = smpplib.commands.DeliverSM( source_addr='13900000000', destination_addr='10001', short_message='id:ffffffff00000001 stat:DELIVRD done'.encode(), data_coding=0 ) client.send_pdu(pdu)

这个脚本的关键是bind_receiver:SMPP中接收绑定只能接收消息,不能发送MT。发送状态报告时,短消息内容要按短信中心约定的解析格式填,有的中心用id:xxx stat:DELIVRD,有的用TLV字段。如果格式不对,中心会把状态报告当成普通上行消息,导致对账失败。

第二种方式更简单:用短信中心管理台或测试工具,直接改消息状态。很多商用SMSC会在管理端提供“手动模拟状态回执”的入口,开发环境都留着。没有管理台,可以在提交时人为让下游返回临时失败码,看中心是否进入重试流程。重试流程的验证重点不是“有没有重试”,而是“重试次数上限、间隔、以及过期后是否停止”。可以把有效期设成3分钟、重试间隔1分钟,这样能在测试中快速看到从失败到重试再到过期的完整链路。

4.3 与 CMPP/SGIP 的差异和适配要点

国内环境很少直接用国际SMPP对接运营商核心网,更多见的是CMPP(移动)、SGIP(联通)、SMGP(电信)。但短信中心对外业务网关侧,SMPP仍然很常见。做方案时如果只写SMPP,容易忽略国内协议差异。我一般会在设计稿里加一张协议对比表。

特性SMPPCMPPSGIP/SMGP
连接方式长连接+并发请求长连接+消息头序列号长连接+源目节点
鉴权方式bind时带系统ID和密码连接时MD5鉴权连接时鉴权
状态报告通过deliver_sm回推通过CMPP_DELIVER回推通过SGIP_REPORT回推
长短信分片分包+用户头分包+用户头分包+用户头
消息ID字符串,提交响应返回整型MsgId,占用较大空间序列号派生

适配时最容易翻车的是消息ID:SMPP的消息ID是字符串,CMPP的MsgId常常是整型,中间转换时如果丢了前导零,状态报告回推就找不到原消息。我的做法是在短信中心内部统一维护一个全局消息流水号,外部协议的消息ID只作为映射表字段,不直接参与内部关联。这样无论上游用哪种协议,状态报告都能回到同一条原始MT。

长短信分片同样是适配重点。PPT里如果写了“支持长短信”,要在协议适配里明确:分片消息带UDHI头,分片顺序必须保持,同一条长短信的所有分片要走同一个下行通道。如果走不同通道,终端侧可能收到乱序分片,用户看到的内容就是乱的。

5. 短消息中心业务功能的避坑实录:现象、原因与解决

短信中心的功能问题不是靠PPT写得多漂亮能解决的,都是从线上踩坑踩出来的。这里选四条我见过最多的翻车点,按现象、原因、解决写清楚。

5.1 状态报告丢失导致对账不平

现象:早上运营发现日报里“计费成功”比“已送达”高出一截,查消息记录却发现短信中心明明收到了状态报告,上游就是没收到。

原因:状态报告回推失败后没有补推机制。尤其是在SMPP会话中断时,deliver_sm在传输中丢失,中心只记录状态,不会主动重推。

解决:在中心增加状态报告暂存区。上游收到报告后回ACK确认,确认后的报告清除;未确认的报告进入补推队列,补推次数上限设为3次。同时在管理台保留状态报告查询入口,极端情况下可把导出合并给上游。补推队列本身也要限流,防止状态报告积压处理不过来。

5.2 重试风暴打爆短信中心

现象:某个通知类任务下发后,MSC高峰响应“系统忙”,结果这个任务的内部重试把后半夜的吞吐占满,连银行验证码也被堵在后面。

原因:重试策略没有和拥塞控制联动。所有失败消息按固定间隔重复提交,失败越多重试越多,形成放大器。

解决:把重试划分为两个层次。第一层在发送通道内按退避间隔重试;第二层为超过退避窗口的消息进入重试队列,由调度器统一控制并发。每次下发前检查当前发送通道的积压数,积压超过阈值时暂停重试,只保留高优先级。重试次数上限必须强制生效,宁可丢掉一条低优先级消息,也要保住整条链路的稳定性。

5.3 有效期参数设错导致消息被提前丢弃

现象:用户早上发的短信,过了十分钟就发不出去,看起来状态是“已过期”,但业务方坚持说填的有效期是24小时。

原因:上游把有效期理解成“消息生成时间”,中心却把它当“过期时间”解析。很多平台默认有效期是“当前时间+有效期秒数”,如果上游填的是绝对时间且时区不对,就会直接变成过去时间戳。

解决:在消息入参时强制校验有效期字段:必须大于接收时间,且小于运营商上限;不合法就按中心默认有效期处理并给上游告警。同时,在配置更新时做取交集,而不是直接覆盖。上游要求48小时,中心默认24小时,应该按24小时生效,而不是反过来。

5.4 黑名单只做发送侧拦截,漏掉状态报告回执

现象:用户已退订并加入黑名单,但状态报告仍然回推给上游,导致上游客户在后台看到“我还在给已退订用户发消息”。

原因:黑名单过滤只拦截了MT提交,没有覆盖状态报告回推路径。已经发送到黑名单用户的消息,其回执依然会触发对账和计费。

解决:把黑名单检查放在两个点。第一,MT提交时校验并拒绝新建发送请求;第二,状态报告回执时校验,如果原消息属于黑名单且为营销场景,则不回推业务方。注意,退订用户的最后一次消息的状态报告应当正常返回,否则退订流程无法闭环,业务方永远不知道用户收到了退订确认短信。

5.5 长短信分片顺序错乱

现象:超过70字的短信被拆成两条,用户收到时内容顺序颠倒,看起来就是乱码。

原因:长短信通过用户头信息标识分片序号,但分片被负载均衡到不同通道或者被不同调度周期发出后,接收终端可能先看到后片再看到前片。短信中心没做通道合并,直接把分片当成独立消息下发。

解决:同一条长短信的所有分片必须绑定同一个发送通道并串行下发。如果中心有多通道负载均衡,要按“长短信唯一会话ID”哈希到固定通道。协议层也要把TPID设置为带UDHI,让对端知道按用户头重组。验证时用超过140字的文本,连续发100条,检查终端收到的顺序是否完全一致。

6. 用一套验证 checklist 确认业务功能完整

6.1 从发送到回执的六步检查

我把短信中心业务功能验收浓缩成一个清单,每个功能点都对应一个可观测的步骤,不满足就继续调,不急着发版。

功能点验证方法通过标准
接收提交用SMPP脚本提交不同编码的消息非法长度返回错误码,合法消息落库
存储持久化提交后杀掉短信中心进程再启动消息不丢失,重启后能继续下发
路由队列同时压入高优先级与普通消息高优先级先发出,且时延明显更低
重试与过期用模拟失败码触发重试间隔符合配置,过有效期后停止
状态报告回推模拟deliver_sm回报告上游收到报告,消息ID能对上
上行响应模拟手机回短信正确路由至对应业务系统

6.2 用日志统计确认功能没有虚设

最后要看日志,不要只看管理台界面。我习惯在系统运行二十分钟后,从守护进程日志里统计每次提交、下发失败、重试、状态报告的条数占比。下面是一条简单的Shell统计命令:

grep 'msg_status' /var/log/smsc/smsc.log | \ awk '{print $NF}' | \ sort | uniq -c | sort -rn

如果FAILED比例超出预期,或者RETRY数量远大于正常值,说明PPT里承诺的重试功能和实际参数没有配合好。正常的重试占比应该维持在一个低位,比如总下发量的1%到3%。超过这个数,要么参数给了太多重试次数,要么下游通道有问题。这条命令只是验证入口,真正完整的检查还要把状态机日志串起来,确认每条消息从提交到最终状态都有轨迹。

我现在的习惯是每次接手短信中心需求,不管对方有没有PPT,先把上面的六步清单过一遍,再单独补上重试和状态报告两个黑盒测试。比起反复翻PPT里写了什么功能,这是更快的确定方案的办法。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表