Redis作为一种在后端系统中运用广泛的中间件,除了普通的Kv键值数据库功能,还有其他高级用法值得探索
初识Redis
我学习Redis的初步认识就是一个集中式的KV键值对数据库,具有很高的读写性能。可以适用于多个服务端的统一授权验证,存储一些自动过期的键值,性能也非常的高。 也学习到一些Redis更擅长的使用场景
- 高性能集中缓存系统
- 网络访问量转发量评论量的计数器
- 实时更新的排行榜 有序集合
- 消息队列 发布订阅实现或者是阻塞队列
Redis高级功能
Redis的常见数据结构像List Set ZSet String Hash 标准的KV再继续简单介绍的话篇幅就过于长了,打算后续再对这个5种数据结构深入了解。
Pipeline
在不同语言的Redis 客户端下都会对实现Pipeline(管道) 功能, 主要就是独占一条链接将要执行的数据一致发送而不断开,我的第一感觉有点像Http的Keep-Alive,通过缩短打开和关闭的网络时间从而提高效率
我觉得还是又要注意得地方相比于带M得指令比如Mset,Hmset等,这种指令是原生就是批量执行会原子执行,而Pipeline虽然是统一发送但是在Redis-Server上则是拆开来一条一条得执行
GO下实例 初始化
import "github.com/redis/go-redis/v9"
var (
IRB *redis.Client
)
func init() {
IRB = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
DB: 0,
})
}
管道goredis实现方式
func TestPipeline(t *testing.T) {
pipe := IRB.Pipeline()
r1 := pipe.Set(ctx, "key1", "32", 0)
r2 := pipe.Set(ctx, "key2", 64, 0)
exec, err := pipe.Exec(ctx)
if err != nil {
t.Error(exec)
}
log.Println(r1.Val())
log.Println(r2.Val())
}
如果采取上述方案必须等Pipe执行后才能拿到结果 也可采取回调得形式,避免了手动Exec得调用,但是编程体验也下降了,我还是觉得第一种方式比较符合正常编程思路
func TestPipeCallback(t *testing.T) {
pipelined, err := IRB.Pipelined(ctx, func(pipeliner redis.Pipeliner) error {
pipeliner.Set(ctx, "cbKey1", 2, 0)
pipeliner.Set(ctx, "cbKey2", 2, 0)
return nil
})
if err != nil {
t.Error(err)
}
log.Println(pipelined)
}
执行结果如下
个人体验上Pipe和Redis的事务的Multi比较像,事务也是在执行队列中统一执行,管道就是省去一部分网络传输的时间,当然Redis事务还有其他命令比如Watch等,功能上更完善也有另外的用途。
Publish-Subscribe
go语言下的go-redis的在发布订阅模式中支持在网络异常中重连服务器
定时发布
func PubTicker(channel string) {
ticker := time.NewTicker(time.Second * 3)
for {
select {
case <-ticker.C:
IRB.Publish(ctx, channel, time.Now().Format("02/15-04-05"))
}
}
}
接收消息ReceiveMessage
func TestPubSub(t *testing.T) {
var channel = "chan"
go PubTicker(channel)
subscribe := IRB.Subscribe(ctx, channel)
defer subscribe.Close()
for {
message, err := subscribe.ReceiveMessage(ctx)
if err != nil {
t.Error(err)
}
log.Println(message.String())
}
}
订阅结束后要记得关闭订阅
messages := subscribe.Channel()
for message := range messages {
log.Println(message)
}
这样去获取消息也是可取的 for-range会一直遍历到通道关闭 可能会造成死锁 channel for range之前建议close或者使用for - select 循环取出数据
tips: go-redis的详细配置选项见文档 Go Redis [配置]
发布订阅和消息队列的小比较: 发布订阅数全收到,消息队列有个抢的过程,只有一个抢到
BitMap
Redis的Bitmap用于大量数据的统计,但是状态一般只能是两个,状态的转换只需要一个Bit的空间,相比于普通的int内存占用大大降低 可以实现的场景
- 用户登录统计
- 统计用户每日的操作数 (需要手动划分字节但是支持的数目可以很大)
总结学习
Redis还有更高级的事务Multi和Lua脚本原子性执行,Geo和HyperLogLog和Streams 实现消息队列 等还有Redis的持久化机制学习RDB和AOF,本篇只是简单介绍一部分高级数据结构和Go语言的实战使用,学不可以已 /(ㄒoㄒ)/~~