这是我参与「第五届青训营 」伴学笔记创作活动的第 15 天
Redis 介绍
Redis 是什么
Redis 是一个完全开源免费,遵守 BSD 协议的高性能 k-v 库
Redis 的特点
与多数 k-v 换存产品类似,Redis 具有以下特点:
- 支持数据的持久化:Redis 可以将内存中的数据保存在磁盘中,重启时重新写入缓存
- 支持数据的多样性:Redis 提供了包括 string、list、set、hash 等数据的存储
- 支持数据的备份:Redis 支持数据的 master-slave 模式的数据备份 相较于其他 k-v 产品, Redis 还具有以下优点
- 高性能:Redis 读的速度是 110000 次/s, 写的速度是 81000 次/s,单机可达 15w qps
- 原子性:Redis 的所有操作都是原子性的
- 拓展性:Redis 支持包括有序集合(ordered set)等数据结构,且具有诸如 key 过期,通知等丰富的特性
redis 的使用
redis 支持在 windows 环境下的使用,可通过链接下载 github.com/tporadowski…
在使用 go 操控 redis 时也具有相应的第三方开源库
go get github.com/garyburd/redigo/redis
使用 go 操控 Redis
链接 Redis
同使用 go 操控 MySQL 一样,使用 go 操控 Redis 也需要先与 Redis 服务器建立链接:
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
c, err := redis.Dial("tcp", "localhost:6379")
if err != nil {
fmt.Println("conn redis failed,", err)
return
}
fmt.Println("redis conn success")
defer c.Close()
}
Set 和 Get 操作
Redis 中最基础的便是 Set 和 Get 操作
Set:可以理解为向缓存中加入一个 k-v 对
Get:可以理解为查询 key 值在缓存中对应的 value
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
c, err := redis.Dial("tcp", "localhost:6379")
if err != nil {
fmt.Println("conn redis failed,", err)
return
}
defer c.Close()
_, err = c.Do("Set", "abc", 100)
if err != nil {
fmt.Println(err)
return
}
r, err := redis.Int(c.Do("Get", "abc"))
if err != nil {
fmt.Println("get abc failed,", err)
return
}
fmt.Println(r)
}
SIsMember 和 SRem 操作
与 Set 和 Get 类似,不同的是这两个指令操作的是哈希集合
SIsMember 向集合中加入 value
SRem 从集合中移除 value
在这次的青训营大项目中我也是对这两个指令进行了简单地应用:
// GetAFollowB 判断A是否关注了B
func (p *ProxyIndexMap) GetAFollowB(a, b int64) bool {
key := fmt.Sprintf("relation:%d", a)
return rdb.SIsMember(ctx, key, b).Val()
}
// SetAFollowB isFollowed:true已关注 false未关注
func (p *ProxyIndexMap) SetAFollowB(a, b int64, isFollowed bool) {
key := fmt.Sprintf("relation:%d", a)
if isFollowed {
rdb.SAdd(ctx, key, b)
}
rdb.SRem(ctx, key, b)
}
过期
缓存并非取之不尽,是有限的,对于一对 k-v,我们可以对 key 值设置过期时间,时间一到,便从缓存中清除,至于这对 k-v 对是存入数据库还是做其他操作视我们的需求而定
package main
import (
"fmt"
"github.com/garyburd/redigo/redis"
)
func main() {
c, err := redis.Dial("tcp", "localhost:6379")
if err != nil {
fmt.Println("conn redis failed,", err)
return
}
defer c.Close()
_, err = c.Do("expire", "abc", 10)
if err != nil {
fmt.Println(err)
return
}
}
Redis 链接池
Redis 链接的创建与销毁是十分消耗程序性能的,因此,go 中相应的第三方库也为 Redis 提供了相应的池化操作技术,这样在建立链接时便可以直接从池子中取出一个链接资源,使用完毕后再归还给池子即可,相应的代码如下:
package main
import(
"fmt"
"github.com/garyburd/redigo/redis"
)
var pool *redis.Pool //创建redis连接池
func init(){
pool = &redis.Pool{
MaxIdle:16,
// MaxActive:1000000,
MaxActive:0,
IdleTimeout:300,
Dial: func() (redis.Conn ,error){
return redis.Dial("tcp","localhost:6379")
},
}
}
func main(){
c := pool.Get() //从连接池,取一个链接
defer c.Close() //函数运行结束 ,把连接放回连接池
_,err := c.Do("Set","abc",200)
if err != nil {
fmt.Println(err)
return
}
r,err := redis.Int(c.Do("Get","abc"))
if err != nil {
fmt.Println("get abc faild :",err)
return
}
fmt.Println(r)
pool.Close() //关闭连接池
}