日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > 互聯(lián)網(wǎng) > Redis集群方案及實現(xiàn)

Redis集群方案及實現(xiàn)

來源:程序員人生   發(fā)布時間:2014-09-02 23:37:00 閱讀次數(shù):3696次

之前做了一個Redis的集群方案,跑了小半年,線上運行的很穩(wěn)定
差不多可以跟大家分享下經(jīng)驗,前面寫了一篇文章 數(shù)據(jù)在線服務(wù)的一些探索經(jīng)驗,可以做為背景閱讀

應(yīng)用

我們的Redis集群主要承擔(dān)了以下服務(wù):
1. 實時推薦
2. 用戶畫像
3. 誠信分值服務(wù)

集群狀況

集群峰值QPS 1W左右,RW響應(yīng)時間999線在1ms左右
整個集群:
1. Redis節(jié)點: 8臺物理機(jī);每臺128G內(nèi)存;每臺機(jī)器上8個instance
2. Sentienl:3臺虛擬機(jī)

集群方案


Redis Node由一組Redis Instance組成,一組Redis Instatnce可以有一個Master Instance,多個Slave Instance

Redis官方的cluster還在beta版本,參看Redis cluster tutorial
在做調(diào)研的時候,曾經(jīng)特別關(guān)注過KeepAlived+VIP 和 Twemproxy
不過最后還是決定基于Redis Sentinel實現(xiàn)一套,整個項目大概在1人/1個半月

整體設(shè)計

1. 數(shù)據(jù)Hash分布在不同的Redis Instatnce上
1. M/S的切換采用Sentinel
2. 寫:只會寫master Instance,從sentinel獲取當(dāng)前的master Instane
3. 讀:從Redis Node中基于權(quán)重選取一個Redis Instance讀取,失敗/超時則輪詢其他Instance
4. 通過RPC服務(wù)訪問,RPC server端封裝了Redis客戶端,客戶端基于jedis開發(fā)
5. 批量寫/刪除:不保證事務(wù)

RedisKey

