成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何在Go語言中使用Redis連接池

開發(fā) 前端 Redis
我們就有了 keepalive 的機(jī)制,不會(huì)出現(xiàn) timeout 的連接了,從 redis 連接池里面取出的連接都是可用的連接了。看似簡單的代碼,卻完美的解決了連接池里面超時(shí)連接的問題。同時(shí),就算 Redis server 重啟等情況,也能保證連接自動(dòng)重連。

一、關(guān)于連接池

一個(gè)數(shù)據(jù)庫服務(wù)器只擁有有限的資源,并且如果你沒有充分使用這些資源,你可以通過使用更多的連接來提高吞吐量。一旦所有的資源都在使用,那么你就不 能通過增加更多的連接來提高吞吐量。事實(shí)上,吞吐量在連接負(fù)載較大時(shí)就開始下降了。通常可以通過限制與可用的資源相匹配的數(shù)據(jù)庫連接的數(shù)量來提高延遲和吞 吐量。

 

如果不使用連接池,那么,每次傳輸數(shù)據(jù),我們都需要進(jìn)行創(chuàng)建連接,收發(fā)數(shù)據(jù),關(guān)閉連接。在并發(fā)量不高的場景,基本上不會(huì)有什么問題,一旦并發(fā)量上去了,那么,一般就會(huì)遇到下面幾個(gè)常見問題:

  • 性能普遍上不去

  • CPU 大量資源被系統(tǒng)消耗

  • 網(wǎng)絡(luò)一旦抖動(dòng),會(huì)有大量 TIME_WAIT 產(chǎn)生,不得不定期重啟服務(wù)或定期重啟機(jī)器

  • 服務(wù)器工作不穩(wěn)定,QPS 忽高忽低

要想解決這些問題,我們就要用到連接池了。連接池的思路很簡單,在初始化時(shí),創(chuàng)建一定數(shù)量的連接,先把所有長連接存起來,然后,誰需要使用,從這里取走,干完活立馬放回來。 如果請求數(shù)超出連接池容量,那么就排隊(duì)等待、退化成短連接或者直接丟棄掉。

二、使用連接池遇到的坑

最近在一個(gè)項(xiàng)目中,需要實(shí)現(xiàn)一個(gè)簡單的 Web Server 提供 Redis 的 HTTP interface,提供 JSON 形式的返回結(jié)果。考慮用 Go 來實(shí)現(xiàn)。

首先,去看一下 Redis 官方推薦的 Go Redis driver。官方 Star 的項(xiàng)目有兩個(gè):Radix.v2 和 Redigo。經(jīng)過簡單的比較后,選擇了更加輕量級和實(shí)現(xiàn)更加優(yōu)雅的 Radix.v2。

Radix.v2 包是根據(jù)功能劃分成一個(gè)個(gè)的 sub package,每一個(gè) sub package 在一個(gè)獨(dú)立的子目錄中,結(jié)構(gòu)非常清晰。我的項(xiàng)目中會(huì)用到的 sub package 有 redis 和 pool。

由于我想讓這種被 fork 的進(jìn)程***簡單點(diǎn),做的事情單一一些,所以,在沒有深入去看 Radix.v2 的 pool 的實(shí)現(xiàn)之前,我選擇了自己實(shí)現(xiàn)一個(gè) Redis pool。(這里,就不貼代碼了。后來發(fā)現(xiàn)自己實(shí)現(xiàn)的 Redis pool 與 Radix.v2 實(shí)現(xiàn)的 Redis pool 的原理是一樣的,都是基于 channel 實(shí)現(xiàn)的, 遇到的問題也是一樣的。)

不過在測試過程中,發(fā)現(xiàn)了一個(gè)詭異的問題。在請求過程中經(jīng)常會(huì)報(bào) EOF 錯(cuò)誤。而且是概率性出現(xiàn),一會(huì)有問題,一會(huì)又好了。通過反復(fù)的測試,發(fā)現(xiàn) bug 是有規(guī)律的,當(dāng)程序空閑一會(huì)后,再進(jìn)行連續(xù)請求,會(huì)發(fā)生3次失敗,然后之后的請求都能成功,而我的連接池大小設(shè)置的是3。再進(jìn)一步分析,程序空閑300秒 后,再請求就會(huì)失敗,發(fā)現(xiàn)我的 Redis server 配置了 timeout 300,至此,問題就清楚了。是連接超時(shí) Redis server 主動(dòng)斷開了連接。客戶端這邊從一個(gè)超時(shí)的連接請求就會(huì)得到 EOF 錯(cuò)誤。

然后我看了一下 Radix.v2 的 pool 包的源碼,發(fā)現(xiàn)這個(gè)庫本身并沒有檢測壞的連接,并替換為新的連接的機(jī)制。也就是說我每次從連接池里面 Get 的連接有可能是壞的連接。所以,我當(dāng)時(shí)臨時(shí)的解決方案是通過增加失敗后自動(dòng)重試來解決了。不過,這樣的處理方案,連接池的作用好像就沒有了。技術(shù)債能早點(diǎn) 還的還是早點(diǎn)還上。

三、使用連接池的正確姿勢

想到我們的 ngx_lua 項(xiàng)目里面也大量使用 redis 連接池,他們怎么沒有遇到這個(gè)問題呢。只能去看看源碼了。

