https://github.com/iamlongalong/longredis
long redis learn
https://github.com/iamlongalong/longredis
Last synced: about 2 months ago
JSON representation
long redis learn
- Host: GitHub
- URL: https://github.com/iamlongalong/longredis
- Owner: iamlongalong
- Created: 2021-05-17T12:52:33.000Z (about 4 years ago)
- Default Branch: main
- Last Pushed: 2022-08-27T03:49:13.000Z (almost 3 years ago)
- Last Synced: 2025-02-08T00:28:23.756Z (4 months ago)
- Language: Go
- Size: 36.1 KB
- Stars: 0
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
## 背景
由于业务需要同时兼容 redis 及 redis-cluster,且希望能直接通过 配置 进行切换,因此决定开发该 redis 包。同时,添加了一些统一的 hook 以减少业务方的工作量。## longredis说明
longredis 是在 go-redis 的基础上做了封装。
主要封装了如下能力:
1. Client 和 连接池管理 (统一的连接池)
2. Client 和 Prefix 绑定
3. Opentracing
4. Metrics
5. Error log
6. Slow query log
7. 超时管理
8. 探活与重新连接### longredis 基本使用方式
```golang
// 基础 client 初始化
NormalClient, err := longredis.NewClient(longredis.Option{
Addrs: []string{"127.0.0.1:6379"},
Password: "xxxxxx",
RedisType: longredis.ParseRedisType("single"), // 默认为 cluster
RequestTimeout: time.Second * 1,
})if err != nil {
return err
}// 增加不同的 prefix client => 不同业务使用不同的前缀以做区分
SessionCLient := NormalClient.SubPrefix("session")
FreqLimitClient := NormalClient.SubPrefix("limitation")
// ……// 使用
sess, err := SessionCLient.Get(ctx, user.ID)
if err != nil {
// ……
}
```### 特别的:
特别的:
1. GetBind / HGetBind```golang
targetObj := &TarObj{}err := xxClient.GetBind(ctx, "xxkey", targetObj)
if err != nil {
// ……
}// 同理,HGetBind
```2. GetBool
```golang
isTrue, err := xxClient.GetBool(ctx, "xxkey")
if err != nil {
// ……
}
// 注意,bool 的 parse 方法为 strconv.ParseBool(),因此只能识别以下字符
// true => "1", "t", "T", "true", "TRUE", "True"
// false => "0", "f", "F", "false", "FALSE", "False"
// 当不是上述字符时,会返回 error
```3. TxPipeline
目前对 pipeline 没有做太多封装,是直接返回的 go-redis 的 pipeline,在使用时,需要注意 prefix 的问题。在一些场景下,需要显式使用 xxClient.WithPrefix(key) 进行 prefix 的添加。
```golang
c := redis.XxClient
pipe := c.TxPipeline(ctx)
pipe.Set(ctx, c.WithPrefix(key1), "xxx")
pipe.HSet(ctx, c.WithPrefix(key2), "field1", "xxx")results, err := pipe.Exec()
if err != nil {
// ……
}
```4. 默认值
在 longredis 中,设置了一系列的默认值,具体可以查看 longredis/opt 每项的注释。
不过,绝大多数默认值你都无需关心,除非你遇到了特殊需求。这几项重要的默认值你应当知道:
- RedisType: redis 类型,枚举值,可为 cluster single sentinel , 默认为 cluster。
- RequestTimeout: 请求超时时间,time.Duration ,默认为 3s,但会以你传的 ctx 的最小超时时间为准。
- SlowLog.SlowTime: 慢查询时间,time.Duration, 默认为 300ms
- Metrics、Tracing、ErrorLog、SlowLog 默认都是开启状态。### 小技巧
Option 设置了 yaml 和 json 的字段,为蛇形命名风格,因此可以通过 scan 的方式将 配置项中的字段 扫描到 option 中。
假设 config.yaml 中的内容有一段是这样的:
```yaml
redis:
api_prefix: "api"
sess_prefix: "session"
figma_prefix: "fig"
options:
addrs: ["127.0.0.1:6379"]
redis_type: "cluster"
password: "xxx"
request_timeout: 1s
metrics:
namespace: mastergo
```我们在项目中可以用这样的方式实例化 redis client:
```golang
var (
BaseClient *longredis.Client // 基础 client
ApiClient *longredis.Client // 用于 普通 api 的 client
SessClient *longredis.Client // 用于 session 的 client
FigmaClient *longredis.Client // 用于 figma 的 client
)func Startup() error {
opt := longredis.Option{}
err := config.DeepGet("redis.options").Scan(&opt)
if err != nil {
return errors.Wrap(err, "init redis scan option fail")
}
// 设置 默认 logger
longredis.SetDefaultLogger(log.NewOctopusLog(longredis.LevelDebug))
apiPrefix := config.DeepGet("redis.api_prefix").String("api")
sessPrefix := config.DeepGet("redis.sess_prefix").String("session")
figmaPrefix := config.DeepGet("redis.figma_prefix").String("fig")
BaseClient, err = longredis.NewClient(opt) // prefix 为 ""
if err != nil {
return errors.Wrap(err, "init redis create client fail")
}
ApiClient = BaseClient.SubPrefix(apiPrefix) // prefix 为 api:
SessClient = ApiClient.SubPrefix(sessPrefix) // prefix 为 api:session:
FigmaClient = ApiClient.SubPrefix(fimaPrefix) // prefix 为 api:fig:return nil
}
```### 常见误用说明
1. 由于一些特殊场景的需要,把内部的 go-redis 的 client 开放了出来 (通过 xxClient.RedisConn() 获取),虽然这个 client 看起来也能使用一系列的 Get/Set 等方法,但该 client 缺少 prefix 的管理,会造成预期的 key 和实际的 key 不一致的问题,因此,不要直接使用 内部client,除非你知道自己在做什么。
```golang
// !!! 错误例子,引以为戒 !!!!
SessClient.RedisConn().Get(ctx, 1001001) // => 对应到命令为 GET 1001001// 正确使用
SessClient.Get(ctx, 1001001) // => 对应的命令为 GET api:session:1001001
```2. client 自带了 连接池的管理能力,自带了 prefix 的管理能力,因此仅需要初始化一个 `基础client` (baseClient、normalClient), 其他业务所需的特定前缀的 client,应当使用 `baseClient.SubPrefix(xxx)` 的方式生成。而无需进行多次 longredis.NewClient(opt) 的实例化。
```golang
// !!! 错误例子,引以为戒 !!!!
BaseClient := longredis.NewClient(longredis.Option{
Addr: ["127.0.0.1:6379"],
Prefix: "",
})
ApiClient := longredis.NewClient(longredis.Option{
Addr: ["127.0.0.1:6379"],
Prefix: "api",
})
SessClient := longredis.NewClient(longredis.Option{
Addr: ["127.0.0.1:6379"],
Prefix: "api:session",
})// 正确使用
BaseClient := longredis.NewClient(longredis.Option{
Addr: ["127.0.0.1:6379"],
})
ApiClient := BaseClient.SubPrefix("api")
SessClient := ApiClient.SubPrefix("session")```
## 最后
由于时间有限、水平有限,有所遗漏之处还请担待,发现 bug、有无法满足的需求 等,欢迎提 issue 或者 pr。
## TODO
希望这个库能成为一个 开箱即用的、工程化的 redis 库,还有如下部分没有完成:
- [ ] pipeline 未封装,容易弄混 prefix
- [ ] 还有大量命令未封装
- [ ] 需要基于该 redis 库,集成多种常用的 redis 工具,例如
- [ ] 布隆过滤器
- [ ] 分布式锁
- [ ] metrics backend
- [ ] session
- [ ] 分布式 limiter
- [ ] 排行榜
- [ ] 任务队列
- [ ] id 生成器
- [ ] 签到表
- [ ] 需要更多的 example## 测试环境搭建
可以参考 https://github.com/iamlongalong/redis-instances 进行操作
## PS
redis 真的是一个很牛逼的项目啊,不仅 redis 本身,还有其扩展部分 redis-stack,包含了
- redisinsight (图形操作面板 + 教程)
- Search (文档查询、全文索引)
- JSON (文档存储,类似 mongodb)
- graph (图数据库)
- Time series (时间序列数据库)
- 其他常用的使用的封装
- 布隆过滤器
- 布谷鸟过滤器
- 最小计数草图 (可以参考[这篇文档](https://zhuanlan.zhihu.com/p/369981005)介绍)
- top-k
- tdigest具体可以查看[官网信息](https://redis.io/docs/stack/get-started/)
另外,redis 官方也做了很多教程啊!!! 可以查看 [官方站点](https://university.redis.com/)
不得不说,redis-stack 把实验教程直接融入到 redis-insight 项目中,真的是太新手友好了!具体可以查看 [官方说明](https://redis.io/docs/stack/insight/)