Redis | 青训营笔记

55 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 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() //关闭连接池
}