Redis 在 Go 項(xiàng)目中的集成和統(tǒng)一管理
本節(jié)我們?cè)陧?xiàng)目中安裝和集成 go-redis,讓項(xiàng)目能訪問Redis,后面實(shí)戰(zhàn)項(xiàng)目中的用戶認(rèn)證體系會(huì)依賴Redis來實(shí)現(xiàn),像Token、Session這些都是在Redis中存儲(chǔ)的。
本節(jié)大綱如下:
圖片
Redis的使用場(chǎng)景有不少,不過有一點(diǎn)需要提醒的是別把Redis當(dāng)數(shù)據(jù)庫用哦。
這里分享一篇 Redis應(yīng)用場(chǎng)景匯總,里面羅列了十幾個(gè)場(chǎng)景,大家有興趣的可以看一下。
go-redis 的安裝和配置
在我們的Go項(xiàng)目里訪問Redis使用的是 go-redis 這個(gè)包,之前也見過一些項(xiàng)目使用redigo 來訪問Redis,不過redigo已經(jīng)停止維護(hù)了,所以就不考慮使用它了。
安裝 go-redis 使用以下命令
go get github.com/redis/go-redis/v9安裝過程中會(huì)向項(xiàng)目依賴中添加下面這些包,在gomod 文件中也會(huì)看到它們的身影。
圖片
依賴下載完成后,我們先不著急去初始化它,還是先把相關(guān)的配置先在配置文件里寫好。在 applicaiton.dev.yaml 增加Redis相關(guān)配置。
redis: # 記得更改成自己的連接配置
  addr: 127.0.0.1:31379
  password: 123456
  pool_size: 10
  db: 0其他兩個(gè)環(huán)境的配置文件建議也先加上,避免配置文件之間結(jié)構(gòu)和字段相差太多,等有測(cè)試和生產(chǎn)環(huán)境后再把配置調(diào)整過去即可。
配置添加完后,我們?cè)?config.go 中增加 Redis 這些配置字段的對(duì)應(yīng)的類型定義
var (
 ...
 Redis    *redisConfig
)
// Redis 配置
type redisConfig struct {
 Addr     string `mapstructure:"addr"`
 Password string `mapstructure:"password"`
 PoolSize int    `mapstructure:"pool_size"`
 DB       int    `mapstructure:"db"`
}同時(shí)也在 bootstrap.go 中把config文件中的redis配置字段映射到 redisConfig 類型的變量 config.Redis上
func init() {
 env := os.Getenv("ENV")
 vp := viper.New()
    ...
    
 vp.UnmarshalKey("redis", &Redis)
}配置做好后,接下來我們?cè)?dal/cache 目錄中新建redisinit.go 文件,在其中對(duì)go-redis客戶端進(jìn)行初始化
var redisClient *redis.Client
func Redis() *redis.Client {
 return redisClient
}
func init() {
 redisClient = redis.NewClient(&redis.Options{
  Addr:         config.Redis.Addr,
  Password:     config.Redis.Password,
  DB:           config.Redis.DB,
  PoolSize:     config.Redis.PoolSize,
  DialTimeout:  10 * time.Second,
  ReadTimeout:  30 * time.Second,
  WriteTimeout: 30 * time.Second,
  PoolTimeout:  30 * time.Second,
 })
 
 if err :=redisClient.Ping(context.Background()).Err(); err != nil {
  // 連接不上redis 讓項(xiàng)目停止啟動(dòng)
  panic(err)
 }}跟初始化GORM時(shí)一樣,如果你不想用Go的init機(jī)制,這里可以把這個(gè)初始化方法修改名成InitRedis,到main函數(shù)中去調(diào)用它來手動(dòng)完成初始化。
Redis Key 的管理
我們?cè)谑褂肦edis的時(shí)候,最好把Key 放在項(xiàng)目里統(tǒng)一的地方進(jìn)行管理,同時(shí)在命名時(shí)給Key加上包含業(yè)務(wù)、項(xiàng)目、模塊信息的前綴名,通過簽證在查問題的時(shí)候我們最起碼能快速定位到緩存是哪個(gè)項(xiàng)目寫進(jìn)去的。
我在平時(shí)維護(hù)項(xiàng)目中被 Redis 搞的頭大的大部分情況是,很多舊代碼在A項(xiàng)目里緩存了個(gè)什么數(shù)據(jù),然后到下游的B項(xiàng)目再去讀這個(gè)數(shù)據(jù),根據(jù)緩存里數(shù)據(jù)的狀態(tài)執(zhí)行不同的邏輯分支。
有的時(shí)候監(jiān)控系統(tǒng)報(bào)告B項(xiàng)目出了Bug,查問題看到從Redis里讀取到的數(shù)據(jù)跟預(yù)想的不一樣,一般人都會(huì)先在B項(xiàng)目中Debug,看下緩存設(shè)置的程序是不是有問題,但是針對(duì)這種情況把整個(gè)B項(xiàng)目搜遍也沒發(fā)現(xiàn)緩存是從哪里存進(jìn)去的。
所以 Redis Key 的命名不能太隨意,最好包含設(shè)置緩存的項(xiàng)目名、所屬業(yè)務(wù)等能確定緩存來源的信息。
我們?cè)陧?xiàng)目的 common/enum 目錄中新增rediskey.go 在其中對(duì)Redis 緩存的 Key 進(jìn)行統(tǒng)一管理
/ Redis Key的格式為:
//   項(xiàng)目名:模塊名:鍵名
const (
 REDIS_KEY_DEMO_ORDER_DETAIL = "GOMALL:DEMO:ORDER_DETAIL_%s"
)這里先定義一個(gè)測(cè)試用的Redis緩存的鍵名。
- GOMALL:DEMO:ORDER_DETAIL_%s
 
Key的格式為 項(xiàng)目名:模塊名:鍵名,你的公司大的話還可以在最前面加一個(gè)業(yè)務(wù)名,免得項(xiàng)目名重復(fù)了。
項(xiàng)目名:GOMALL
模塊名:DEMO (因?yàn)槭茄菔荆G闆r下是ORDER、USER 這種模塊名)
鍵名:ORDER_DETAIL_%s
在使用到這個(gè) Redis 緩存的方法中可以來拿業(yè)務(wù)標(biāo)識(shí)(比如訂單號(hào)) 拼裝出完整的Redis Key
redisKey := fmt.Sprintf(enum.REDIS_KEY_DEMO_ORDER_DETAIL, demoOrder.OrderNo)Redis怎么做日志鏈路追蹤
和在項(xiàng)目中集成ORM使用數(shù)據(jù)庫時(shí)一樣,除了關(guān)注常規(guī)的功能外,我們還要關(guān)注組件集成進(jìn)項(xiàng)目后的可觀測(cè)性。最基礎(chǔ)的保障觀測(cè)性的方式是組件日志整合到應(yīng)用日志,并且通過traceId、reqeustId等方式講它們歸因到對(duì)應(yīng)的請(qǐng)求上。















 
 
 

 
 
 
 