大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節(jié)點(diǎn)LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 hot資訊 實(shí)現(xiàn)Redis分布式存儲

實(shí)現(xiàn)Redis分布式存儲

更新時間:2022-02-15 10:12:24 來源:動力節(jié)點(diǎn) 瀏覽1510次

Memcache是在服務(wù)端實(shí)現(xiàn)分片的分布式的緩存系統(tǒng),而Redis是基于Master-Slave(主從),如果想把Reids做成分布式緩存,就要多做幾套Master-Slave,每套Master-Slave完成各自的容災(zāi)處理,另外,Redis只能在客戶端完成分片。

Redis有中語言的客戶端,其中基于Java語言的客戶端叫做Jedis,Jedis客戶端已經(jīng)為Redis實(shí)現(xiàn)了分布式存儲。下面分別介紹了Jedis分布式存儲的簡單使用以及Spring與Jedis的整合使用。

1.Jedis分布式存儲舉例

package com.ghs.test;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
public class TestShardJedis {
    ShardedJedisPool pool = null;
    ShardedJedis jedis = null;
    @Before
    public void setup(){
        JedisShardInfo shardInfo1 = new JedisShardInfo("192.168.1.108");
        JedisShardInfo shardInfo2 = new JedisShardInfo("...");
        List<JedisShardInfo> shardInfos = new ArrayList<JedisShardInfo>();
        shardInfos.add(shardInfo1);
        shardInfos.add(shardInfo2);
        pool = new ShardedJedisPool(new GenericObjectPoolConfig(), shardInfos);
    }
    @Test
    public void testShard(){
        jedis = pool.getResource();
        //CRUD
        jedis.set("name", "zhangsan");
        System.out.println(jedis.get("name"));
        jedis.del("name");
        //釋放對象
        pool.returnResource(jedis);
    }
}

2.Spring+Jedis實(shí)現(xiàn)分布式存儲

spring中的配置:

這里只是把示例一中JedisShardInfo和ShardJedisPool的示例交給Sping容器管理。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-4.1.xsd">
    <context:property-placeholder location="classpath:redis.properties" />
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxActive" value="${redis.pool.maxActive}" />
        <property name="maxIdle" value="${redis.pool.maxIdle}" />
        <property name="maxWait" value="${redis.pool.maxWait}" />
        <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
    </bean>
    <bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool">
        <constructor-arg index="0" ref="jedisPoolConfig" />
        <constructor-arg index="1">
            <list>
                <bean class="redis.clients.jedis.JedisShardInfo">
                    <constructor-arg index="0" value="${redis1.ip}" />
                    <constructor-arg index="1" value="${redis.port}"
                        type="int" />
                </bean>
                <bean class="redis.clients.jedis.JedisShardInfo">
                    <constructor-arg index="0" value="${redis2.ip}" />
                    <constructor-arg index="1" value="${redis.port}" type="int" />
                </bean>
            </list>
        </constructor-arg>
    </bean>
</beans>

對訪問操作進(jìn)行封裝:

package com.ghs.test;
import java.util.List;
import javax.annotation.Resource;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
public class SpringRedisClient implements IRedisClient{
    @Resource(name="shardedJedisPool")
    private ShardedJedisPool shardedJedisPool;
    private ShardedJedis getResource(){
        return shardedJedisPool.getResource();
    }
    @Override
    public String set(String key,String value){
        return getResource().set(key,value);
    }
    @Override
    public String get(String key){
        return getResource().get(key);
    }
    @Override
    public Long del(String key) {
        return getResource().del(key);
    }
    @Override
    public Long lpush(String key, String... strings) {
        return getResource().lpush(key, strings);
    }
    @Override
    public Long rpush(String key, String... strings) {
        return getResource().rpush(key, strings);
    }
    @Override
    public List<String> lrange(String key, int start, int end){
        return getResource().lrange(key, start,end);
    }
    //…………………………
}

3.Jedis分布式存儲實(shí)現(xiàn)原理

(1)JedisShardInfo類

這個類封裝了Redis主機(jī)的一些基本信息:

  private int timeout;
  private String host;
  private int port;
  private String password = null;
  private String name = null;

最重要的是它的父類中有一個weight字段,作為本Redis服務(wù)器的權(quán)值。

這個類還有一個繼承自父類的方法createResource(),用來生成這個Redis服務(wù)器對應(yīng)的Jedis對象,即往Redis服務(wù)器存取數(shù)據(jù)的對象。

(2)Sharded類

對一致性哈希算法熟悉以后,對Sharded類的理解就不難了,通過這個類來為每個分片創(chuàng)建虛擬節(jié)點(diǎn),為每次操作獲取分片。

