一. 缓存
可以在服务端使用中间件来缓存数据,例如redis。Redis之所以读取速度快,主要是因为数据存储在内存中,不需要读取磁盘,内存读取速度通常比磁盘读取速度快百倍甚至更多。
数据库通常使用MySql,mysql的数据存储到磁盘上,但是mysql为了提升读写性能,会利用bufferpool缓存数据页。mysql读取时会按照页的粒度将数据页读取到bufferpool中,bufferpool中的数据页使用LRU算法(最近最少使用)淘汰长期没有用到的页面,缓存最近访问的数据页。
缓存常见问题
1、缓存雪崩:指缓存中的大量数据同时失效或者过期,导致大量的请求直接读取到下游数据库,导致数据库瞬时压力过大,通常的解决方案是将缓存数据设置的过期时间随机化。在事件服务中就是利用固定过期时间+随机值的方式,避免缓存雪崩。
2、缓存穿透:指读取下游不存在的数据,导致缓存命中不了,每次都请求下游数据库。这种情况通?;岢鱿衷谙呱弦斐A髁抗セ骰蛘呦掠问荼簧境淖纯?,针对缓存穿透可以使用布隆过滤器对不存在的数据进行过滤,从而避免请求穿透缓存去查询数据库。
3、缓存击穿: 指某个热点数据在缓存中被删除或者过期,导致大量的热点请求同时请求数据库。解决方案可以对于热点数据设置较长的过期时间或者利用分布式锁避免多个相同请求同时访问下游服务。
4、热点key: 热点key是指缓存中被频繁访问的key,导致缓存该key的分片或者redis访问量过高??梢越扇鹊鉱ey分散存储到多个key上,例如将热点key+序列号的方式存储,不同key存储的值都是相同的,在访问时随机访问一个key,分散原来单key分片的压力。
二.?并行化处理
通过创建多个容器提高服务的吞吐量,服务内部可以将多个串行的I/O操作改为并行处理,缩短接口的响应时长,提升用户体验。对于I/O存在相互依赖的情况,可以进行多阶段分批并行化处理。
mysql的主从同步
通过I/O thread读取主库的binlog,将日志写入到relay log中。
由sqlthread执行relaylog进行数据的同步。
sqlthread是由多个线程并发执行,加快数据的同步,防止主从同步延迟。sqlthread多线程化也经历了多个版本迭代,按表维度分发到同一个线程进行数据同步,再到按行维度分发到同一个线程。
redis在版本6.0之前都是号称单线程模型,主要是利用epllo管理用户海量连接,使用一个线程通过事件循环来处理用户的请求,优点是避免了线程切换和锁的竞争,以及实现简单,但是缺点也比较明显,不能有效的利用cpu的多核资源。随着数据量和并发量的越来越大,I/O成了redis的性能瓶颈点,因此在6.0版本引入了多线程模型。redis的多线程将处理过程最耗时的sockect的读取跟解析写入由多个I/O 并发完成,对于命令的执行过程仍然由单线程完成。
三. 批量化处理
kafka的消息发送并不是直接写入到broker中的,发送过程是将发送到同一个topic同一个分区的消息通过main函数的partitioner组件发送到同一个队列中,由sender线程不断拉取队列中消息批量发送到broker中。利用批量发送消息处理,节省大量的网络开销,提高发送效率。
四. 数据压缩
对于kafka进行传输数据时,在生产者端和消费者端可以开启数据压缩。生产者端压缩数据后,消费者端收到消息会自动解压,可以有效减小在磁盘的存储空间和网络传输时的带宽消耗,从而降低成本和提升传输效率。需要注意生产者端和消费者端指定相同的压缩算法。
五. 秒杀系统设计的要点
面对高并发的抢购活动,前端常用的三板斧是【扩容】【静态化】【限流】
扩容:加机器,这是最简单的方法,通过增加前端池的整体承载量来抗峰值。
静态化:将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素。通过CDN来抗峰值。
限流:一般都会采用IP级别的限流,即针对某一个IP,限制单位时间内发起请求数量?;蛘呋疃肟诘氖焙蛟黾佑蜗坊蛘呶侍饣方诮邢宀僮?。
后端:秒杀系统的本质就是在高并发下准确的增减商品库存,不出现超卖少卖的问题。
所有的用户在抢到商品时需要利用互斥锁进行库存数量的变更。
互斥锁的存在必然会成为系统瓶颈,但是秒杀系统又是一个高并发的场景,所以如何进行互斥锁优化是提高秒杀系统性能的一个重要优化手段。
无锁化设计方案之一就是利用消息队列,对于秒杀系统的秒杀操作进行异步处理,将秒杀操作发布一个消息到消息队列中,这样所有用户的秒杀行为就形成了一个先进先出的队列,只有前面先添加到消息队列中的用户才能抢购商品成功。
引入队列,然后将所有写DB操作在单队列中排队,完全串行处理。当达到库存阀值的时候就不在消费队列,并关闭购买功能。这就解决了超卖问题。
优点:解决超卖问题,略微提升性能。
缺点:性能受限于队列处理机处理性能和DB的写入性能中最短的那个,另外多商品同时抢购的时候需要准备多条队列。
总结
1、前端三板斧【扩容】【限流】【静态化】
2、后端两条路【内存】+【排队】
六.?分片化
redis集群的出现就是为了解决单机redis的读写性能瓶颈问题,redis集群是将数据自动分片到多个节点上,每个节点负责数据的一部分,每个节点都可以对外提供服务,突破单机redis存储限制跟读写上限,提高整个服务的高并发能力。
同样的kafka中每个topic也支持多个partition,partition分布到多个broker上,减轻单台机器的读写压力,通过增加partition数量可以增加消费者并行消费消息,提高kafka的水平扩展能力和吞吐量。