目录

一、环境准备(已经安装redis的直接跳过本步骤)

redis安装有在线安装和离线安装,后者针对某些内网环境部署时不能与外网通信。

这里采用docker在线安装。

1.1 安装redis

搜索镜像

输入以下指令搜索 redis 镜像

docker search redis

 拉取镜像

这里安装redis 5版本

docker pull redis:5

 查看本地镜像

拉取完后,查看本地镜像。

docker images

创建挂载目录

在linux中创建redis运行时的挂载目录,方便在docker容器外配置redis。

这里挂载目录分别是,可根据自己实际情况创建不同路径的挂载目录

mkdir /home/zhongqiu/redis

mkdir /home/zhongqiu/redis/data

这一步可以按需挂载 redis.conf,这里不做挂载 配置文件

 运行镜像

docker run -p 6379:6379 --name redis-5  -v /home/zhongqiu/redis/data:/data -d redis:5 redis-server  --appendonly yes

如果 redis.conf挂载了,写法如下:


docker run -p 6379:6379 --name redis-five -v /home/zhongqiu/redis/redis.conf:/etc/redis/redis.conf  -v /home/zhongqiu/redis/data:/data -d redis:5 redis-server /etc/redis/redis.conf --appendonly yes
 
 
-p 6379:6379:把容器内的6379端口映射到宿主机6379端口
-v /home/zhongqiu/redis/redis.conf:/etc/redis/redis.conf:把宿主机配置好的redis.conf放到容器内的这个位置中
-v /home/zhongqiu/redis/data:/data:把redis持久化的数据在宿主机内显示,做数据备份
redis-server /home/zhongqiu/redis/redis.conf:这个是关键配置,让redis不是无配置启动,而是按照这个redis.conf的配置启动
 redis:5  版本号
–appendonly yes:redis启动后数据持久化

查看启动

docker ps -a

二、驱动选型

Redis是一个键值对存储系统,和Memcached类似,支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。

目前应用Redis最广泛的应该是新浪微博平台,其次还有Facebook收购的图片社交网站 instagram。Go语言目前支持Redis的驱动如下:

本例中将采用git star最高的 go-redis/redis组件。

 三、编写代码

3.1 简单读写代码(含计数)

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"time"
)

var ctx = context.Background()

func main() {

	// 建立链接
	rdb := redis.NewClient(&redis.Options{
		Addr:     "192.168.58.128:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	// set值
	err := rdb.Set(ctx, "key", "value", 0).Err()
	if err != nil {
		panic(err)
	}

	// 获取值
	val, err := rdb.Get(ctx, "key").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("key", val)

	val2, err := rdb.Get(ctx, "key2").Result()
	if err == redis.Nil {
		fmt.Println("key2 does not exist")
	} else if err != nil {
		panic(err)
	} else {
		fmt.Println("key2", val2)
	}

	// 计数器
	incr := rdb.Incr(ctx, "incrKeys")
	fmt.Println("回调计数器加一的值:", incr)

	// 设置过期为10S
	rdb.SetEX(ctx, "expireTestKey", "飞飞飞", 10000)
	// 休眠12S
	time.Sleep(time.Duration(12) * time.Second)
	fmt.Println("key = expireTestKey的值 =", rdb.Get(ctx, "expireTestKey"))

	rdb.Close()
	
}

输出:

 3.2 分布式锁

模仿两个线程抢占同一把锁,若获取到锁则进行业务操作,未获取到则不进行业务操作。

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"github.com/gofrs/uuid"
	"time"
)

var ctx = context.Background()

func main() {

	// 建立链接
	rdb := redis.NewClient(&redis.Options{
		Addr:     "192.168.58.128:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	for i := 0; i < 2; i++ {
		go func() {
			v4, err := uuid.NewV4()
			if err != nil {
				panic(err)
			}

			threadId := v4.String()
			fmt.Println("当前线程唯一值=", threadId)

			// 这里最后一个参数代表时间,0代表值不过期,-1=keepttl,会比较时间和时间单位S的关系,最后转换成MS或者S
			// 如果最后时间设置小了,可能获取到分布式锁的业务还未执行完,分布式锁就过期了(本文不探讨锁过期机制)
			result, err := rdb.SetNX(ctx, "setNxTestKeyName", threadId, 10000000000).Result()
			if err != nil {
				panic(err)
			}

			if result {
				fmt.Println("开始业务操作", threadId)
				time.Sleep(time.Second * 4)
				fmt.Println("结束业务操作", threadId)

				// 这里该是删除对应线程设置的锁,这里没有考虑业务线程过期因素
				value := rdb.Get(ctx, "setNxTestKeyName").Val()
				fmt.Println("对应线程锁的值", value)
				if err != nil {
					panic(err)
				}
				if value == threadId {
					rdb.Del(ctx, "setNxTestKeyName")
					fmt.Println("删除了对应的key", threadId)
				}
			} else {
				fmt.Println("没有获取到锁,无法进行业务操作", threadId)
			}
		}()
	}

	time.Sleep(time.Second * 20)
	rdb.Close()

}

 运行结果:

 

 四、官方文档

要了解该组件,最好看第一手官方文档资料,对应操作api基本与redis指令一一对应,地址见:

https://pkg.go.dev/github.com/go-redis/redis/v8#section-readme