这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战
作者:lomtom
个人网站:lomtom.top,
个人公众号:博思奥园
你的支持就是我最大的动力。
redis
底层为C语言
解决hash冲突类似于1.7的hashmap
redis概念
- 非关系型的键值对数据库,可以根据键以O(1)的时间复杂度取出或插入关联值
- Reds的数据是存在内存中的
- 键值对中键的类型可以是字符串,整型,浮点型等,且键是唯一的
- 键值对中的值类型可以是 string,hash,list,set, sorted set等
- Reds内置了复制,磁盘持久化,LUA脚本,事务,SSL,客户端代理等功能
- 通过Reds哨兵和自动分区提供高可用性
应用场景
- 计数器
可以对Sng进行自增自减运算,从而实现计数器功能。Reds这种内存型数据库的读写性能非常高,
很适合存储频繁读写的计数量 - 分布式D生成
利用自增特性,一次请求一个大一点的步长如incr2000,缓存在本地使用,用完再请求。 - 海量数据统计
位图(btmp):存储是否参过次活动,是答已读谋篇文章,用户是否为会员,日活统计。 - 会话缓存
可以使用 Redis来统一存储多台应用服务器的会话信息。当应用服务器不再存储用户的会话信息,也就
不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。 - 分布式队列/阻塞队列
List是一个双向链表,可以通过 push/push和rpop/pop写入和读取消息。可以通过使用 brpop/b|pop
来实现阻塞队列
String(最大存储512M)
String 是redis中使用最多的存储类型
1、数据结构(3.2之前):
sds:simple dynamic string是一个二进制安全数组
sds:
- length: 长度
- free:剩余长度
- char [] :{1,12,324,123}
2、数据结构(3.2之后)
根据存储的内容来
3、扩容机制
容量不够时,扩容为原来的两倍,直到1024k,不在成倍增加,而是以1024k的增加。
Go中使用Redis
Go中也有很多比较流行的并且开源Redis库,比如go-redis或redigo,在github上,分别12.3k和8.6k的star数量(截止到2021.09.03)
在这里将以go-redis为例。
安装
第一步:安装go-redis
1 | bash复制代码请勿省略版本号 |
配置连接
第二步:连接Redis服务器
连接Redis服务器有两种方法,第一种使用redis.Options
,第二种就是使用redis.ParseURL
1 | go复制代码1、第一种 |
那么,我这里使用从我的配置里读取,不会使用go读取配置文件可以参考
1 | bash复制代码 |
Ping() 旧版本是不需要参数的,从v8版本开始 需要参数 context.Context
编写存取逻辑
第三步:封装 存/获取值 函数
网上大部分教程都是在v8之前的,而在v8需要传入context.Context
,所以在存取时需要额外增加一个参数
1 | bash复制代码1、存值 |
说明:
- Set除了
context
、键、值外,还需要传入一个过期时间 - Get方法,返回错误码可能是redis当中不含有该值,所以做一个特殊处理
使用
第四步:使用
1 | bash复制代码func Test(test *testing.T) { |
把值为12
push到键为1
,然后在redis中查看
1 | bash复制代码1、redis控制台 |
Redis 发布/订阅模式
Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。
值得注意的是:订阅者接收不到启动之前的消息。
订阅者
1 | go复制代码func Receive(key ...string) error { |
发布者
1 | go复制代码func Publish(key string, value interface{}) error { |
注:如果需要Publish
自定义结构体,需要实现MarshalBinary
方法。
1 | bash复制代码type Msg struct { |
当我尝试Publish
自定结构体,就会这样的错误提示,这告诉我们需要将我们的结构体转为二进制形式
1 | bash复制代码redis: can't marshal *dto.Msg (implement encoding.BinaryMarshaler) |
这里有两种解决方法:
1、我们可以把Msg
结构体实现MarshalBinary
方法,Redis将自动执行所有操作
1 | go复制代码func (m *Msg) MarshalBinary() (data []byte, err error) { |
2、或者可以选择在Publish
前自己手动转为二进制形式
1 | go复制代码func Test3(test *testing.T) { |
Redis小技巧
1、为什么要是用mset或者mget
减少带带宽和io,因为redis需要封装resp协议(需要封装tcp协议与ip协议,各需要20byte),如果使用set或get去设置或获取(k,v)会封装两次,而是用mset k1 v1 k2 v2,就会减少封装次数,减少带宽和io。
2、现在系统有千万级的活跃用户,如何实现日活统计,为了增强用户粘性,要上线一个连续打卡发放积分的功能,怎么实现连续打卡用户统计。
使用setbit设值、getbit、bitcount统计
参考:blog.csdn.net/hgd613/arti…
本文转载自: 掘金