單例模式在生產環境jedis集群中的應用


背景:不久前單位上線一款應用,上了生產環境之后,沒過多久,便吃掉了服務器所有的內存,最后導致網站服務掛了。

 

在解決了這一問題之后,我發現這其實是典型的一單例模式,現分享一下。

之前存在問題的老代碼如下:

這是導致問題所在的那個關鍵方法

public synchronized static JedisCluster getJedisCluster() {
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(MAX_ACTIVE);
    config.setMaxIdle(MAX_IDLE);
    config.setMaxWaitMillis(MAX_WAIT);
    config.setTestOnBorrow(TEST_ON_BORROW);
    
    // 集群模式
    JedisPoolConfig poolConfig = new JedisPoolConfig();
    Set<HostAndPort> nodes = new HashSet<HostAndPort>();

    HostAndPort hostAndPort1 = new HostAndPort("服務器地址1", 端口1);
    HostAndPort hostAndPort2 = new HostAndPort("服務器地址2", 端口2);
    HostAndPort hostAndPort3 = new HostAndPort("服務器地址3", 端口3);

    nodes.add(hostAndPort1);
    nodes.add(hostAndPort2);
    nodes.add(hostAndPort3);

    JedisCluster jedisCluster = new JedisCluster(nodes, poolConfig);
    
    return jedisCluster;
}

以上這段代碼是有問題的,大家看出來了嗎?

問題在於,雖然方法聲明為synchronized static,但是在並發多線程的情況下,並不能保證每個用戶線程只生成一個JedisCluster的實例。

這樣就會導致每個線程都會創建jedisCluster的實例,就會消耗內存,而且這塊內存又沒有被及時地釋放掉,導致多用戶並發以后,快速吃光了服務器的內存。

 

解決方法就是使用單例模式,把JedisCluster作為static的類成員,且使用懶漢單例模式,代碼如下:

public class OuterClass{
    ...
    private static JedisCluster jedisCluster = null;
    ...

    public synchronized static JedisCluster getJedisCluster() {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(MAX_ACTIVE);
        config.setMaxIdle(MAX_IDLE);
        config.setMaxWaitMillis(MAX_WAIT);
        config.setTestOnBorrow(TEST_ON_BORROW);
        
        // 集群模式
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        Set<HostAndPort> nodes = new HashSet<HostAndPort>();

        HostAndPort hostAndPort1 = new HostAndPort("服務器地址1", 端口1);
        HostAndPort hostAndPort2 = new HostAndPort("服務器地址2", 端口2);
        HostAndPort hostAndPort3 = new HostAndPort("服務器地址3", 端口3);

        nodes.add(hostAndPort1);
        nodes.add(hostAndPort2);
        nodes.add(hostAndPort3);

        // 只有當jedisCluster為空時才實例化
        if (jedisCluster == null) {
            jedisCluster = new JedisCluster(nodes, poolConfig);
        }

        return jedisCluster;
    }
}

這樣就會保證即使在高並發的環境下,所有用戶線程還是只會擁有一個JedisCluster的實例。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM