使用背景
场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种串行的方式;并行方式。
1、串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端。
2、并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信。以上三个任务完成后,返回给客户端。与串行的差别是,并行的方式可以提高处理的时间。
引入消息队列,改造后的架构如下:
按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此用户的响应时间可能是50毫秒。因此架构改变后,系统的吞吐量提高到每秒20 QPS。比串行提高了3倍,比并行提高了两倍。
业务解耦:
一个事务,只关心核心的流程。而需要依赖其他系统但不那么重要的事情,有通知即可,无需等待结果。换句话说,基于消息的模型,关心的是“通知”,而非“处理”。
1、传统模式
场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。如下图:
缺点:
假如库存系统无法访问,则订单减库存将失败,从而导致订单失败;
订单系统与库存系统耦合;
2、消息队列模式
订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。
最终一致性:
最终一致性指的是两个系统的状态保持一致,要么都成功。
广播:
消息队列的基本功能之一是进行广播。如果没有消息队列,每当一个新的业务方接入,我们都要联调一次新接口。有了消息队列,我们只需要关心消息是否送达了队列,至于谁希望订阅,是下游的事情,无疑极大地减少了开发和联调的工作量。
错峰流控:
对于需要强事务保证而且延迟敏感的,RPC是优于消息队列的。对于一些无关痛痒,或者对于别人非常重要但是对于自己不是那么关心的事情,可以利用消息队列去做,如下图。
整体架构
消息队列,本质是两次RPC加一次转储,当然需要消费端最终做消费确认的情况是三次RPC。既然是RPC,后续需要处理负载均衡、服务发现、通信协议、序列化协议等,如下图所示。
消息架构
RabbitMQ是流行的开源消息队列系统,用erlang语言开发。RabbitMQ是AMQP(高级消息队列协议)的标准实现。支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX,持久化。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。如下图所示:
安卓端设备
由上图可知:后台会架构出消息的server端(中转处理/存储消息),移动端设备属于client端(负责订阅/收发消息)。
消息通讯:
消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。android一般会基于此实现比如实现点对点消息队列,或者聊天室等功能。实际是消息队列的两种消息模式,点对点或发布订阅模式。
点对点:客户端A和客户端B使用同一队列,进行消息通讯。
聊天室:客户端A,客户端B,客户端N订阅同一主题,进行消息发布和接收。实现类似聊天室效果。
移动端IM客户端的坑
1. 流量:
采取哪种协议、图片缩略图、附件的压缩三点决定了流量的大小。
2. 耗电:
(1)流量越小,耗电越低。(2)心跳策略,减少心跳次数,耗电量就会降低。
3. 心跳时长:
wifi,2G,3G,4G,移动、电信、联通,不同网络,不同运行商,NAT失效时间不一样,因此心跳的时间也就不一样。
4. 网络连接:
cmnet和cmwap下连接处理机制。
5. 网络不稳定:
移动端最大的特点就是网络不稳定,在不稳定的网络状态下,如何保证消息以最快的速度到达?如何避免重联风暴?这些既需要从整体架构考虑,也需要在移动端采取巧妙的策略加以避免。
IM应用层协议设计
1. XMPP协议:
优点:基于xml协议,容易理解,使用广泛,易于扩展。
缺点:流量大,在移动终端也耗电。交互过程复杂。多被pc时代的产品使用,不适合移动时代的IM产品,即使我们基于xmpp进行改进,简化握手过程,改进文件传输机制,但是它的基因决定了如何改进,他都不适合移动互联网时代的IM产品。就像凤姐无论怎么整容,也变成不了高圆圆一样。
2. MQTT协议:
优点:适配多平台。
缺点:协议简单,但是需要自己扩展好友,群组等功能。
3. 私有协议:
优点:随心所欲,自己定义,流量小。
缺点:工作量巨大,扩展性差,需要考虑全面。
4. Protobuf协议:
优点:非常小、非常快、非常简单,一条消息数据用Protobuf序列化后的大小是JSON的1/10、XML格式的1/20、是二进制序列化的1/10。
缺点:不能表示复杂的数据结构,但是对于IM来讲,已经足够。强烈推荐此协议。
IM安全层协议设计
im协议,消息的保密性非常重要 ,谁都不希望自己聊天内容被看到,所以安全层是必不可少的。
1、使用SSL
证书管理微微复杂,代价有点高。
2、自行加解密
自己来搞加解密,核心在于密钥的生成与管理,密钥管理方式有多种,主要有这么三种:
(1)固定密钥
服务端和客户端约定好一个密钥,同时约定好一个加密算法(eg:AES ),每次客户端im在发送前,就用约定好的算法,以及约定好的密钥加密再传输,服务端收到报文后,用约定好的算法,约定好的密钥再解密。这种方式,密钥和算法对程序员都是透明的。
(2)一人一密钥
简单说来就是每个人的密钥是固定的,但是每个人之间又不同,其实就是在固定密钥的算法中包含用户的某一特殊属性,比如用户uid、手机号、qq号等。
(3)动态密钥(一session一密钥)
动态密钥,一Session一密钥的安全性更高,每次会话前协商密钥。密钥协商的过程要经过2次非对称密钥的随机生成,1次对称加密密钥的随机生成,具体详情这里不展开,有兴趣的同学可以看下SSL密钥协商额过程。
参考: