基于SMPP 3.4的批量SMS平台:go-smpp包发送千条后超时问题求助
解决go-smpp批量发送SMS超时问题的方案
1. 优化连接管理
- 改用连接池:单连接并发提交请求容易触发SMPP服务器限流或窗口耗尽,初始化多个Transceiver会话组成连接池,轮询使用不同连接提交请求,分散负载。
- 自动重连机制:监听会话的错误事件,当检测到超时、连接断开等异常时,销毁旧连接并重新建立会话,避免进程直接终止。
2. 控制发送流量
- 限制发送速率:不要一次性提交全部1000条短信,根据服务商要求设置速率(通常10-50条/秒),用令牌桶或
time.Tick控制发送节奏,避免服务器过载。 - 调整SMPP窗口大小:初始化会话时通过
smpp.WindowSize(N)配置未响应请求的最大数量(N值需符合服务商限制),避免因窗口占满导致后续请求超时。
3. 调整超时配置
- 延长请求超时:初始化Transceiver时设置更长的
smpp.Timeout(10*time.Second),适配批量发送时的服务器响应延迟。 - 优化心跳间隔:通过
smpp.EnquireLinkInterval(30*time.Second)调整EnquireLink发送频率,保持会话活跃,避免被服务器判定为空闲断开。
4. 实现错误重试与异步处理
- 请求重试逻辑:针对超时的
SubmitSM请求,加入重试队列,采用指数退避策略重试3-5次,同时为每条短信添加唯一ID避免重复发送。 - 异步响应处理:不要同步等待单条短信响应再发下一条,异步提交请求并监听
SubmitSMResp通道批量处理响应,避免阻塞发送流程。
5. 会话健康检查
- 定期心跳检测:定时发送EnquireLink请求,若连续多次无响应立即触发重连。
- 监控连接状态:记录每个会话的请求成功率、响应时间,当超时率超过阈值时,切换到连接池中的其他可用会话。
代码示例片段
// 初始化连接池 func NewConnPool(size int, addr, user, pass string) ([]*smpp.Transceiver, error) { pool := make([]*smpp.Transceiver, 0, size) for i := 0; i < size; i++ { tc, err := smpp.NewTransceiver(addr, user, pass, smpp.Timeout(10*time.Second), smpp.EnquireLinkInterval(30*time.Second), smpp.WindowSize(50), ) if err != nil { return nil, err } pool = append(pool, tc) } return pool, nil } // 带速率控制的批量发送 func BatchSend(pool []*smpp.Transceiver, messages []string, rate int) { ticker := time.NewTicker(time.Duration(1000/rate) * time.Millisecond) defer ticker.Stop() idx := 0 for range ticker.C { if idx >= len(messages) { break } tc := pool[idx%len(pool)] msg := messages[idx] go func(t *smpp.Transceiver, m string) { pdu := smpp.NewSubmitSM() pdu.SourceAddr = "YOUR_SHORT_CODE" pdu.DestAddr = "RECIPIENT_NUMBER" pdu.ShortMessage = []byte(m) resp, err := t.Submit(pdu) if err != nil { log.Printf("Submit failed: %v, message: %s", err, m) // 此处可加入重试队列逻辑 return } log.Printf("Message sent, msgid: %s", resp.MessageID) }(tc, msg) idx++ } }
内容的提问来源于stack exchange,提问作者jucan
相关产品推荐
相关产品推荐