Sharded中的三個字段,nodes是用來模擬一致性哈希算法用的;algo是用來對字符串產(chǎn)生哈希值的hash函數(shù),這里默認(rèn)的是murmurhash,這個算法的隨機(jī)分布特征表現(xiàn)比較好;resources這個map是用來存儲JedisShardInfo與其對應(yīng)的Jedis類之間的映射關(guān)系。

  public static final int DEFAULT_WEIGHT = 1;
  private TreeMap<Long, S> nodes;//機(jī)器節(jié)點(diǎn)
  private final Hashing algo;
  private final Map<ShardInfo<R>, R> resources = new LinkedHashMap<ShardInfo<R>, R>();//每個機(jī)器節(jié)點(diǎn)關(guān)聯(lián)的虛擬節(jié)點(diǎn)

下面我們來看看初始化操作和獲取分片的操作:

  //初始化操作,為每個主機(jī)管理虛擬節(jié)點(diǎn)
  private void initialize(List<S> shards) {
    nodes = new TreeMap<Long, S>();
    for (int i = 0; i != shards.size(); ++i) {
      final S shardInfo = shards.get(i);
      if (shardInfo.getName() == null) for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
        nodes.put(this.algo.hash("SHARD-" + i + "-NODE-" + n), shardInfo);
      }
      else for (int n = 0; n < 160 * shardInfo.getWeight(); n++) {
        nodes.put(this.algo.hash(shardInfo.getName() + "*" + shardInfo.getWeight() + n), shardInfo);
      }
      resources.put(shardInfo, shardInfo.createResource());
    }
  }

在for循環(huán)中,遍歷主機(jī)列表(shards.get(i)),之后對每個主機(jī)按照單權(quán)重160的比例計算shard值,將shard值和主機(jī)信息(shardInfo)放到nodes中,將主機(jī)信息(shardInfo)和其對應(yīng)的鏈接資源(Jedis)映射放入到resources中。

Weight是權(quán)重,用于調(diào)節(jié)單個主機(jī)被映射值個數(shù),如果weight為1,那么當(dāng)前主機(jī)將被映射為160個值,weight為2,當(dāng)前主機(jī)將被映射為320個值,因此weight為2的節(jié)點(diǎn)被訪問到的概率就會高一些。

遍歷list中的每一個shardInfo,將其權(quán)重weight*160生成n,然后用名字或者編號來生成n個哈希值(這個是為了保證哈希算法的平衡性而生成的虛擬節(jié)點(diǎn)),然后將其和本shardInfo的對應(yīng)關(guān)系存儲到treemap里面(這是在模擬一致性哈希算法中將虛擬節(jié)點(diǎn)映射到環(huán)上的操作),最后將shardInfo與對應(yīng)的Jedis類的映射關(guān)系存儲到resources里面。

   //獲取分片
    public S getShardInfo(byte[] key) {
    SortedMap<Long, S> tail = nodes.tailMap(algo.hash(key));
    if (tail.isEmpty()) {
      return nodes.get(nodes.firstKey());
    }
    return tail.get(tail.firstKey());
  }
  public S getShardInfo(String key) {
    return getShardInfo(SafeEncoder.encode(getKeyTag(key)));
  }

首先根據(jù)傳入的key按照hash算法(默認(rèn)為murmurhash)取得其value,然后用這個value到treemap中找key大于前面生成的value值的第一個鍵值對,這個鍵值對的value既是對應(yīng)的shardedInfo。如果您想了解更多相關(guān)知識,可以關(guān)注一下動力節(jié)點(diǎn)的Java在線學(xué)習(xí),里面的課程內(nèi)容更加豐富,希望對大家能夠有所幫助。

提交申請后,顧問老師會電話與您溝通安排學(xué)習(xí)

免費(fèi)課程推薦 >>
技術(shù)文檔推薦 >>
主站蜘蛛池模板: 久久精品亚洲热综合一本奇米 | 久草国产在线播放 | 国产一区二区三区久久 | 美女视频黄视大全视频免费网址 | 久久这里只精品国产99热8 | 麻豆一区二区三区在线观看 | 亚洲精品久久久久久久777 | 97视频免费 | 日本欧美小视频 | 久久国产高清一区二区三区 | 午夜视频精品 | 99热这里只有成人精品国产 | 女人18毛片a级毛片免费看一 | 新久草视频 | 老子午夜精品我不卡影院 | 日本一级高清不卡视频在线 | 国产伦精品一区二区三区免费迷 | 国产伦精品一区二区 | 456性欧美欧美在线视频 | 国产91在线看| 日本aⅴ永久免费网站www | 国产成人在线播放视频 | 亚洲欧美日韩国产专区一区 | 久久国产视屏 | 久久久www成人免费精品 | 咪咪色在线视频 | 99色在线播放 | 欧美日韩顶级毛片www免费看 | 久久综合久久久久 | 国产青青久久 | 国产精品剧情原创麻豆国产 | 亚洲不卡一区二区三区在线 | 国产成人18黄网站麻豆 | 桃子在线观看 | 99精品视频在线 | 国产成年女一区二区三区 | 欧美日韩中文字幕久久伊人 | 99久久99久久久精品齐齐鬼色 | 97视频在线观看免费播放 | 国产精品午夜高清在线观看 | 99精品久久久久久久婷婷 |