之前的两篇系统架构的博客中都提到了高并发、高可用技术,但是却都没有详细聊过,今天就好好聊一下常见的高并发技术。
一 高并发技术核心
高并发技术的核心是分流;分别针对请求的各个环节,根据具体场景和业务特点采用不同的分流方案,逐层逐级的分担系统压力,从而达到高并发能力。
常见的高并发技术有:动静分离、缓存、异步并发、水平扩展等。分流简单来说就是:一台服务器承担不了的流量,就让多台服务器共同分担;DB承担不了流量就让缓存来帮忙分担;等等。接下来讨论的所有内容都是围绕着分流来实现的。
现实中没有一招鲜吃遍天的美事儿,每一个公司、每一种业务、每一个场景、每一个功能都有其与众不同的特点,现实中一般都会根据业务特征、根据请求的各个环节特点,做针对性优化。
二 分阶段优化策略
1. 模型
一次请求主要分为四个阶段:客户端发起请求;通过网络将请求信息发送到服务端;服务端处理请求;服务端将结果返回给客户端。为了追求并发的极致,我们可以针对每一个阶段分别使用不同的策略,来提升系统的并发性能。模型如下:
这是一个漏斗型的模型,通过逐层过滤,将流量分散,让尽可能少的请求到达底层。
此模型的核心就是,根据各环节的特点,选择相应的优化策略,从而实现高并发的目的。
2. 客户端优化技术
客户端优化技术主要指的是客户端通过缓存数据,减少访问服务端的次数,以实现降低服务端压力,达到支持更多并发量的需求。
常见的处理方式是:缓存不经常变动的内容,每隔一定时间更新一次,或者除非修改了否则较长时间不更新;如:更新微信公众账号的头像时,手机端不会立即看到这个更新。另外,根据业务场景可以限制不必要的请求;如:点击一个按钮,发送一次请求到服务端时,禁用按钮,避免因用户多次点击,而发送不必要的请求。
3. 网络优化技术
网络优化的核心目标是:将资源缓存到距离用户最近的网络节点上,这样除了可以省下大量网络带宽外,还可以达到最快的请求速度;一般针对静态资源。
通过静态化技术(将不经常变动的内容生成静态文件)或动静分离技术(例如H5+ajax),将静态的内容存储在CDN上,当用户查看一个页面时,只让少数的动态请求落到服务器端,其他内容从CDN上直接获取,这样就可以极大的减少服务器端的流量。
4. 服务端优化技术
1) 负载均衡
负载均衡的核心是让每台服务器以一个合适的负载来分担所有的请求。
常见的负载均衡方案有:随机、轮询、hash、一致性hash。当然在这些基础上有很多扩展,例如在负载均衡的机器中设置不同的权重;根据key的范围不同调用不同的服务器等等。
2) 缓存
a) 为什么高效
缓存的结构一般都是key-value结构,通过key直接寻址,时间复杂度为O(1),这比DB的遍历比较来快了非常多;另外,不少的缓存中间件通过在内存中存储数据,不用从磁盘中获取数据,性能也就会非常高。
说明一下:大部分缓存中间件都会对value做一些扩充,让value也成为一个复杂的数据结构,例如Redis的Set、SortSet,如果需要在value中寻找某一个值,时间复杂度会退化成为O(N);这些数据结构提供了强大的功能,使用的时候注意合理使用,以避免因为缓存乱用导致性能降低的问题。
b) 分布式缓存
如redis、tair、memcached等。
优点是:集群部署,不用考虑容量问题,数据支持持久化,支持高可用。
缺点是:因为服务器和缓存数据交换时存在一次网络交互,如果数据结构选择不合理或者并发量非常大或者每次交互的数据量较大时,可能会引起io阻塞等问题,需谨慎。
c) 堆缓存
通过java的堆来缓存数据。
优点是:速度非常快。
缺点是:存储数据量受限,断点数据丢失,分布式场景中如果出现不一致时,处理麻烦。
d) 磁盘文件缓存
将数据存储到服务器所在的磁盘上。
优点是:存储内容较堆内存多(少于分布式缓存),是持久化的。
缺点是:服务器迁移时也要迁移磁盘中的文件,分布式场景中如果出现不一致时,处理麻烦。
e) 注意事项
缓存数据和数据库数据不一致的问题。
缓存击穿问题。
缓存数据丢失问题(缓存一般都需要持久化的,为了保证性能缓存一般都不是同步持久化,所以是可能存在数据丢失问题的)。
3) 通信模型
高性能的IO通信模型可以给系统带来巨大的性能提升。目前就较为成熟、高效的IO通行模型是NIO(也叫IO多路复用、异步阻塞IO)。
在java服务器前加一层Nginx服务器,它既可以提供良好的负载均衡能力,也能够支持非常高的并发。当然Nginx的高性能还与他的master-worker设计有关,几乎做到了无线程切换。
使用Dubbo进行RPC调用时,默认使用的Netty也是基于NIO的。