随着前端技术的普及和前后端分离的盛行,前端对缓存的需求也越来越高。利用 Redis 缓存可以显著提高网站的性能,降低服务器负荷,但是也需要注意它所带来的一些问题,以及如何做出优化。
问题
缓存雪崩
缓存雪崩是指在 Redis 缓存中,由于缓存键的过期时间相同或接近,导致缓存同时失效,请求都落在了数据库上,造成数据库短时间内瞬时并发访问压力太大,从而导致数据库宕机的现象。
-- -------------------- ---- ------- -- ---- -- ------------ ----------------- - ----- ------ ---- -- -- ----- ------ -- ---- ---- -- ----- -------- --------- - --- ---- - ----- ------------------ -- ------- - -- ----------- ---- - ----- ---------------- -- ---- ----------------- ----- ----- ------ - ------ ----- -展开代码
以上示例代码中,由于缓存过期时间一致,如果同时失效,则在从数据库获取数据时会同时发起大量请求,导致数据库可能会宕机,从而引发缓存雪崩。
缓存穿透
缓存穿透是指在 Redis 缓存中,由于恶意攻击或者业务逻辑bug,在缓存和数据库中均不存在某个键,这时大量请求都会落在数据库上,造成数据库短时间内瞬时并发访问压力太大,从而导致数据库宕机的现象。
-- -------------------- ---- ------- -- ---- -- ------ ----- -------- --------------- - --- ---- - ----- ----------------- - ---- -- ------- - ---- - ----- ---------------------- -- ------- - -- ----- ----------------- - --- --- ----- ------ ------ ----- - ----------------- - --- ----- ----- ------ - ------ ----- -展开代码
为了防止缓存穿透,通常会在 Redis 缓存中把不存在的键写入一个空值,这样下次请求过来时就只会落在 Redis 缓存中。但是如果攻击者频繁的请求数量太大,仍然会对数据库造成压力。
缓存击穿
缓存击穿是指在 Redis 缓存中,由于一个热点数据缓存过期或者业务逻辑高频访问,而导致这个键的大量请求都会落在数据库上,造成数据库短时间内瞬时并发访问压力太大,从而导致数据库宕机的现象。
-- -------------------- ---- ------- -- ---- -- ------ ----- -------- --------------- - --- ---- - ----- ----------------- - ---- -- ------- - -- ------------------------------ -- ------ ----------------------- - --- ---- ----- ----- ---- - ---- - ----- ---------------------- -- ------- - -- ----- ----------------- - --- --- ----- ------ ------ ----- - ----------------- - --- ----- ----- ------ -- --- ----------------------- - ---- - ---- - -- --------------------------------------- ----- --------- ------ ----- ---------------- - - ------ ----- -展开代码
为了防止缓存击穿,通常会在 Redis 缓存中加入互斥锁。当一个请求到来时,如果获取到了锁,那么它就可以从数据库中获取数据,然后写入缓存,并释放锁。如果一个请求到来时没有获取到锁,则等待一段时间(比如50ms),再次尝试获取缓存即可。
优化方案
缓存雪崩优化
为了避免缓存雪崩的发生,可以采取以下几种优化方案:
- 不同缓存键设置不同的过期时间,避免同时失效;
- 缓存失效时不是立即从数据库中获取数据,在某个随机的时间点再去获取数据;
- 对于实时性要求不高的数据,可以在高峰期对其进行预热,提前将其写入缓存中。
-- -------------------- ---- ------- -- ---- -- -------------- ---------------------- - ----- ------ ---- -- -- ----- ------ ---------------------- - ----- -------- ---- -- -- ----- ------ ---------------------- - ----- -------- ---- -- -- ----- ------ -- ------------------- ----- -------- --------- - --- ---- - ----- ------------------ -- ------- - -- -- --- --------- ----- ----- - ------------------------ - -- - --- - -- ----- ---------- - ------ ---- - ----- ---------------- -- ---- ----------------- ----- ----- ------ - ------ ----- - -- ---- ----- -------- -------------- - ----- ----- - ----- ----------------- --- ---- ---- -- ------ - ----------------- - -------- ----- ----- ------ - -展开代码
缓存穿透优化
为了避免缓存穿透的发生,可以采取以下几种优化方案:
- 对于不存在的键,写入一个空值或一个特殊标识符,表示该键不存在,这样下次请求过来时就只会落在 Redis 缓存中,避免请求数据库;
- 过滤掉异常或者不存在的请求;
- 使用布隆过滤器,在 Redis 缓存和数据库之间做一层过滤,过滤掉一些不存在于数据库中的请求。
-- -------------------- ---- ------- -- ---- -- ------ ----- -------- --------------- - --- ---- - ----- ----------------- - ---- -- ------- - -- ----- ----------------- - --- --- ----- ------ ------ ----- - ------ ----- - -- ------- ----- -------- --------------- - -- ---------------- - ------ ----- - --- ---- - ----- ----------------- - ---- -- ------- - ---- - ----- ---------------------- -- ------- - -- ----- ----------------- - --- --- ----- ------ ------ ----- - ----------------- - --- ----- ----- ------ - ------ ----- - -- ---------------------- ----- ---------- - ----------------------- ----- ---------- - --- ------------ ----- ------------ ----- ---- --- ----- -------- ------------------------------ - -- ------ ---------------------------------- ---- - ------ ----- - --- ---- - ----- ----------------- - ---- -- ------- - ---- - ----- ---------------------- -- ------- - ----- ------------------------------- ---- ------ ----- - ----------------- - --- ----- ----- ------ - ------ ----- -展开代码
缓存击穿优化
为了避免缓存击穿的发生,可以采取以下几种优化方案:
- 加入互斥锁,避免缓存并发访问;
- 利用 Redis 的自带机制,通过批量获取数据来优化查询。
-- -------------------- ---- ------- -- ---- -- ----- ----- -------- --------------- - --- ---- - ----- ----------------- - ---- -- ------- - -- ------------------------------ -- ------ ----------------------- - --- ---- ----- ----- ---- - ---- - ----- ---------------------- -- ------- - -- ----- ----------------- - --- --- ----- ------ ------ ----- - ----------------- - --- ----- ----- ------ -- --- ----------------------- - ---- - ---- - -- --------------------------------------- ----- --------- ------ ----- ---------------- - - ------ ----- - -- ------ ----- -------- ------------------ - -- ---------- ----- ----------- - ----- ------------------------ -- ------- - ----- -- -------- ----- --------- - --- ----- ------------- - --- ---------------------------- ------ -- - -- --------- - --------------------------- - ---- - -------------------- --- ----------- ------- ------------------- --- - --- -- --------- ----- ----------- - ----- ------------------------------- -- ---- ------------------------ -- - ----------------- - -------- --------------------- ----- ------ -------------------- --- -------- ------- ---- --- --- -- ---- ----- ------- - --- -------------- -- - ----- ---- - ----------------------- -- ------- --- ---- -- ------ - -------------------------- - ---- - ------------------- - --- ------ -------- -展开代码
综上所述,利用 Redis 缓存可以大幅提升网站性能,但也带来了一些问题。通过采取优化方案可以有效避免这些问题,让网站运行更加平稳稳定。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d806e0a941bf7134e534d0