經(jīng)過抽象分離, ngx_lua 里面使用 redis 連接池部分的代碼大致是這樣的:

 

  1. server { 
  2.     location /pool { 
  3.         content_by_lua_block { 
  4.             local redis = require "resty.redis" 
  5.             local red = redis:new() 
  6.  
  7.             local ok, err = red:connect("127.0.0.1"6379
  8.             if not ok then 
  9.                 ngx.say("failed to connect: ", err) 
  10.                 return 
  11.             end 
  12.  
  13.             ok, err = red:set("hello""world"
  14.             if not ok then 
  15.                 return 
  16.             end 
  17.  
  18.             red:set_keepalive(10000100
  19.         } 
  20.     } 

發(fā)現(xiàn)有個(gè) set_keepalive 的方法,查了一下官方文檔,方法的原型是 syntax: ok, err = red:set_keepalive(max_idle_timeout, pool_size) 貌似 max_idle_timeout 這個(gè)參數(shù),就是我們所缺少的東西,然后進(jìn)一步跟蹤源碼,看看里面是怎么保證連接有效的。

 

  1. function _M.set_keepalive(self, ...) 
  2.     local sock = self.sock 
  3.     if not sock then 
  4.         return nil, "not initialized" 
  5.     end 
  6.  
  7.     if self.subscribed then 
  8.         return nil, "subscribed state" 
  9.     end 
  10.  
  11.     return sock:setkeepalive(...) 
  12. end 

至此,已經(jīng)清楚了,使用了 tcp 的 keepalive 心跳機(jī)制。

于是,通過與 Radix.v2 的作者一些討論,選擇自己在 redis 這層使用心跳機(jī)制,來解決這個(gè)問題。

四、***的解決方案

在創(chuàng)建連接池之后,起一個(gè) goroutine,每隔一段 idleTime 發(fā)送一個(gè) PING 到 Redis server。其中,idleTime 略小于 Redis server 的 timeout 配置。
連接池初始化部分代碼如下:

  1. p, err := pool.New("tcp", u.Host, concurrency) 
  2. errHndlr(err) 
  3. go func() { 
  4.     for { 
  5.         p.Cmd("PING"
  6.         time.Sleep(idelTime * time.Second) 
  7.     } 
  8. }() 

使用 redis 傳輸數(shù)據(jù)部分代碼如下:

 

  1. func redisDo(p *pool.Pool, cmd string, args ...interface{}) (reply *redis.Resp, err error) { 
  2.     reply = p.Cmd(cmd, args...) 
  3.     if err = reply.Err; err != nil { 
  4.         if err != io.EOF { 
  5.             Fatal.Println("redis", cmd, args, "err is", err) 
  6.         } 
  7.     } 
  8.  
  9.     return 

其中,Radix.v2 連接池內(nèi)部進(jìn)行了連接池內(nèi)連接的獲取和放回,代碼如下:

 

  1. // Cmd automatically gets one client from the pool, executes the given command 
  2. // (returning its result), and puts the client back in the pool 
  3. func (p *Pool) Cmd(cmd string, args ...interface{}) *redis.Resp { 
  4.     c, err := p.Get() 
  5.     if err != nil { 
  6.         return redis.NewResp(err) 
  7.     } 
  8.     defer p.Put(c) 
  9.  
  10.     return c.Cmd(cmd, args...) 

這樣,我們就有了 keepalive 的機(jī)制,不會(huì)出現(xiàn) timeout 的連接了,從 redis 連接池里面取出的連接都是可用的連接了。看似簡單的代碼,卻***的解決了連接池里面超時(shí)連接的問題。同時(shí),就算 Redis server 重啟等情況,也能保證連接自動(dòng)重連。

責(zé)任編輯:王雪燕 來源: 極客頭條
相關(guān)推薦

2013-06-25 09:52:32

GoGo語言Go編程

2019-12-30 15:30:13

連接池請求PHP

2011-06-01 13:54:10

MySQL

2022-09-29 10:01:05

Go編程語言文本文件

2022-11-03 20:38:01

CMD命令Go

2014-04-09 09:32:24

Go并發(fā)

2009-06-15 13:46:00

netbeans設(shè)置數(shù)據(jù)庫連接池

2011-05-25 13:22:05

PHPJSON

2024-04-01 00:02:56

Go語言代碼

2011-08-25 09:55:27

2025-03-27 00:45:00

2010-03-11 19:16:32

Python語言

2024-05-10 08:36:40

Go語言對象

2023-10-09 07:14:42

panicGo語言

2025-02-13 09:02:04

2019-09-16 19:00:48

Linux變量

2020-11-30 11:55:07

Docker命令Linux

2014-07-02 09:47:06

SwiftCocoaPods

2020-04-09 10:18:51

Bash循環(huán)Linux

2024-09-06 11:34:15

RustAI語言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲精品成人免费 | 丝袜美腿一区二区三区 | 色在线视频网站 | 成人黄色在线观看 | 国产97视频在线观看 | 精品国产一区二区三区av片 | 成人网址在线观看 | 亚洲欧美日韩精品久久亚洲区 | 亚洲一级av毛片 | 精品一区二区三区四区 | 国产成人99久久亚洲综合精品 | 日本一卡精品视频免费 | 日本视频在线 | 国产一区二区三区久久久久久久久 | 久久久久网站 | 一区二区久久 | 中文字幕一区二区三区不卡在线 | 国产91亚洲精品 | 午夜99 | 国产精品久久久久久久久久久免费看 | 极情综合网 | 亚洲精品久久久久中文字幕二区 | 日韩欧美一级片 | 91精品久久久久久久久中文字幕 | 91社区在线观看播放 | 国产在线拍偷自揄拍视频 | 亚洲精品二区 | 国产精品久久久久一区二区三区 | 国产精品久久久久久久久久久久 | 成人精品免费视频 | 欧美日韩一区在线播放 | 日韩高清av | 久久久成人一区二区免费影院 | aaaaaaa片毛片免费观看 | 久久久观看 | 国产一二三视频在线观看 | 久久草在线视频 | av黄色在线| 午夜精品一区二区三区在线视频 | 一级毛片网 | wwwsihu|