这是一个创建于 3455 天前的主题,其中的信息可能已经有所发展或是发生改变。
本文来自于个推CTO叶新江在2015Qcon的分享整理。
截止2015年6月,个推SDK累计接入总用户数达50亿 (其中海外近5亿),接入应用超过35万,开发者人数近20万,覆盖独立终端超过8亿(其中海外超过1亿),日均活跃用户近6亿,日分发消息20亿条。
这么庞大的数据,是如何做到的呢?2011年公司做的是小规模IM产品,发展思路偏向于拿来主义,和很多开发者一样会选择MySQL来作为网站数据库。到了2011年,重新设计了系统架构,选择了更为开源的大并发通信系统;直至去年,多地协同、流式处理的理念应运而生,形成了大分布及大数据的处理系统。从单点的数据库到点与点的通讯,再到网络结构系统,不仅需要克服思维上的局限,更需要挑战服务器的极限。
例如:延迟和吞吐量,用户多了之后如何在保证延迟可接受的情况下达到想要的吞吐?关于这点大家可以回想下Java虚拟机的垃圾回收算法。
以下是开发大并发通信系统的相关经验:
1.内部服务调用方式
关于调用方式,异步非侵入式是首选。无需等待返回值的函数调用绝对拥有最高的收益,辅以非侵入调用就能最大程度上减少对目标程序的占用。
2.JVM及线程调优
个推选择CMS(Concurrent Mark-Sweep)作为GC(Garbage Collection),默认了92%的回收触发条件。另外要注意的是Linux下的性能调优,如MAT的使用,利用 top-p-H 来查看CPU占用情况,利用jstack,jmap命令定位问题所在等。
3.TCP 阑尾
TCP是全双工的,因此关闭连接必须要在两个方向上分别进行,反复的通道开启和关闭很容易带来问题。起初TW(Time Wait)就是为了克服不稳定的网络带来的丢包等问题,如今随着网络技术的发展,TW已经成了鸡肋。另外,虽然说TW状态的连接既可以被回收(Recycle)又可以被重用(Reuse),但没有人愿意冒这双重风险。在二者选其一时,能在时间戳上满足接入规律的Reuse有着明显的优势。
4.健壮保障
需要重点关注:关键词,如流控、维稳、异常隔离、分降级、断续处理等。就流控而言,有可能出现SDK发送数据存在逻辑问题而导致浪涌现象的情况。
5.分布式事务
如何在分布式情况下实现将100元钱从A转到B?传统思维是按照A.C.I.D原则进行操作。A.C.I.D指数据库事务正确执行的四个基本要素。包含:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。这里我详细讨论下另一种替代方案——B.A.S.E,Basic Availability:基本可用;Soft-state :软状态/柔性事务,可以理解为”无连接”的, 而 “Hard state” 是”面向连接”的;Eventual consistency:最终一致性,最终整个系统(时间和系统的要求有关)看到的数据是一致的。在B.A.S.E中,强调可用性的同时,引入了最终一致性这个概念,不像A.C.I.D,并不需要每个事务都是一致的,只需要整个系统经过一定时间后最终达到是一致的。首先确定考虑因素,即用什么方式来分割交易事务,资源方面有哪些要求,如何保证幂等性。
接下来是具体实现方式,流程如下:
1.设置业务交易记录表 T, 并建立一套和 T 相同存储的队列 Q
2.记录交易到 T, 同时放入队列 Q, 两个动作一个事务
3.A设置一个已处理交易记录表TA
4.监测 Q, 如果有给 A 的交易请求,则
开始事务
查看 TA 中是否有处理过此交易
If没有处理过 then
更新 A 记录
把处理痕迹写入 TA
end if
结束事务
If 上面的事务处理成功 then
Q出列
end if
1. B也按上述方式处理
使用分布式事务有助于简化应用开发,使用消息队列明显需要更多的工作量,两者各有优劣。
总结:对于时间紧迫或者对性能要求不高的系统,应采用分布式事务加快开发效率,对于时间需求不是很紧,对性能要求很高的系统,应考虑使用消息队列方案。对于原使用分布式事务,且系统已趋于稳定,性能要求高的系统,则可以使用消息队列方案进行重构来优化性能。
6.关于前瞻和成本
举个简单的例子——数据分区。实施前确定需要的资源,事先规划和分割,看到资源的限制后安排后期数据搬迁,最后利用redis内存分配占用。