項目接入redis

首先通俗的介紹下redis:可以把redis當做一個數據庫,像mysql這樣,只是存放的方式和地方不一樣。

                                       redis將數據存放在內存中,所有讀取的速度肯定比mysql快。

                                       同時redis的數據類型是key-value型。和Map<String,Object>相似。所以對於java項目來說,很方便對redis                                         的數據操作。redis的value值可以支持 String,List,Set,ZSet(有序),Hash.

項目需求:項目需要統計每個使用者(大概每天1w人登錄操作)的操作內容,操作了多少次(總共400個接口)。每天最多400w條數據。

方案:1.採用HashMap來存數據,數據內存太大。系統吃不消

        2.接入監控平臺,添加埋點即可。但是花費太大,每年11w

        3.接入redis。費用大減

具體操作: 1.引入jar 由於項目比較老,用的jdk6,並且內網限制。採用了jedis 2.1.0 和commons-pool 1.5.6

                   jedis用於操作redis,常見的set,get,expire,其他對象的操作等。

                  現在基本使用jedis 2.9.0+ 和commons2-pool 2.4.2+ 並且會接入Spring(封裝了一層)

                2.具體代碼邏輯,2.1 寫好redis工具類,這個可以百度。然後注意連接池的配置。  JedisPoolConfig的配置。

                                            2.2 寫個攔截器。對所有的請求,獲取用戶編碼 a,請求url b,當天時間 c. 以 a_b_c爲key,value放次                                                       數。第一次爲1,然後 2. 可以用到redis的incrby方法。因爲有了當前日期,並且我們打算存兩天                                                      的數據,所有得設 置有效期,不然以後垃圾數據就爆了。設置有效期爲兩天。

                                            2.3 寫個定時任務,每天凌晨將緩存的數據讀取出來,批量插入到oracle中,然後定期進行歸檔(將次                                                    數進行彙總,相同的key的數據累加,只保留前7天的數據和月份數據,後期歸檔到年數據中)

                             至此就完成了:          後面再根據oracle中的數據查詢即可。

 

出現的問題:

1.JedisPoolConfig 的問題,很多參數只是百度然後沒有認真思考。

   1.1 whenExhaustedAction(當取不到jedis鏈接時的操作):默認是 阻塞等待。千萬不要這樣,這樣會導致線上大量線程阻塞。                                                          最好是設置爲0.即超過等待時間還沒獲取到就拋異常。這個問題導致線上緊張的一批。

                                                    同時設置下max_wait的值。比如 3000,單位 毫秒

  1.2. testOnBorrow 和testOnReturn 即 測試 取鏈接和還鏈接 是測試 鏈接時ok的,但是我出現了問題,並設置了後並沒有起作                                        用。

 

2. 異常  JedisConnectionException

    正常測試開發環境都沒有問題,一旦併發,就出現問題了。。。。

  後來經過不斷的找問題,終於發現是對於異常處理的問題:

   之前 的代碼:

      long result=0;

    Jedis jedis=getJedis();

 try{

    result=jedis.incrBy(key,count)// key 爲a_b_c 字符串,count 爲1,累加1

    if(result==1) jedis.expire(key,expire_time)//只在第一次設置過期時間

}catch(Exception e){

log.error(......)

}finally{

   jedisPool.returnResource(jedis);//釋放資源,將連接放回連接池

}

上述代碼好像沒有問題,可以一旦並發起來,jedis.incrBy 這個代碼會有異常,

由於異常後沒有將異常鏈接銷燬掉,導致異常鏈接一直被用,從而一直報有錯誤信息。

所以在Catch那裏需要有針對性的catch異常。

catch(JedisConnectionException e){

      jedisPool.returnBrokenResource(jedis);//銷燬異常鏈接

}

 

 

異常二:

   是由於自己不小心造成的,後果非常嚴重。我在取鏈接的方法中的finally中添加了returnResource方法,在實際操作鏈接的地方,比如incrby(),get(),set()方法的finally也添加了returnResource方法。導致連接池中的一個參數 numActive爲負數。應爲每拿了一個鏈接,我返回的兩次,導致現存的鏈接時負數。而 whenExhaustedAction 這參數的判斷條件是當前鏈接大於最大鏈接時纔會起作用,所以whenExhaustedAction 這個參數不起作用。可想而知。最後都阻塞了。

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章