Redis
作为一种优秀的基于key/value
的缓存,有非常不错的性能和稳定性,无论是在工作中,还是面试中,都经常会出现。
陆陆续续也写了一些Go
操作redis
以及redis
使用场景的案例了,本文就记录一下工作中Redis
常用的一些场景,做一个小结。
20. go-redis基本使用
70.Redis缓存优化实践(基于分类树场景)
对于很多官方网站的首页,经常会有一些统计首页访问次数的需求。访问次数只有一个字段,如果保存到数据库中,再最后做汇总显然有些麻烦。
该业务场景可以使用Redis
,定义一个key
,比如:OFFICIAL_INDEX_VISIT_COUNT
。
在Redis中有incr命令,可以实现给value值加1操作:
incr OFFICIAL_INDEX_VISIT_COUNT
当然如果你想一次加的值大于1
,可以用incrby
命令,例如:
incrby OFFICIAL_INDEX_VISIT_COUNT 5
这样可以一次性加5
。
该场景下需要注意:68. redis计数与限流中incr+expire的坑以及解决办法(Lua+TTL)
Redis
的最常用的用例是缓存,以加快网络应用的速度。在这种用例中,Redis
将经常请求的数据存储在内存中。它允许网络服务器频繁访问的数据。这就减少了数据库的负载,并缩短应用程序的响应时间。在大规模应用中,缓存分布在 Redis
服务器集群中。
Redis
作为分布式缓存时需要考虑的其他问题包括:
TTL (Time to Live)
HotKey 、BigKey
29.Go处理Redis HotKey 以及30.Go处理Redis BigKey 以及69.使用Go标准库compress/gzip压缩数据存入Redis避免BigKey需要协调对某些共享资源的访问时,就会使用分布式锁。Redis
通过其原子命令(如 SETNX, SET if Not eXists
)来做分布式锁。它允许调用者设置一个不存在的键。
比如,客户端通过设置一个唯一的 Key
来获取锁:
SETNX lock "1234abcd" EX 3
如果Key
尚未设置,SETNX
命令返回 1
,表明锁已被客户端获取。客户端完成工作后 删除 Key
,释放锁。
如果 Key
已被设置,SETNX
命令返回 0
,表明锁已被其他客户机持有。在这种情况下,客户端会等待并重试 SETNX
操作,直到锁被其他客户端释放。
请注意,这种简单的实现对于许多用例来说已经足够好了,但并非完全容错。对于生产应用,许多 Redis
客户端库提供高质量的分布式锁实现。 聊聊redis分布式锁的8大坑
使用Redis
还有一个非常常用的的业务场景是做限流。当然还有其他的限流方式,比如:使用nginx
,但使用Redis
控制可以更精细。
比如:限制同一个ip
,1
分钟之内只能访问10
次接口,10
分钟之内只能访问50
次接口,1
天之内只能访问100
次接口。如果超过次数,则接口直接返回:请求太频繁了,请稍后重试。此时可以在Redis
中保存用户的请求次数记录。
比如:key
是用户ip
,value
是访问的次数从1
开始,后面每访问一次则加1
。如果value
超过一定的次数,则直接拦截这种异常的ip
。当然也需要设置一个过期时间,异常ip
如果超过这个过期时间,比如:1
天,则恢复正常了,该ip
可以再发起请求了。或者限制同一个用户id
。
26.redis实现日限流、周限流(含黑名单、白名单)
27.Go实现一月(30天)内不发送重复内容的站内信给用户
同样,该场景下涉及到计数incr
,所以也需要注意:68. redis计数与限流中incr+expire的坑以及解决办法(Lua+TTL)
很多网站有排行榜的功能,比如:商城中有商品销量的排行榜,游戏网站有玩家获得积分的排行榜。
通常情况下,我们可以使用Sorted Set
保存排行榜的数据。
使用ZADD
可以添加排行榜的数据,使用ZRANGE
可以获取排行榜的数据。
例如:
ZADD rank:score 100 "周星驰"
ZADD rank:score 90 "周杰伦"
ZADD rank:score 80 "周润发"
ZRANGE rank:score 0 -1 WITHSCORES
返回数据:
"周星驰"
"100"
"周杰伦"
"90"
"周润发"
"80"
另一个常见用例是将 Redis
用作 Session
存储,在无状态服务之间共享 Sessio
n 数据。
当用户登录网络应用程序时,服务端会创建一个唯一的 Session ID
,Session
数据会存储在 Redis
中,然后 Session
作为 Cookie
的一部分返回给客户端。
当用户向应用程序发出请求时,Session ID
会包含在请求中。无状态网络服务器会使用 Session
数据。值得注意的是 Redis
是内存数据库。如果 Redis
服务器重启,存储在 Redis
中的 Session
数据会丢失。
即使 Redis
提供了 RDB
和 AOF
等持久化选项,但这些选项在重启时加载数据的时间往往太长,不实用。在实际生产环境中,数据会复制到备份实例。如果主实例崩溃,备份迅速升级,接管流量。
使用Redis
保存用户登录状态,有个好处是它可以设置一个过期时间,比如:该时间可以设置成30
分钟。
在Redis
内部有对应的策略,会将过期的数据删除,也有获取数据时才实时删除的逻辑。
比如现在有个需求:有个网站需要统计一周内连续登陆的用户,以及一个月内登陆过的用户。这个需求使用传统的数据库,实现起来比较麻烦,但使用Redis
的bitmap
让我们可以实时的进行类似的统计。
bitmap
是二进制的byte
数组,也可以简单理解成是一个普通字符串。它将二进制数据存储在byte
数组中以达到存储数据的目的。
保存数据命令使用setbit
,语法:
setbit key offset value
具体示例:
setbit user:view:2024-01-20 123456 1
往bitmap
数组中设置了用户id=123456
的登录状态为1
,标记2024-01-20
已登录。
然后通过命令getbit
获取数据,语法:
getbit key offset
具体示例:
getbit user:view:2024-01-17 123456
如果获取的值是1
,说明这一天登录了。
如果我们想统计一周内连续登录的用户,只需要遍历用户id
,根据日期中数组中去查询状态即可。
在有些需要生成全局ID
的业务场景,其实也可以使用Redis
。
可以使用incrby
命令,利用原子性操作,可以执行下面这个命令:
incrby userid 10000
在分库分表的场景,对于有些批量操作,我们可以从Redis
中,一次性拿一批id
出来,然后给业务系统使用。