实现千万级用户量的微信公众号平台的研发
2019-07-16唐煜舟
唐煜舟
摘要:该文分析了现有微信公众号平台存在的问题,对如何优化现有微信公众号平台以便支持千万级用户访问量的总体需求进行了分析,介绍了系统架构调整的原因以及如何调整,具体的调整内容以及如何实现。
关键词:微信公众平台;异步;队列;缓存
中图分类号:TP311 文献标识码:A
文章编号:1009-3044(2019)15-0096-04
1 概述
J银行信用卡中心微信服务号自2014年1月正式上线以来,累计关注用户数已突破2000万,绑卡用户数已突破1700万。微信服务号已经成为卡中心电子渠道中最为活跃、最为重要的一个部分,同时也成为卡中心市场推广、营销的最重要的手段之一。
预计2019年底J银行信用卡中心微信服务号关注用户数将突破3000万,对微信公众号平台自身的容量及可用性提出了更高的要求。卡中心微信服务号定时全量客户群发也会对卡中心各个系统造成冲击。
本文分析了为达到业务目标现有微信公众号平台存在的问题,对如何支撑业务目标改造现有微信公众平台的总体需求进行了分析,探讨了如何优化J银行卡中心现有微信公众号平台的系统架构并重构部分功能以支持千万级用户量的微信公众号平台。
2 总体需求分析
为满足2019年底微信服务号关注用户数达到3000万的业务目标,微信公众平台亟须解决问题如下:
1) 腾讯与微信公众号平台对接的网络不稳定
腾讯通过J银行总行payment域名与卡中心微信公众号平台对接,网络链路长、故障点多,已多次发生由于线路故障导致交易中断的情况。
2) 业务高峰期系统响应慢
在用户账单日或者J银行信用卡开展大型活动期间,瞬间用户访问量超过微信公众号平台、后端业务系统容量上限时,会造成响应缓慢甚至无响应情况。同时,腾讯在大量请求无回复后会重复发起请求,用户也会在系统无响应后重复点击微信公众号菜单,导致情况进一步恶化。
3) 下发模板消息无流量控制
后端业务系统对接微信公众号平台发送模板消息,如访问腾讯服务器的线路故障,将导致请求积压,影响微信公众号平台、后端业务系统的并行处理能力,甚至导致系统宕机。大量的下发模板消息也容易引导用户访问J银行卡中心诸如官网、App、商城等其他对外系统,造成对其他系统冲击,引发其他系统宕机。
为解决上述问题,微信公众号平台亟须优化现有架构,以便系统容量能够满足日益增长的业务目标。
3 系统架构设计
用户关注J银行信用卡中心微信公众号,在3*5菜单或者对话框中输入问题,点击发送后至腾讯,腾讯将用户的请求发送至J银行总行payment域名。J银行总行payment域名将消息转发至微信公众号平台,Proxy软负载服务器收到请求后,将请求随机分发至多台Robot服务器中的某一台,Robot服务器调用平台的AI引擎获取后续操作指令后调用后端业务系统返回处理结果。
后端业务系统也可以通过调用微信公众号平台的下发/群发服务器,将营销内容、交易提醒等实时模板消息发送至腾讯,腾讯将实时模板消息推送至用户的微信号上。
现有系统架构如图1。
上述架构存在消息接入链路长、每笔消息同步回复容易对后端系统造成冲击、系统响应慢导致用户重复请求以及实时模板下发无法实现流控等等弊端。现有微信公众号平台架构已无法满足2019年底微信服务号用户数达到3000万的业务目标,更无法适应互联网用户无规律、大并发、脉冲式的访问。故本文引入专线接入、异步回复、队列机制、缓存机制、重复请求甄别机制、实时模板下发流控等机制,对系统架构进行调整。
调整后系统架构如图2。
4 具体调整内容
4.1 专线接入
目前腾讯平台发送微信公众号平台的报文需通过J银行总行payment域名及总行DMZ、卡中心办公网转发。卡中心主动访问腾讯服务器有2条线路,一条是通过卡中心DMZ的外网出口(备用线路),一条是通过电信的专线出口(主用线路)。
现有接入方式如图3。
现有平台与腾讯服务器的接入方式存在线路环节较多、延时较大、出故障概率高、问题排查较复杂等问题。为解决上述问题,改进机制如下:
1) 通过电信、铁通专线直连腾讯机房,跳过中间环节,减少故障概率。
2) 平台入口由电信、铁通专线在物理层面形成主备,同时保留卡中心DMZ出口,将腾讯服务器的地址作为基础参数,快速实现出口网络(专线、互联网)环境切换。
调整后采用专线接入方式如图4。
4.2 异步回复
目前微信公众号平台所接收到的服务请求会通过平台自有的Proxy软负载服务器平均分配至3台Robot服务器,如果后端业务系统响应超过4s则回复空串。
未采用异步回复方式如图5。
4S等待时间并无太大意义,一旦超时,对于用户请求来说相当于浪费了4S。同时,由于延迟响应,将堆积后续服务请求,对系统造成更大的压力。为解决上述问题,改进机制如下:
1) Proxy软负载服务器将请求放入队列服务器后即返回空串,具体实现如下:
//返回腾讯空字符串内容
String con = "success";
//直接在IO中返回将空字符串内容返回腾讯
out.write(con);
// 將请求放入队列服务器
executor.execute(new Runnable() {
public void run() {
KafkaUntils.push(topic_req, openid, reqxml);
}
});
2) 由后端Robot服务器从队列服务器中获取请求并处理用户的请求后异步返回结果,具体实现如下:
channel.send(return.get(resp));
调整后采用异步回复方式如图6。
4.3 队列机制
微信公众号平台在接收到用户同时大量并发请求后直接发送至后端,在超出后端处理能力的情况下,将导致对后端资源的争抢,后端处理响应将变慢,交易耗时增加。
未采用队列的方式如图7。
采用队列后,微信公众号平台将以后端能够承受的速度发送请求。假设1笔交易平均耗时0.25s(平均5个接口*50ms=0.25s),在后端系统不扩容、响应不变的前提下,如果交易量增加1倍,则原有用户交易不受影响,新增一半用户交易时长增加0.25s,但预计可抵消由于交易量激增导致的后端响应缓慢问题。
采用队列后的效果如图8。
采用消息队列技术,所有的用户请求都先进入到队列服务器中,程序保持先进先出的原则顺序读取队列并对所有用户的请求进行处理。Proxy服务器根据算法将不同用户的消息放置入不同队列中,不同Robot服务器从不同队列中获取消息。Proxy服务器监控队列深度,一旦发现某队列深度超过最大值,则判为Robot服务器故障,改变分发策略。同时,队列深度超过一定阈值还会触发告警,以便运维人员及时了解Robot服务器、后端业务系统是否存在故障。
Robot服务器以指定的速度(考虑后端业务系统处理能力)从队列服务器中获取消息后送后端业务系统处理。Robot服务器将返回消息放入队列服务器,由Proxy服务器以最快速度發送腾讯。
队列机制具体实现如下:
Map
List
//从队列中获取数据以指定频率发送后端业务系统处理
if(topic.equals(PropertiesUtil.getValueByKey("topic"))){
ExecutorService executor = Executors.newFixedThreadPool(Integer.parseInt(a_numThreads));
for (final KafkaStream stream : streams) {
executor.submit(new KafkaMasssendThread(stream));
}
}
队列方式的技术实现如图9。
4.4 缓存机制
在业务处理的过程中,引入Redis缓存读取机制,即在处理请求前查看是否存在可用的缓存内容并加以使用,以及在完成业务处理后将结果保存到缓存中以供重复使用。
缓存设计在以下几个场景中使用:
1) 对腾讯端内容的缓存:缓存请求响应报文中的Token供系统生成报文时使用,具体实现如下:
URLConnection conn = new URL(tokenUrl).openConnection();
ByteArrayOutputStream bytesOut =
new ByteArrayOutputStream();
accessToken = new String(bytesOut.toByteArray(), "UTF-8");
2) 对绑定关系的缓存:缓存用户微信openid与用户账户usrid的绑定关系、用户下挂卡关系,具体实现如下:
Object[] bindinfo = bindService.isBind(openid, nickname);
3) 对每个用户操作行为缓存:供对重复请求判断时使用,具体实现如下:
boolean isRepeat = RedisService.isRepeat(openid, action);
缓存机制技术实现如图10。
4.5 重复请求甄别机制
Proxy服务器每次接收请求后从Redis缓存服务器中获取用户操作行为,对用户在短时间内重复请求的甄别,按照一定规则(例如10s内同类型重复请求)排除重复请求防止对系统资源的浪费:
1) 如果为重复请求,将重复请求放入重复请求的队列中,由存储服务器记录供相关维护人员查看。
2) 如果不为重复请求,则缓存用户请求后将用户请求放入队列中供Robot服务器处理。
3) 对于短时间内来源于同一用户的大量重复请求做出预警,有相关人员来判断是否属于恶意攻击。
重复请求甄别机制具体实现如下:
boolean isRepeat = RedisService.isRepeat(openid, action);
if(isRepeat){
//重复请求放入相应队列供业务人员、运维人员分析
KafkaUntils.push(topic_req, openid, reqxml);
}else{
//正常请求由Robot服务器处理
int result = this.proxyClient.executeMethod(post);
}
重复请求甄别机制技术实现如图11。
4.6 实时模板下发流控
现有微信公众号平台的下发/群发模块在收到后端系统的下发请求后直接将下发请求发送至腾讯服务器。如腾讯服务器响应超时,将影响使用下发接口的后端业务系统。同时,平台直接接收后端系统的下发请求并实时发送,无法对下发的模板实现并发数等流量控制。
调整前实时模板下发方式如图12。
改造后,微信公众号平台下发/群发服务器在收到下发请求后将消息写入队列服务器并立刻返回后端系统,Proxy服务器从队列服务器中获取下发请求后发送腾讯。
实时模板下发流控具体实现如下:
//流控队列线程池处理
ExecutorService executor = Executors.newFixedThreadPool(Integer.parseInt(b_numThreads));
for (final KafkaStream stream : streams) {
executor.submit(new KafkaMasssendThread(stream));
}
}
调整后实时模板下发方式如图13。
4.7 实时模板消息回执处理
微信公众号平台在实时模板消息发送后对消息的发送回执进行判断:对于未发送成功的消息回执进行存储,并生成相应报表,后期可通过人工干预的方式进行处理。
消息回执中包含以下有用内容:用户openID、所发消息messageID、发送是否成功标示、发送失败原因标示(用户屏蔽、其他原因)。
具体实现如下:
//模板消息回执放置入队列稍后处理
if event.equals("TEMPLATESENDJOBFINISH") {
executor.execute(new Runnable() {
public void run() {
KafkaUntils.push(topic_templatesend, openid, reqxml);
}
});
}
實时模板消息回执处理实现方式如图14。
5 结束语
通过引入专线接入、异步回复机制、队列机制、缓存机制、重复请求甄别机制、实时模板下发流控等机制后,J银行卡中心微信公众号平台系统容量、可靠性、稳定性获得了极大的提升。
平台架构调整后,微信公众号平台性能、容量可满足2019年底J银行卡中心微信服务号关注用户数达到3000万的业务目标,J银行卡中心微信公众号更是获得了信用卡行业关注用户数、品牌影响力、美誉度等综合排名仅次于行业标杆招行信用卡的微信公众号。
【通联编辑:代影】