Go安装和使用Redis

Docker 安装 Redis

创建data文件做数据持久化存储时

1
2
mkdir /data/redis
mkdir /data/redis/data

做redis容器启动后的配置文件

1
touch /data/redis/redis.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Redis默认不是以守护进程的方式运行
daemonize no

# 指定Redis监听端口,默认端口为6379
port 6379

# 绑定的主机地址,不要绑定容器的本地127.0.0.1地址,因为这样就无法在容器外部访问
bind 0.0.0.0

# 持久化
appendonly yes

#设置密码
requirepass password

启动命令

1
docker run -p 6379:6379 --name redis -v /docker/redis/redis.conf:/etc/redis/redis.conf -v /docker/redis/data:/data -d redis redis-server /etc/redis/redis.conf

命令解释

1
2
3
4
5
6
7
docker run redis # 从redis镜像运行容器
-p 6379:6379 # 映射本地6379端口到容器6379端口,前为本地端口
--name redis # 设置容器名称为redis,方便以后使用docker ps进行管理
-v /data/redis/redis.conf:/etc/redis/redis.conf # 关联本地/data/redis/redis.conf文件到容器中/etc/redis/redis.conf,同样,前为本地
-v /data/redis/data:/data # 关联本地/docker/redis/data到容器内/data目录,此为存放redis数据的目录,为方便以后升级redis,而数据可以留存
-d # 后台启动,使用此方式启动,则redis.conf中daemonize必须设置为no,否则会无法启动
redis-server /etc/redis/redis.conf # 在容器内启动redis-server的命令,主要是为了加载配置

容器内部使用redis

1
2
3
docker exec -it redis_container /bin/sh
cd /usr/local/bin
redis-cli

Go 中使用 Redis

安装 go-redis v8

1
go get github.com/go-redis/redis/v8  

初始化 redis client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var rdb *redis.Client

func InitRedisClii(cfg config.RedisConf) error {
rdb = redis.NewClient(&redis.Options{
Addr: cfg.Address,
Password: cfg.Password, //设置好的密码
DB: 0, //要连接的redis库
PoolSize: 100, //连接池的最大连接数
})

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := rdb.Ping(ctx).Result() //检测心跳,确认是否能连接上
return err
}

func GetRedisCli() *redis.Client {
return rdb
}

使用 redis

本次以查询评论功能为例

使用的rpc的调用方式,属于所写的星辰缘项目,是一个微服务架构的项目,在后续中也会逐步完善相关笔记

  • 在使用redis之前要思考为什么使用redis,在什么地方使用redis

  • 此次是在查询文章评论功能上使用redis文章评论使用,将db查询结果进行json序列化作为value存入redis(不严谨,目前初始学,暂时先这样),并且设置时间为5s

  • 这样每次查就会先去redis中查找是否有相关信息,没有的话再去mysql中找,并且将结果再存入到redis中且设置存活时间为5s

  • 这样用户每次新写了评论后可能会5s中后才能看到自己写的评论(不严谨,现在暂时逻辑先这样),虽然造成了延迟,牺牲了及时性,但是却有效保护了mysql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
func (h *CommentServer) QueryComment(ctx context.Context, req *comment.QueryCommentREQ, rsp *comment.QueryCommentRSP) error {
var comments []model.Comment
var ack []*comment.CommentContent
info, err := redisCli.GetRedisCli().Get(ctx, "comment_id_"+strconv.Itoa(int(req.CommentId))).Bytes() //先redis中找数据
if err == nil { //找到了redis中的数据
fmt.Println("use redis!")
err = json.Unmarshal(info, &ack) //反序列化
rsp.Code = uint32(common.StatusRPCOK)
rsp.Comment = ack
return nil
}
err = db.QueryComment(req.CommentId, req.Type, &comments) //没有找到就去mysql中查询
if err != nil {
rsp.Code = uint32(common.ErrRPCCode)
rsp.Err = err.Error()
return errors.Wrap(err, "db query comment err")
}
for _, v := range comments {
//TODO:微服务调微服务优化
rspUser, err := client.GetIDUser(v.UserID) //去account 微服务中查询user_id的具体信息
if err != nil {
rsp.Code = uint32(common.ErrRPCCode)
rsp.Err = err.Error()
return errors.Wrap(err, "db get id user err")
}
ack = append(ack, &comment.CommentContent{
Id: v.ID,
CommentId: v.CommentedID,
Type: uint32(v.Type),
Content: v.Content,
Time: v.Time,
UserId: v.UserID,
UserAvatar: oss.DownloadUrl(rspUser.Avatar),
UserName: rspUser.Name,
Love: int64(v.Love),
})
}
fmt.Println("user mysql!")
rsp.Code = uint32(common.StatusRPCOK)
rsp.Comment = ack
data, _ := json.Marshal(ack) //将查询结果序列化
//将查询结果存入redis,并设置存活时间为5s
err = redisCli.GetRedisCli().Set(ctx, "comment_id_"+strconv.Itoa(int(req.CommentId)), string(data), time.Second*5).Err()
if err != nil {
rsp.Err = "redis add comment err"
}
return nil
}

贴士

go-redis中如果Get一个不存在的键会直接返回err,而不是空字符串


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!