一个大型网站应用一般都是从最初小规模网站甚至是单机应用发展而来的,为了让系统能够支持足够大的业务量,从前端到后端也采用了各种各样技术,前端静态资源压缩整合、使用CDN、分布式SOA架构、缓存、数据库加索引、读写分离等等。这些技术是高并发系统所必须的
高并发系统设计原则
高并发的接口/系统有一个共同的特性,那就是”快”。
在系统其它条件既定的情况下,系统处理请求越快,用户得到反馈的时间就越短,单位时间内服务器能够处理请求的数量就会越多。所以”快”几乎可以算是高并发系统的要满足的必要条件,要评估一个系统性能如何,某次优化是否提高系统的容量,”快”是一个很直观的衡量标准。那么,如何才能做得快呢?有两个需要注意的原则
1. 做得少,一方面是指在功能特性上有所为,有所不为,另一方面是指一次处理的信息量要少。
2. 做得巧,根据业务自身的特点,选择合理的业务实现方式,选择合理的缓存类型和缓存调用时机。对于一个秒杀系统来说,瞬时的大量请求会对后台服务造成冲击,需要保证服务的可用性以及业务的正确性。设计了一个高并发高可用的系统简要流程架构如下图:
1.将商品(或券)的信息等静态数据放到cdn节点,实现动静分离
2.业务请求和业务处理之间使用MQ对请求进行削峰
3.读写分离:对于逻辑复杂(用户验证,风控管理,行为分析)的系统,可以将读写部署两套服务进行分离
4.使用缓存:像库存这种信息无法放到静态页面,为了应对大并发读问题,可以在服务端做本地缓存用于读取,一般缓存时间设置为数秒,缓存失效时(最好在失效前一两秒)重新拉取redis中的库存信息。防止超买问题由扣减行为保证,因此即使和缓存不一致,读本地缓存也不会导致超卖,读场景一般允许脏数据情况。高并发时,大量的mysql操作会有很大性能问题,因此使用redis集群作为缓存进行读取。
5.防止缓存雪崩:减少缓存渗透:可以在服务中进行布隆过滤,可以将不存在的商品或券访问在服务端过滤掉;或者对缓存中没有的数据key置为null并设置较短的过期时间,优点是简单易操作,缺点要增加大量的null key,增大了与mysql的不一致性,需要消息机制和mysql保持同步限流:对key的操作加锁排队(利用setnx进行分布式锁),即同时只允许一个线程访问。防止缓存同时失效:设置key的过期时间时,采用固定时间+随机时间的方法,可以有效防止缓存同时过期引起雪崩的问题增加二级缓存: A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。
6.合理设置redis中的key,使其均匀的分布到各个节点,防止大量请求访问到少量节点的热点问题,而且可以减少单个节点宕机造成的影响。
7.由于商品或券具有独立性, 每个商品或券分配一个独有id,可以根据id范围划分到各个服务集群中,服务在访问对应范围的的redis缓存,这样可以大大增加访问的并发性。实现方式一个是在web服务中将id路由到对应的消息队列topic中,另一个是在消息队列后部署消息路由集群,相对来说方案一更好,因为方案而增加了链路长度和故障点。
8.在7的基础上,为了进一步提升性能防止少量热点数据影响全量数据的操作性能,可在服务中统计热点数据(比如LRU),并将热点数据独立存放到一个集群中去,这样可以将热点数据和其它数据隔离开来。当然这样会增加热点数据迁移的工作,增加了系统的复杂性。
phper在进阶的时候总会遇到一些问题和瓶颈,业务代码写多了没有方向感,不知道该从那里入手去提升,对此我整理了一些资料,包括但不限于:分布式架构、高可扩展、高性能、高并发、服务器性能调优、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql优化、shell脚本、Docker、微服务、Nginx等多个知识点高级进阶干货需要的可以免费分享给大家,需要的请点击加群(→)677079770