作者:AngryFox 分类: Uncategorized May 7th, 2016 暂无评论

不为用不到的特性付出代价 仅为用到的特性付出最低代价
这是C++的设计原则,也是Rust的设计原则
GC的终极目的是安全地释放内存 • Rust通过Ownership和RAII也能达到此目的,且性能更好
内存安全?
安全地读写内存 • 在限定时间和空间范围内读写内存 • 防止被他人意外修改或释放 • 避免访问空指针和野指针
安全地释放内存 • 在恰当的时机释放 • 确保释放,不遗漏 • 仅释放一次

内存不安全?
• 指针越界访问,意外修改别处内存 • 内存被提前释放,形成野指针,非法读写内存 • 野指针又转化为合法指针,意外修改别处内存 • NULL指针解引用,非法操作 • 并发读写同一内存地址,数据竞争 • 缓冲区溢出、段错误……

实现async的不同机制
callback
generator
async/await
monad

在高并发的分布式系统中,重要点:
1)大系统小做,把一个大的系统拆分成很多小的独立的服务,降低系统的复杂性
2)需要一套成熟的通信框架,来提高开发效率。
3)尽量避免使用多线程,最好是多进程、无锁设计。
4) 做好过载保护、监控和灰度。(这个很重要)

推送系统
1) 接入层性能问题
原来的接入层单台服务器最多接入30W长连接,而且很多业务逻辑也放在了接入层处理,导致接入层性能低下,而且代码很臃肿,维护成本很高,所以我们对接入层做重构,把业务逻辑拆分出来,接入层只做简单的用户接入。所有的业务逻辑都在后端处理。也就是现在比较流行的微服务的架构。
2) 带宽问题
最初我们的系统使用的是文本协议,每次做全网推送都占用了IDC大量的带宽,导致用户访问其他业务非常慢,我们就自定义了一套二进制协议,降低了50%-70%的带宽。
3) 服务化的基础组件
第一点里面提到 我们的一些业务逻辑是和接入层搅在一起的,我们需要把业务逻辑拆分成单独的服务。服务之间的互相调用就需要一套成熟的网络通讯框架。我们就做了一套RPC的框架,来提高开发的效率。最初这套框架用的多线程+同步调用,在实际的使用中发现,多线程有很多坑,各种锁,特别是新员工写代码一不小心就死锁了。而且同步调用的性能并不理想,虽然开了多线程,但是线程又不能开的太多(大家都懂的)。针对以上情况,我们做了第二版的框架,使用了多进程+异步,服务的性能提高了10倍,但是又面对另外一个问题,因为异步,就没有办法避免各种回调,本来很连续的一个业务逻辑流程被打散在了各种回调函数里面,看代码的人非常痛苦,而且很容易产生内存泄露问题,比如:我申请的内存传递到回调函数中,结果忘记释放了(我们发现的内存泄露问题95%都是这样产生的)。
最后,我们参照go语言的特性使用协程来做了第三版的框架,业务开发人员再也不用考虑同步的性能和异步的回调问题。同步调用方式、异步的性能。
4) 存储
引入了redis和mongodb来做缓存和消息存储。
因为redis是有单点问题,我们开发了一套redis集群,一是提高redis的存储容量,二是解决单点的风险。
根据业务形态选择合理的片键,尽量手动分片。
mongodb自带的balancer最好在业务低峰期做。
合适的索引。

微服务提倡的足够小、可独立部署、升级、伸缩和运维确实能够提升系统的敏捷性,满足业务的快速发布和敏捷交付,降低运维成本。

分布式服务框架的关键技术有三点:

1) 底层远程服务调用使用的RPC框架,它负责链路的创建、跨网络通信、消息的发送和接收、消息序列化和反序列化等。
2) 服务的调度和透明化路由,涉及到服务的发布和消费、服务的透明化路由和软负载,以及集群容错等。
3) 服务治理: 服务化之后,如何保障服务线上高效运行,服务发生故障之后如何快速恢复业务,需要一套功能强大和成熟的服务治理体系来保障服务的SLA。