高并发系统设计之道(一)- 方法论

315 阅读4分钟

1 解决思想

业务发展必然带来洪水般流量,为持续确保系统可靠稳定,我们也得会“大禹治水”。万变不离其宗,目前主流其实方案都可归类如下三种思想:

1.1 Scale-out

一种分治思想,采用集群将流量分散于各服务器。像数据库一主多从、分库分表、存储分片都是其思想的实际方案体现。网上有个例子很生动,假设现在有1口锅,可以一次给10人做饭。突然要给100人做饭,scale-out就是扩展到10口锅来做饭

1.2 缓存

使用缓存来提高系统的性能,就好比水库,抵御了大部分流量冲击,尽力保证下游的平安。也就是1口锅在人来之前做10次。

几乎所有服务都会用到缓存,可谓是现实的万金油。比如CPU的一级缓存、二级缓存、三级缓存,操作系统缓存(如windows的page.sys文件),MyBatis的一级缓存,二级缓存等。

缓存主要是能够显著提升系统的访问性能,更好支持高并发场景的访问。

因为数据是放在磁盘持久化保存的,而用的最多的就是普通磁盘。

  • 普通磁盘的寻道时间大约10ms
  • CPU执行指令和内存寻址的时间都是ns级
  • 从千兆网卡上读取数据的时间是μs级

所以磁盘最慢,因此通常利用内存作为存储缓存的介质,才能提升性能。

1.3 异步

有时未处理完成之前,可以让请求先返回,在数据准备好之后再通知请求方,即可在单位时间内处理更多请求。也就是 100人来了,让大家先拿着碗儿等着,做好饭了再给大家一个个盛过去,而不要都挤死在锅边。

与之相反的是同步,同步调用代表调用方要阻塞等待被调用方法中的逻辑执行完成。这种方式下,当被调用方法响应时间较长时,会造成调用方长久的阻塞,在高并发下会造成整体系统性能下降甚至发生雪崩。

异步调用则相反,调用方不必等待方法逻辑执行完成就可返回执行其他逻辑,在被调用方法执行完毕后再通过回调、事件通知等方式将结果反馈给调用方。

异步在高并发系统中也是常客了,我们也很容易观察到,比如订高铁票时,页面会提示你系统正在排队,其实就是系统在异步处理我们的订票请求。因为在12306中查余票、下单和更改余票状态等都是较耗时的操作,涉及多个系统间互相调用,如果还坚持同步,那高峰期你永远别指望能下单成功。

采用异步的话,后端处理会把请求丢到MQ,同时快速响应用户,通知其系统正在排队处理,然后释放出资源来处理更多请求。订票请求处理完后,再通知用户订票成功或失败。

处理逻辑后移到异步处理程序中,Web服务的压力小了,资源占用的少了,自然就能接收更多的用户订票请求,系统承受高并发的能力也就提升了。

这其实就是解藕操作,订单成交的消息需要保证的是准确性而不是实时性,因此就先放入 MQ,消息被消费的时候在进行业务的处理,这样就可以提高并发性能。

2 架构演进最佳实践

既然有这三种方案,是不是就该在高并发系统设计中一股脑全用上? of course not!架构设计是演进的,不是一次性的!还需要考虑资金成本,运维成本、开发成本各种。淘宝的成功就是现实的生动案例。

不能为了设计而设计,不要过度设计。单机满足业务需求就不要分布式,架构不能盲目,架构一定是逐步演进的,而且是随着业务的需求逐步进行的。可总结如下:

  • 最简单的系统设计满足业务需求和流量现状,选择最熟悉的技术体系
  • 随着流量的增加和业务的变化修正架构中存在问题的点,如单点问题、横向扩展问题、性能无法满足需求的组件。在这个过程中,选择社区成熟的、团队熟悉的组件帮助我们解决问题,在社区没有合适解决方案的前提下才会自己造轮子
  • 当对架构的小修小补无法满足需求时,考虑重构、重写等大的调整方式以解决现有的问题。

高并发系统的演进应该是循序渐进,以解决系统中存在的问题为目的和驱动力的。

参考