public class RedisKey implements Serializable{ private static final long serialVersionUID = 1L; //每個業(yè)務(wù)不同的family private String family; private String key; ...... //物理保存在Redis上的key為經(jīng)過MurmurHash之后的值 private String makeRedisHashKey(){ return String.valueOf(MurmurHash.hash64(makeRedisKeyString())); } //ReidsKey由family.key組成 private String makeRedisKeyString(){ return family +":"+ key; } //返回用戶的經(jīng)過Hash之后RedisKey public String getRedisKey(){ return makeRedisHashKey(); } ..... }


Family的存在時為了避免多個業(yè)務(wù)key沖突,給每個業(yè)務(wù)定義自己獨立的Faimily
出于性能考慮,參考Redis存儲設(shè)計,實際保存在Redis上的key為經(jīng)過hash之后的值

接口

目前支持的接口包括:
public interface RedisUseInterface{ /** * 通過RedisKey獲取value * * @param redisKey * redis中的key * @return * 成功返回value,查詢不到返回NULL */ public String get(final RedisKey redisKey) throws Exception; /** * 插入<k,v>數(shù)據(jù)到Redis * * @param redisKey * the redis key * @param value * the redis value * @return * 成功返回"OK",插入失敗返回NULL */ public String set(final RedisKey redisKey, final String value) throws Exception; /** * 批量寫入數(shù)據(jù)到Redis * * @param redisKeys * the redis key list * @param values * the redis value list * @return * 成功返回"OK",插入失敗返回NULL */ public String mset(final ArrayList<RedisKey> redisKeys, final ArrayList<String> values) throws Exception; /** * 從Redis中刪除一條數(shù)據(jù) * * @param redisKey * the redis key * @return * an integer greater than 0 if one or more keys were removed 0 if none of the specified key existed */ public Long del(RedisKey redisKey) throws Exception; /** * 從Redis中批量刪除數(shù)據(jù) * * @param redisKey * the redis key * @return * 返回成功刪除的數(shù)據(jù)條數(shù) */ public Long del(ArrayList<RedisKey> redisKeys) throws Exception; /** * 插入<k,v>數(shù)據(jù)到Redis * * @param redisKey * the redis key * @param value * the redis value * @return * 成功返回"OK",插入失敗返回NULL */ public String setByte(final RedisKey redisKey, final byte[] value) throws Exception; /** * 插入<k,v>數(shù)據(jù)到Redis * * @param redisKey * the redis key * @param value * the redis value * @return * 成功返回"OK",插入失敗返回NULL */ public String setByte(final String redisKey, final byte[] value) throws Exception; /** * 通過RedisKey獲取value * * @param redisKey * redis中的key * @return * 成功返回value,查詢不到返回NULL */ public byte[] getByte(final RedisKey redisKey) throws Exception; /** * 在指定key上設(shè)置超時時間 * * @param redisKey * the redis key * @param seconds * the expire seconds * @return * 1:success, 0:failed */ public Long expire(RedisKey redisKey, int seconds) throws Exception; }

寫Redis流程

1. 計算Redis Key Hash值
2. 根據(jù)Hash值獲取Redis Node編號
3. 從sentinel獲取Redis Node的Master
4.  寫數(shù)據(jù)到Redis
//獲取寫哪個Redis Node int slot = getSlot(keyHash); RedisDataNode redisNode = rdList.get(slot); //寫Master JedisSentinelPool jp = redisNode.getSentinelPool(); Jedis je = null; boolean success = true; try { je = jp.getResource(); return je.set(key, value); } catch (Exception e) { log.error("Maybe master is down", e); e.printStackTrace(); success = false; if (je != null) jp.returnBrokenResource(je); throw e; } finally { if (success && je != null) { jp.returnResource(je); } }



讀流程

1. 計算Redis Key Hash值
2. 根據(jù)Hash值獲取Redis Node編號
3. 根據(jù)權(quán)重選取一個Redis Instatnce
4.  輪詢讀
//獲取讀哪個Redis Node int slot = getSlot(keyHash); RedisDataNode redisNode = rdList.get(slot); //根據(jù)權(quán)重選取一個工作Instatnce int rn = redisNode.getWorkInstance(); //輪詢 int cursor = rn; do { try { JedisPool jp = redisNode.getInstance(cursor).getJp(); return getImpl(jp, key); } catch (Exception e) { log.error("Maybe a redis instance is down, slot : [" + slot + "]" + e); e.printStackTrace(); cursor = (cursor + 1) % redisNode.getInstanceCount(); if(cursor == rn){ throw e; } } } while (cursor != rn);



權(quán)重計算

初始化的時候,會給每個Redis Instatnce賦一個權(quán)重值weight
根據(jù)權(quán)重獲取Redis Instance的代碼:
public int getWorkInstance() { //沒有定義weight,則完全隨機(jī)選取一個redis instance if(maxWeight == 0){ return (int) (Math.random() * RANDOM_SIZE % redisInstanceList.size()); } //獲取隨機(jī)數(shù) int rand = (int) (Math.random() * RANDOM_SIZE % maxWeight); int sum = 0; //選取Redis Instance for (int i = 0; i < redisInstanceList.size(); i++) { sum += redisInstanceList.get(i).getWeight(); if (rand < sum) { return i; } } return 0; }



生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 高清性爱视频 | 久久这里只有精品6 | 黄色永久 | 国产激情视频在线 | 精品无码久久久久久国产 | 女人久久久 | 综合久久一区 | 欧美精品一区二区三区四区 | 日韩精品久久久久久 | 亚洲国产精品99久久久久久久久 | 久久久久人 | 国产精品久久久久婷婷二区次 | 亚洲成人精品久久久 | 国产日韩在线视频 | 中国av免费在线观看 | 天堂av.com | 午夜三区 | 中文字幕综合在线 | 欧美日韩亚洲一区二区三区 | 亚洲欧洲视频在线观看 | 一区二区网站 | www.欧美 | √最新版天堂资源网在线 | 久久久亚洲国产精品麻豆综合天堂 | 在线日韩一区 | 国产精品久久久久婷婷二区次 | 日韩a级毛片免费观看久久 精品一区二区在线播放 | 91av官网| 国产精品久久久久久久久潘金莲 | 快播久久| 精品久久久久久久久久岛国gif | 成人中文字幕在线观看 | 四虎影院最新地址 | 欧美黑人性猛交 | 黄色av网 | 亚洲视频在线一区二区 | 日韩午夜视频在线观看 | 99久久99久久精品国产片果冻 | 99一区二区 | 亚洲精品电影在线观看 | 国产在线国偷精品免费看 |