电竞比分网-中国电竞赛事及体育赛事平台

分享

Jedis分片Sentinel連接池實(shí)驗(yàn)

 WindySky 2016-02-18

Jedis分片Sentinel連接池實(shí)驗(yàn)

1.起因

眾所周知,Redis官方HA工具Sentinel已經(jīng)問世很久了,但令人費(fèi)解的是,Jedis官方卻遲遲沒有更新它的連接池。到目前Maven庫中最新的2.7.3版本為止,都只能要么使用分片連接池,要么使用不分片的Sentinel連接池。如果既進(jìn)行了Sharding,又對每組的主從實(shí)例配置Sentinel進(jìn)行監(jiān)控,怎么辦?答案是只能自己開發(fā)了,暈!還好萬能的GitHub上已經(jīng)有人提供了一個(gè)簡單可用的分片Sentinel連接池實(shí)現(xiàn),于是就直接拿來用用。


2.Sentinel配置

我的Redis是這樣配置的:一個(gè)主6379帶一個(gè)從16379,名字叫mymaster-6379;另一個(gè)主6380帶另一個(gè)從16380,名字叫mymaster-6380。Sentinel按照慣例,起三個(gè)實(shí)例26379,26380,26381。以其中一個(gè)為例,其他的Sentinel配置只是端口號不同:

port 26379
dir /tmp

sentinel monitor mymaster-6379 192.168.241.220 6379 2
sentinel down-after-milliseconds mymaster-6379 30000
sentinel parallel-syncs mymaster-6379 1
sentinel failover-timeout mymaster-6379 180000

sentinel monitor mymaster-6380 192.168.241.220 6380 2
sentinel down-after-milliseconds mymaster-6380 30000
sentinel parallel-syncs mymaster-6380 1
sentinel failover-timeout mymaster-6380 180000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

如果想要Sentinel快速failover,就把sentinel down-after-milliseconds mymaster-6379 30000中的30秒改短點(diǎn),這個(gè)時(shí)間是Sentinel Ping不到Master多久后開始failover。具體Redis主從復(fù)制和Sentinel如何配置就不贅述了,請參考我以前寫的Redis主從和HA配置。


3.Jedis客戶端擴(kuò)展

3.1 測試代碼

將GitHub那個(gè)開源的連接池引到工程里,使用起來很簡單,只需通過構(gòu)造方法傳入所有Sentinel實(shí)例的連接地址以及master的名字列表。連接池配置可以使用默認(rèn)的。

注意:一定要每次重新從pool中取一個(gè)連接,否則會(huì)一直訪問老master。

    public static void main(String[] args) throws Exception {
        Set<String> sentinels = new HashSet<String>();
        sentinels.add("192.168.111.222:26379");
        sentinels.add("192.168.111.222:26380");
        sentinels.add("192.168.111.222:26381");

        ShardedJedisSentinelPool pool = new ShardedJedisSentinelPool(
                Arrays.asList("mymaster-6379", "mymaster-6380"),
                sentinels
        );

        while (true) {
            String ts = new SimpleDateFormat("hh:mm:ss").format(new Date());
            ShardedJedis jedis = pool.getResource();
            try {
                System.out.println(ts + ": hello=" + jedis.get("hello"));
            } catch (Exception e) {
                System.out.println(ts + ": Cannot connect to Redis");
            } finally {
                jedis.close();
            }
            Thread.sleep(500L);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

3.2 連接泄露Bug

循環(huán)時(shí)發(fā)現(xiàn)ShardedJedisSentinelPool連接池有時(shí)竟然滿了!畢竟默認(rèn)是8個(gè)連接,但為什么會(huì)這樣?查了下代碼,果然是這個(gè)原因!這個(gè)新擴(kuò)展的pool沒有為getResource()出來的ShardedJedis設(shè)置DataSource,所以關(guān)閉ShardedJedis時(shí)沒法正常還回到連接池中。

補(bǔ)丁很簡單,就是參照J(rèn)edis的ShardedJedisPool,覆寫一些資源管理的方法。

    @Override
    public ShardedJedis getResource() {
        ShardedJedis jedis = super.getResource();
        jedis.setDataSource(this);
        return jedis;
    }

    @Override
    public void returnBrokenResource(final ShardedJedis resource) {
        if (resource != null) {
            returnBrokenResourceObject(resource);
        }
    }

    @Override
    public void returnResource(final ShardedJedis resource) {
        if (resource != null) {
            resource.resetState();
            returnResourceObject(resource);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

3.3 KeyTag

此外,ShardedJedisSentinelPool的構(gòu)造方法中沒提供傳入KeyTagPattern的地方,這也需要手動(dòng)傳入到ShardedJedisFactory中。需要的話,自己動(dòng)手加一下吧!


4.Failover實(shí)驗(yàn)

以key=hello為例,事先在6380實(shí)例上準(zhǔn)備好key的值。

4.1 實(shí)驗(yàn)結(jié)果

首先,啟動(dòng)Java程序不斷訪問。然后,在后臺kill掉6380那個(gè)Redis實(shí)例??刂婆_輸出會(huì)警告無法連接Redis。大概30秒左右,本地連接池注冊的Sentinel監(jiān)聽器會(huì)收到failover消息。于是,從pool.getResource()拿到的連接自動(dòng)切換到Slave實(shí)例了,又可以查詢到hello對應(yīng)的值了。

10:13:42: hello=nihaonihao111
10:13:42: Cannot connect to Redis
10:13:43: Cannot connect to Redis
10:13:45: Cannot connect to Redis
10:13:48: Cannot connect to Redis
10:13:50: Cannot connect to Redis
10:13:53: Cannot connect to Redis
10:13:56: Cannot connect to Redis
10:13:58: Cannot connect to Redis
10:14:01: Cannot connect to Redis
10:14:03: Cannot connect to Redis
10:14:06: Cannot connect to Redis
10:14:08: Cannot connect to Redis
10:14:11: Cannot connect to Redis
八月 24, 2015 10:14:13 上午 redis.clients.jedis.ShardedJedisSentinelPool initPool
信息: Created ShardedJedisPool to master at [192.168.111.222:6379 192.168.111.222:16380 ]
10:14:13: hello=nihaonihao111
10:14:14: hello=nihaonihao111
10:14:14: hello=nihaonihao111
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

4.2 如何恢復(fù)

如果想反復(fù)試驗(yàn)怎么辦?很簡單,重新啟動(dòng)6380實(shí)例,但此時(shí)16380已經(jīng)變成了Master,6380成了它的Slave。沒關(guān)系!隨便連接到一個(gè)Sentinel實(shí)例上,執(zhí)行sentinel failover mymaster-6380就可以強(qiáng)制failover一次。這樣6380和16380的主從關(guān)系就又恢復(fù)了!


5.總結(jié)

總體來說這個(gè)連接池還是不錯(cuò)的,雖然有點(diǎn)小問題,但免去了開發(fā)的麻煩!不知道用于生產(chǎn)環(huán)境的話,是否還有其他“坑”,不管怎樣可以先用著,感謝作者的分享!

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多