乔克视界 乔克视界
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档

乔克

云原生爱好者
首页
  • 运维
  • 开发
  • 监控
  • 安全
  • 随笔
  • Docker
  • Golang
  • Python
  • AIOps
  • 心情杂货
  • 读书笔记
  • 面试
  • 实用技巧
  • 博客搭建
友链
关于
收藏
  • 分类
  • 标签
  • 归档
  • Docker

  • Golang

    • Golang基础知识

    • Golang进阶知识

      • 使用database_sql
      • 使用sqlx
      • 操作Redis
        • Redis 介绍
        • Redis 支持的数据结构
        • Redis 应用场景
        • Go 操作 Redis
          • 安装
          • 连接
          • 普通连接
          • 连接哨兵模式
          • 连接集群模式
          • 基本使用
          • set/get
          • zset
        • 另一种操作 redis
          • 简单操作
          • 连接池
      • 操作NSQ
      • 操作kafka
      • 操作Etcd
      • 操作ElasticSearch
    • Golang常用包

  • AIOps

  • 专栏
  • Golang
  • Golang进阶知识
乔克
2025-07-13
目录

操作Redis

# Redis 介绍

Redis 是一个开源的内存数据库,Redis 提供了多种不同类型的数据结构,很多业务场景下的问题都可以很自然地映射到这些数据结构上。除此之外,通过复制、持久化和客户端分片等特性,我们可以很方便地将 Redis 扩展成一个能够包含数百 GB 数据、每秒处理上百万次请求的系统。

# Redis 支持的数据结构

Redis 支持诸如字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、带范围查询的排序集合(sorted sets)、位图(bitmaps)、hyperloglogs、带半径查询和流的地理空间索引等数据结构(geospatial indexes)。

# Redis 应用场景

  • 缓存系统,减轻主数据库(MySQL)的压力。
  • 计数场景,比如微博、抖音中的关注数和粉丝数。
  • 热门排行榜,需要排序的场景特别适合使用 ZSET。
  • 利用 LIST 可以实现队列的功能。

# Go 操作 Redis

# 安装

区别于另一个比较常用的 Go 语言 redis client 库:redigo (opens new window),我们这里采用https://github.com/go-redis/redis (opens new window)连接 Redis 数据库并进行操作,因为go-redis支持连接哨兵及集群模式的 Redis。

使用以下命令下载并安装:

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

# 连接

# 普通连接

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password set
		DB:       0,  // use default DB
	})

	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 连接哨兵模式

func initClient()(err error){
	rdb := redis.NewFailoverClient(&redis.FailoverOptions{
		MasterName:    "master",
		SentinelAddrs: []string{"x.x.x.x:26379", "xx.xx.xx.xx:26379", "xxx.xxx.xxx.xxx:26379"},
	})
	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}
1
2
3
4
5
6
7
8
9
10
11

# 连接集群模式

func initClient()(err error){
	rdb := redis.NewClusterClient(&redis.ClusterOptions{
		Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
	})
	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}
1
2
3
4
5
6
7
8
9
10

# 基本使用

# set/get

