这是我参与「第五届青训营 」伴学笔记创作活动的第 15 天
这篇文章主要是收集了笔者在学习今天的课程,在学习了一些秒杀系统设计与实现课程后并进行实践操作后,总结了一些注意点。
秒杀系统设计注意点4
使用缓存带来的相关问题
缓存击穿
缓存击穿,又称热点key问题。一般的缓存击穿,是指某个或某些key对应缓存忽然失效,导致大量用户的请求无法集中缓存,而直接去查询数据库,从而导致的崩溃问题。
解决缓存击穿,当前市场上主流有两种方法,分别是互斥锁和逻辑过期。
互斥锁
我们的系统为了追求效率,带给用户最佳体验,一般的业务执行线程都是并发的。比如缓存击穿对应的查询业务,当大部分的用户同时执行查询时,我们会为每一个用户执行一个线程,然后并发执行它们。
因此,为了防止崩溃,我们可以使用互斥锁,在同一时间内限定只有一个线程执行,对应到业务中就是只有一个用户的查询是有效的,那么系统得到的压力无疑将会大幅降低。
而为了实现“限定只有一个线程”的操作,我们使用的工具一般就是锁。
单体系统情况
如果是单体系统,加锁就很简单了,甚至大部分的编程语言都有自己的成熟的锁机制。例如java的synchronized锁,golang的WaitGroup锁、atomic锁等。
因此,我们只需要在我们的查询业务函数,加上互斥锁的标识即可。
当然,如果想要减少锁的粒度,可以转变为在特定业务的关键语句加上锁,而不是无脑给整条函数套上一个互斥锁。
分布式系统
分布式系统,比如基于微服务的系统,那么上面使用的简单互斥锁就用不了啦,应该使用更强大的分布式锁。原因也很简单——一个线程的锁,怎么会影响到其他线程呢?所以,需要一个能够同时限制我们系统中所有线程的锁,也就是我们引入的分布式锁。 分布式锁种类有很多,如:
- Mysql:直接建张表,不推荐。
- zookeeper、etcd:较为常用的方案。
- redis:最常用的方案,目前技术已经很成熟了。
redis lock作为分布式锁,在许多语言上都有相应的第三方实施方案。例如java的redission,go的go-redis都有较为成熟的技术了,我们就不用再继续造轮子,可以直接引入使用!
集群系统
更复杂的情况,就是有多个系统的情况了,比如主从集群系统,此时有多个redis client,一个分布式锁就没办法满足需求了。需要更强大的锁——比如红锁(red lock)之类。