Redis高性能读服务

架构尽量不要分层

读服务的业务逻辑都比较简单,性能主要消耗在网络传输上,以 Java 举例,直接将数据访问层编译为 JAR 包并由读服务进行依赖。这样在部署时,它们在同一个进程里

读服务要尽可能和数据靠近,减少网络传输。

浏览器都自带本地缓存的功能,CDN 也是一样的道理

在读服务对于性能要求非常严格的情况下,要尽可能地减少引入框架。如果一定要引入,必须经过严格的压测。比如 Java 中的 Bean.copyProperties,它采用了反射的机制进行字段 copy,在数据量较大时,性能较低。

在读服务的处理链路上,为了方便排查问题,经常会直接将请求的入参及从存储中获取的数据,使用JSON进行序列化为字符串,并进行日志打印。这种粗暴的方式,对性能也会有非常大的消耗,建议不要直接全量序列化,而是精细化地按需打印。

对于读取的内容要在存储处按需取,而不是全量取回后再在服务内部进行过滤。如果存储为 MySQL,则不要使用 select *,需要手动指定你要查询的字段。如果存储为 Redis,则使用 Redis 的 hash 结构存储数据,因为 hash 结构可以让你在查询时指定需要返回哪些字段。

存储的选型和架构

读服务最主要依赖的中间件是存储,因此存储的性能很大程度上决定了读服务的性能。对于 MySQL、HBase等数据库,即使使用分库分表、读写分离、索引优化等手段,在并发量大时,性能也很难达到 200ms 以内。

为了提升性能,实战中的架构通常选用基于内存的、性能更好的 Redis 作为主存储,MySQL 作为兜底来构建

1. 存在缓存穿透的风险

如果恶意请求不断使用缓存中不存在的数据发送请求,就会导致该请求每次都会被降级到数据库中。

针对数据库中没有的数据,可以在缓存中设置一个占位符。请求的参数可以内置一些 token 或者一些验证数据,在读服务中前置进行校验并拦截,而不是透传到缓存或数据库中。

2. 缓存集中过期导致雪崩

对存储在缓存中的数据设置过期时间是为了定期获取数据库中的变更,但如果设置不合理,可能会导致缓存集中过期,进而所有的读请求都会因缓存未命中,而直接请求到数据库。

对于数据库的过期时间,可以在设置时进行加盐操作。

3. 懒加载无法感知实时变更

。如果你修改完了数据库再更新缓存,在异常情况下,可能出现数据库更新成功了,但缓存更新失败了的情况。

在更新数据库后主动更新缓存的模式,在实际的实施层面很容易出现遗漏。

posted @ 2023-03-07 16:58  jiaozg  阅读(39)  评论(0)    收藏  举报