func redisExample() {
	err := rdb.Set("score", 100, 0).Err()
	if err != nil {
		fmt.Printf("set score failed, err:%v\n", err)
		return
	}

	val, err := rdb.Get("score").Result()
	if err != nil {
		fmt.Printf("get score failed, err:%v\n", err)
		return
	}
	fmt.Println("score", val)

	val2, err := rdb.Get("name").Result()
	if err == redis.Nil {
		fmt.Println("name does not exist")
	} else if err != nil {
		fmt.Printf("get name failed, err:%v\n", err)
		return
	} else {
		fmt.Println("name", val2)
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# zset

func redisExample2() {
	zsetKey := "language_rank"
	languages := []*redis.Z{
		&redis.Z{Score: 90.0, Member: "Golang"},
		&redis.Z{Score: 98.0, Member: "Java"},
		&redis.Z{Score: 95.0, Member: "Python"},
		&redis.Z{Score: 97.0, Member: "JavaScript"},
		&redis.Z{Score: 99.0, Member: "C/C++"},
	}
	// ZADD
	num, err := rdb.ZAdd(zsetKey, languages...).Result()
	if err != nil {
		fmt.Printf("zadd failed, err:%v\n", err)
		return
	}
	fmt.Printf("zadd %d succ.\n", num)

	// 把Golang的分数加10
	newScore, err := rdb.ZIncrBy(zsetKey, 10.0, "Golang").Result()
	if err != nil {
		fmt.Printf("zincrby failed, err:%v\n", err)
		return
	}
	fmt.Printf("Golang's score is %f now.\n", newScore)

	// 取分数最高的3个
	ret, err := rdb.ZRevRangeWithScores(zsetKey, 0, 2).Result()
	if err != nil {
		fmt.Printf("zrevrange failed, err:%v\n", err)
		return
	}
	for _, z := range ret {
		fmt.Println(z.Member, z.Score)
	}

	// 取95~100分的
	op := &redis.ZRangeBy{
		Min: "95",
		Max: "100",
	}
	ret, err = rdb.ZRangeByScoreWithScores(zsetKey, op).Result()
	if err != nil {
		fmt.Printf("zrangebyscore failed, err:%v\n", err)
		return
	}
	for _, z := range ret {
		fmt.Println(z.Member, z.Score)
	}
}
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
49

更多文档 (opens new window)

# 另一种操作 redis

go get github.com/gomodule/redigo/redis
1

# 简单操作

package main

import (
	"fmt"
	"github.com/gomodule/redigo/redis"
)

func main(){
	conn, err := redis.Dial("tcp", "122.51.79.172:6379")
	if err != nil {
		fmt.Println("redis connect error. err: ",err)
		return
	}
	defer conn.Close()
	// 设置值
	if _, err := conn.Do("set", "name", "joker");err!=nil{
		fmt.Println("set key failed. err:",err)
	}
	// 获取值
	reply, err := conn.Do("get", "name")
	if err != nil {
		fmt.Println("get key failed. err:",err)
	}
	// 输出值
	s, err := redis.String(reply,err)
	if err != nil {
		fmt.Println("data format failed. err:",err)
	}
	fmt.Println(s)

}
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

说明:连接成功后,所有得操作都通过Do()方法,返回的是一个接口类型,如果要输出其值需要对其进行类型断言。这个库已经封装了需要的类型断言。

# 连接池

连接池的作用是维护一定数量的连接,我们需要的时候就从连接池中取一个连接进行操作,操作结束后再把它还回去,可以减少客户端每次都需要与服务端连接所造成的性能损耗。

代码如下:

func myRedisPool()*redis.Pool{
	return &redis.Pool{
		Dial: func() (conn redis.Conn, err error) {
			return redis.Dial("tcp","x.x.x.x:6379")
		},
		TestOnBorrow:    nil,
		MaxIdle:         0,
		MaxActive:       0,
		IdleTimeout:     0,
		Wait:            false,
		MaxConnLifetime: 0,
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13

其中:

  • Dial:初始化连接 redis 的代码
  • TestOnBorrow:用于测试 redis
  • MaxIdle:最大空闲数
  • MaxActive:最大连接数,0 表示不限制
  • IdleTimeout:最大空闲时间
  • MaxConnLifetime:最大连接活跃时间

注意:要从连接池中取数据要保证连接池没有关闭

操作:

(1)、从连接池取连接

pool := myRedisPool()
pool.Get()
1
2

(2)、关闭连接

pool.Close()
1

其他操作。

package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "time"

    "github.com/garyburd/redigo/redis"
)

const (
    RedisURL            = "redis://*****:6379"
    redisMaxIdle        = 3   //最大空闲连接数
    redisIdleTimeoutSec = 240 //最大空闲连接时间
    RedisPassword       = "*****"
)

// NewRedisPool 返回redis连接池
func NewRedisPool(redisURL string) *redis.Pool {
    return &redis.Pool{
        MaxIdle:     redisMaxIdle,
        IdleTimeout: redisIdleTimeoutSec * time.Second,
        Dial: func() (redis.Conn, error) {
            c, err := redis.DialURL(redisURL)
            if err != nil {
                return nil, fmt.Errorf("redis connection error: %s", err)
            }
            //验证redis密码
            if _, authErr := c.Do("AUTH", RedisPassword); authErr != nil {
                return nil, fmt.Errorf("redis auth password error: %s", authErr)
            }
            return c, err
        },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            if err != nil {
                return fmt.Errorf("ping redis error: %s", err)
            }
            return nil
        },
    }
}

func set(k, v string) {
    c := NewRedisPool(RedisURL).Get()
    defer c.Close()
    _, err := c.Do("SET", k, v)
    if err != nil {
        fmt.Println("set error", err.Error())
    }
}

func getStringValue(k string) string {
    c := NewRedisPool(RedisURL).Get()
    defer c.Close()
    username, err := redis.String(c.Do("GET", k))
    if err != nil {
        fmt.Println("Get Error: ", err.Error())
        return ""
    }
    return username
}

func SetKeyExpire(k string, ex int) {
    c := NewRedisPool(RedisURL).Get()
    defer c.Close()
    _, err := c.Do("EXPIRE", k, ex)
    if err != nil {
        fmt.Println("set error", err.Error())
    }
}

func CheckKey(k string) bool {
    c := NewRedisPool(RedisURL).Get()
    defer c.Close()
    exist, err := redis.Bool(c.Do("EXISTS", k))
    if err != nil {
        fmt.Println(err)
        return false
    } else {
        return exist
    }
}

func DelKey(k string) error {
    c := NewRedisPool(RedisURL).Get()
    defer c.Close()
    _, err := c.Do("DEL", k)
    if err != nil {
        fmt.Println(err)
        return err
    }
    return nil
}

func SetJson(k string, data interface{}) error {
    c := NewRedisPool(RedisURL).Get()
    defer c.Close()
    value, _ := json.Marshal(data)
    n, _ := c.Do("SETNX", k, value)
    if n != int64(1) {
        return errors.New("set failed")
    }
    return nil
}

func getJsonByte(k string) ([]byte, error) {
    jsonGet, err := redis.Bytes(c.Do("GET", key))
    if err != nil {
        fmt.Println(err)
        return nil, err
    }
    return jsonGet, nil
}
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
上次更新: 2025/07/18, 11:04:43
使用sqlx
操作NSQ

← 使用sqlx 操作NSQ→

最近更新
01
2025年,SRE在企业中可以做哪些事
07-18
02
SRE 如何提升自己在团队中的影响力
07-18
03
使用Go开发MCP服务
07-18
更多文章>
Theme by Vdoing | Copyright © 2019-2025 乔克 | MIT License | 渝ICP备20002153号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式