首页 养生问答 疾病百科 养生资讯 女性养生 男性养生

Redis怎么做集群

发布网友 发布时间:2022-04-22 07:59

我来回答

2个回答

懂视网 时间:2022-04-09 05:55

1、配置redis集群

<?xml version="1.0" encoding="UTF-8"?>
<redisCluster>
	<!--userRoute -->
	<clusterGroup name="userRoute" selectdb="1">
		<server host="10.177.129.16" port="6379"></server>
		<server host="10.177.129.15" port="6379"></server>
	</clusterGroup>
	<!--sessionRoute -->
	<clusterGroup name="sessionRoute" selectdb="2">
		<server host="10.177.129.16" port="6379"></server>
		<server host="10.177.129.15" port="6379"></server>
	</clusterGroup>
	<!--publicData -->
	<clusterGroup name="publicData">
		<server host="10.177.129.16" port="6379"></server>
		<server host="10.177.129.15" port="6379"></server>
	</clusterGroup>
</redisCluster>

2、创建redis连接属性实体类

package com.isoftstone.cms.syscore.pojo;

/**
 * redis连接属性
 * @author xiakai
 *
 */
public class RedisCluster 
{
	private String selectdb;
	private String hostIp;
	private String	port;
	
	
	public String getSelectdb() {
		return selectdb;
	}
	public void setSelectdb(String selectdb) {
		this.selectdb = selectdb;
	}
	public String getHostIp() {
		return hostIp;
	}
	public void setHostIp(String hostIp) {
		this.hostIp = hostIp;
	}
	public String getPort() {
		return port;
	}
	public void setPort(String port) {
		this.port = port;
	}

	
	
	

}

3、解析redis集群配置

package com.iss.itreasury.test.jedis;



import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.core.io.ClassPathResource; 
import org.springframework.core.io.Resource; 
import org.springframework.core.io.support.EncodedResource;




/**
 * 解析redis集群配置
 * @author xiakai
 *
 */
public class RedisConfig {
	
public static Map<String,List<RedisCluster>> redisGroupMap = null;

//有参构造函数
public RedisConfig()
{
	
}


//获取所有clusterGroup组的键值对
public static Map<String,List<RedisCluster>> getRedisGroupMap(){
	//读取xml文件
	Document document=readXmlFile();
	//获得clusterGroup节点的key 和 list
	if(redisGroupMap == null)
	{
		redisGroupMap=getMapByItemsGroup(document);
	}
	
	return redisGroupMap;
}


//读取redisConfig配置文件
private static Document readXmlFile(){
 //创建读入对象
 SAXReader reader = new SAXReader();
 //创建document实例
 Document doc=null;
 try {
 //从类路径下加载文件redisConfig.xml	
 Resource resource = new ClassPathResource("redisClusterConfig.xml"); 
 //指定文件资源对应的编码格式(UTF-8),这样才能正确读取文件的内容,而不会出现乱码
 EncodedResource encodeResource = new EncodedResource(resource,"UTF-8"); 
 doc = reader.read(encodeResource.getReader());
	} 
 catch (IOException e) {
 	System.out.println("无法读取系统配置文件redisConfig.xml,可能该文件不存在");
		
	} catch (DocumentException e) {
		System.out.println("解析redisConfig.xml文件出现异常");
		
	}
	return doc;

}

//读取xml节点,返回节点为redisGroup的Map
private static Map<String,List<RedisCluster>> getMapByItemsGroup(Document document){
	Map<String,List<RedisCluster>> itemmap=new HashMap<String,List<RedisCluster>>();
	try{
		//获得根节点
		Element root=document.getRootElement();
		//获得根节点下所有子节点clusterGroup的list
		List itemsList=root.selectNodes("./clusterGroup");
		for(int i=0;i<itemsList.size();i++){
		//获得节点Items
		Element items=(Element)itemsList.get(i);
		String groupName=items.attribute("name").getText();
		String selectdb = items.attribute("selectdb")==null?"":items.attribute("selectdb").getText();
//		if(groupName!=null&&groupName.equals(this.getGroupName())){
			 //获得clusterGroup下所有子节点service的list
			 List itemList=items.elements();
			 //获得service节点的值
			 List<RedisCluster> redisClusterList = getItemList(itemList,selectdb);
			 
			 itemmap.put(groupName, redisClusterList);
//		}
	 
		}
	}
	catch(Exception e){
		
	}
	return itemmap;
}


//获得所有Item下节点的redis服务节点
private static List<RedisCluster> getItemList(List itemList,String selectdb){
	
	List<RedisCluster> redisClusterList = new ArrayList<RedisCluster>();
	for(int i=0;i<itemList.size();i++){
		//获得节点server
		Element item=(Element)itemList.get(i);
		String hostIp = item.attribute("host").getText();
		String port = item.attribute("port").getText();
		
		RedisCluster redisCluster =new RedisCluster();
		redisCluster.setHostIp(hostIp);
		redisCluster.setPort(port);
		redisCluster.setSelectdb(selectdb);
		
		redisClusterList.add(redisCluster);
 }
	return redisClusterList;
	
	
}

public static void main(String[] args) {
	getRedisGroupMap();
	//JedisUtil.insertPublicDataObject("user1", "张三", JedisUtil.ONLINE_USER);
	//JedisUtil.insertPublicDataObject("user2", "李四", JedisUtil.ONLINE_USER);
	//JedisUtil.insertPublicDataObject("user3", "王五", JedisUtil.ONLINE_USER);

	 Set s = JedisUtil.getAllSet(JedisUtil.ONLINE_USER);
	 Iterator it = s.iterator();	 
	 while (it.hasNext()) {
	 String key = (String) it.next();
	 String value = JedisUtil.getString(key,JedisUtil.ONLINE_USER);
	 System.out.println(key + value);
	 }
	String test = JedisUtil.getString("user1",JedisUtil.ONLINE_USER);
	System.out.println(test);
	
}
}


4、操作redis数据库的工具类


package com.isoftstone.cms.syscore.utils;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Set;
import java.util.zip.CRC32;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.exceptions.JedisConnectionException;

import com.google.gson.Gson;
import com.isoftstone.cms.syscore.pojo.RedisCluster;

public class JedisUtil {
	
	// 数据库
	public static final String STORE_LOGINUSER = "4";// 商户登陆用户
	public static final String STORE_INFO = "5";// 商户状态 商户购买服务有效期
	public static final String CHECK_CODE = "6";// 验证码
	public static final String MENU = "7";// 全部菜单
	public static final String SERVICE = "8";// 服务收费信息
	public static final String STORE_LOGINKEY = "9";// 初始化登录公钥 私钥对
	// 固定key
	public static final String ALL_MENU_KEY = "ALL_MENU_KEY";
	public static final String BUY_SERVICE_KEY = "BUY_SERVICE_KEY";// 服务收费购买key
	public static final String ALL_SERVICE_KEY = "ALL_SERVICE_KEY";//所有服务
	public static final String MENU_AUTHORITY = "MENU_AUTHORITY";// 菜单权限
	public static final String STORE_MENU_KEY = "STORE_MENU_KEY";// 需要商户分配的业务菜单
	public static final String STORE_SERVICE_KEY = "STORE_SERVICE_KEY";// 商户收费key
	public static final String SYSTE_MENU_KEY = "SYSTE_MENU_KEY";// 系统管理菜单key

	// jedis服务组业务类型
	public static final String CONT_CLUSTERNAME_PUBLICDATA = "publicData";
	public static final String CONT_CLUSTERNAME_SESSIONROUTE = "sessionRoute";
	public static final String CONT_CLUSTERNAME_USERROUTE = "userRoute";
	
	// 操作方式 0 插入 1获取 2 删除
	public static final long INSERT_OPERATION = 0;
	public static final long GET_OPERATION = 1;
	public static final long DELETE_OPERATION = 2;

	// 验证码过期秒数
	public static final int CHECKCODE_EXPIRESECONDS = 5*60;
	// session过期秒数
	public static final int EXPIRESECONDS = 30 * 60;

	private static void closeJedis(Jedis jedis) {
		try {
			jedis.quit();
		} catch (JedisConnectionException e) {
			e.printStackTrace();
		}
		jedis.disconnect();
	}
	
	/**
	 * 根据Key获取字符串
	 *
	 * @param key
	 * @param jedisGroup
	 */
	public static String getString(String key, String selectdb) {
		Jedis jedis = getPublicDataJedis(key, GET_OPERATION, selectdb);
		return jedis.get(key);
	}
	
	/**
	 * 获取所有数据set
	 * @param selectdb
	 * @return
	 */
	public static Set getAllSet(String selectdb) {
		Jedis jedis = getDataJedis(GET_OPERATION, selectdb);
		return jedis.keys("*");
	}
	
	/**
	 * 默认取配置文件的第一个数据库
	 * @param operation
	 * @param selectdb
	 * @return
	 */
	private static Jedis getDataJedis(long operation, String selectdb) {
		if (RedisConfig.redisGroupMap == null) {
			RedisConfig.redisGroupMap = RedisConfig.getRedisGroupMap();
		}
		List<RedisCluster> clustersList = RedisConfig.redisGroupMap.get(CONT_CLUSTERNAME_PUBLICDATA);

		int clusterNo = 0;//默认存到第一个

		RedisCluster cluster = clustersList.get(clusterNo);
		Jedis jedis = new Jedis(cluster.getHostIp(), Integer.valueOf(cluster.getPort()));
		jedis.select(Integer.valueOf(selectdb));
		return jedis;
	}


	/**
	 * 删除数据
	 *
	 * @param key
	 * @param jedisGroup
	 */
	public static void deleteObject(String key, String jedisGroup) {
		Jedis jedis = getJedis(key, jedisGroup, DELETE_OPERATION);
		jedis.del(key);
		closeJedis(jedis);
	}

	/**
	 * 删除公共数据
	 *
	 * @param key
	 * @param objClass
	 * @param selectdb
	 */
	public static void deletePublicDataObject(String key, String selectdb) {
		Jedis jedis = getPublicDataJedis(key, DELETE_OPERATION, selectdb);
		jedis.del(key);
		closeJedis(jedis);
	}

	/**
	 * 获取jedis的库实例
	 *
	 * @param key
	 * @param jedisGroup
	 * @param operation
	 * @return
	 */
	private static Jedis getJedis(String key, String jedisGroup, long operation) {
		if (RedisConfig.redisGroupMap == null) {
			RedisConfig.redisGroupMap = RedisConfig.getRedisGroupMap();
		}
		List<RedisCluster> clustersList = RedisConfig.redisGroupMap.get(jedisGroup);
		int arrayLength = clustersList.size();
		// 根据key值算出该信息应该存入到那个
		int clusterNo = getRedisNo(key, arrayLength);

		RedisCluster cluster = clustersList.get(clusterNo);
		Jedis jedis = new Jedis(cluster.getHostIp(), Integer.valueOf(cluster.getPort()));
		jedis.select(Integer.valueOf(cluster.getSelectdb()));
		return jedis;
	}

	/**
	 * redis key值获取对象
	 *
	 * @param key
	 * @param objClass
	 * @param jedisGroup
	 * @return
	 */
	public static Object getObject(String key, Class objClass, String jedisGroup) {
		Jedis jedis = getJedis(key, jedisGroup, GET_OPERATION);

		String sObj = jedis.get(key);
		closeJedis(jedis);
		Gson gson = new Gson();
		return gson.fromJson(sObj, objClass);

	}

	/**
	 * 获取公共数据jedis的库实例
	 *
	 * @param key
	 * @param jedisGroup
	 * @param operation
	 * @return
	 */
	private static Jedis getPublicDataJedis(String key, long operation, String selectdb) {
		if (RedisConfig.redisGroupMap == null) {
			RedisConfig.redisGroupMap = RedisConfig.getRedisGroupMap();
		}
		List<RedisCluster> clustersList = RedisConfig.redisGroupMap.get(CONT_CLUSTERNAME_PUBLICDATA);
		int arrayLength = clustersList.size();
		// 根据key值算出该信息应该存入到那个
		int clusterNo = getRedisNo(key, arrayLength);

		RedisCluster cluster = clustersList.get(clusterNo);
		Jedis jedis = new Jedis(cluster.getHostIp(), Integer.valueOf(cluster.getPort()));
		jedis.select(Integer.valueOf(selectdb));
		return jedis;
	}

	/**
	 * publicdata redis key值获取对象
	 *
	 * @param key
	 * @param objClass
	 * @param jedisGroup
	 * @return
	 */
	public static Object getPublicDataObject(String key, Class objClass, String selectdb) {
		Jedis jedis = getPublicDataJedis(key, GET_OPERATION, selectdb);

		String sObj = jedis.get(key);
		closeJedis(jedis);
		Gson gson = new Gson();
		return gson.fromJson(sObj, objClass);

	}

	/**
	 * publicdata redis key值获取对象 List<Entity>
	 *
	 * @param key
	 * @param objClass
	 * @param jedisGroup
	 * @return
	 */
	public static Object getPublicDataObjectByType(String key, Type type, String selectdb) {
		Jedis jedis = getPublicDataJedis(key, GET_OPERATION, selectdb);

		String sObj = jedis.get(key);
		closeJedis(jedis);
		Gson gson = new Gson();
		return gson.fromJson(sObj, type);
	}

	/**
	 * 获取redis服务器库编号
	 *
	 * @param hashKey
	 * @return
	 */
	public static int getRedisNo(String key, int arraySize) {
		long hashKey = hash(key);
		int redisNo = (int) (hashKey % arraySize);
		return redisNo;
	}

	/**
	 * 根据key值算出hash值
	 *
	 * @param k
	 * @return
	 */
	public static long hash(String k) {
		CRC32 crc32 = new CRC32();
		crc32.update(k.getBytes());
		return crc32.getValue();
	}

	/**
	 * redis 根据key值将对象插入到不同的库中
	 *
	 * @param key
	 * @param insertObj
	 * @param jedisGroup
	 */
	public static void insertObject(String key, Object insertObj, String jedisGroup) {

		Jedis jedis = getJedis(key, jedisGroup, INSERT_OPERATION);
		Gson gson = new Gson();
		jedis.set(key, gson.toJson(insertObj));
		closeJedis(jedis);
	}

	/**
	 * redis 根据key值将对象插入到不同的库中
	 *
	 * @param key
	 * @param insertObj
	 * @param jedisGroup
	 * @param expire
	 */
	public static void insertObject(String key, Object insertObj, String jedisGroup, int expireSeconds) {

		Jedis jedis = getJedis(key, jedisGroup, INSERT_OPERATION);
		Gson gson = new Gson();
		jedis.setex(key, expireSeconds, gson.toJson(insertObj));
		closeJedis(jedis);
	}

	/**
	 * publicdata redis 根据key值将对象插入到不同的库中
	 *
	 * @param key
	 * @param insertObj
	 * @param jedisGroup
	 */
	public static void insertPublicDataObject(String key, Object insertObj, String selectdb) {

		Jedis jedis = getPublicDataJedis(key, INSERT_OPERATION, selectdb);
		Gson gson = new Gson();
		jedis.set(key, gson.toJson(insertObj));
		closeJedis(jedis);
	}

	/**
	 * publicdata redis 根据key值将对象插入到不同的库中,
	 *
	 * @param key
	 * @param insertObj
	 * @param jedisGroup
	 * @param expireSeconds
	 */
	public static void insertPublicDataObject(String key, Object insertObj, String selectdb, int expireSeconds) {
		Jedis jedis = getPublicDataJedis(key, INSERT_OPERATION, selectdb);
		Gson gson = new Gson();
		jedis.setex(key, expireSeconds, gson.toJson(insertObj));
		closeJedis(jedis);
	}

	/**
	 * 更新redis中key的超时时间
	 *
	 * @param key
	 * @param jedisGroup
	 * @param expireSeconds
	 */
	public static void resetExpireSeconds(String key, String jedisGroup, int expireSeconds) {
		Jedis jedis = getJedis(key, jedisGroup, GET_OPERATION);
		jedis.expire(key, expireSeconds);
		closeJedis(jedis);
	}

}


5、所需jar包

技术分享

java操作redis数据库实例(redis集群)

标签:

热心网友 时间:2022-04-09 03:03

为什么集群?

通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取。Redis是一个很好的Cache工具。大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿,在这种情况下,如何正确架构Redis呢?

首先,无论我们是使用自己的物理主机,还是使用云服务主机,内存资源往往是有*的,scale up不是一个好办法,我们需要scale out横向可伸缩扩展,这需要由多台主机协同提供服务,即分布式多个Redis实例协同运行。

其次,目前硬件资源成本降低,多核CPU,几十G内存的主机很普遍,对于主进程是单线程工作的Redis,只运行一个实例就显得有些浪费。同时,管理一个巨大内存不如管理相对较小的内存高效。因此,实际使用中,通常一台机器上同时跑多个Redis实例。

方案

1.Redis官方集群方案 Redis Cluster

Redis Cluster是一种服务器Sharding技术,3.0版本开始正式提供。

Redis Cluster中,Sharding采用slot(槽)的概念,一共分成16384个槽,这有点儿类pre sharding思路。对于每个进入Redis的键值对,根据key进行散列,分配到这16384个slot中的某一个中。使用的hash算法也比较简单,就是CRC16后16384取模。

Redis集群中的每个node(节点)负责分摊这16384个slot中的一部分,也就是说,每个slot都对应一个node负责处理。当动态添加或减少node节点时,需要将16384个槽做个再分配,槽中的键值也要迁移。当然,这一过程,在目前实现中,还处于半自动状态,需要人工介入。

Redis集群,要保证16384个槽对应的node都正常工作,如果某个node发生故障,那它负责的slots也就失效,整个集群将不能工作。

为了增加集群的可访问性,官方推荐的方案是将node配置成主从结构,即一个master主节点,挂n个slave从节点。这时,如果主节点失效,Redis Cluster会根据选举算法从slave节点中选择一个上升为主节点,整个集群继续对外提供服务。这非常类似前篇文章提到的Redis Sharding场景下服务器节点通过Sentinel监控架构成主从结构,只是Redis Cluster本身提供了故障转移容错的能力。

Redis Cluster的新节点识别能力、故障判断及故障转移能力是通过集群中的每个node都在和其它nodes进行通信,这被称为集群总线(cluster bus)。它们使用特殊的端口号,即对外服务端口号加10000。例如如果某个node的端口号是6379,那么它与其它nodes通信的端口号是16379。nodes之间的通信采用特殊的二进制协议。

对客户端来说,整个cluster被看做是一个整体,客户端可以连接任意一个node进行操作,就像操作单一Redis实例一样,当客户端操作的key没有分配到该node上时,Redis会返回转向指令,指向正确的node,这有点儿像浏览器页面的302 redirect跳转。

Redis Cluster是Redis 3.0以后才正式推出,时间较晚,目前能证明在大规模生产环境下成功的案例还不是很多,需要时间检验。

2.Redis Sharding集群

Redis 3正式推出了官方集群技术,解决了多Redis实例协同服务问题。Redis Cluster可以说是服务端Sharding分片技术的体现,即将键值按照一定算法合理分配到各个实例分片上,同时各个实例节点协调沟通,共同对外承担一致服务。

多Redis实例服务,比单Redis实例要复杂的多,这涉及到定位、协同、容错、扩容等技术难题。这里,我们介绍一种轻量级的客户端Redis Sharding技术。

Redis Sharding可以说是Redis Cluster出来之前,业界普遍使用的多Redis实例集群方法。其主要思想是采用哈希算法将Redis数据的key进行散列,通过hash函数,特定的key会映射到特定的Redis节点上。这样,客户端就知道该向哪个Redis节点操作数据。

庆幸的是,java redis客户端驱动jedis,已支持Redis Sharding功能,即ShardedJedis以及结合缓存池的ShardedJedisPool。

Jedis的Redis Sharding实现具有如下特点:

1.采用一致性哈希算法(consistent hashing),将key和节点name同时hashing,然后进行映射匹配,采用的算法是MURMUR_HASH。采用一致性哈希而不是采用简单类似哈希求模映射的主要原因是当增加或减少节点时,不会产生由于重新匹配造成的rehashing。一致性哈希只影响相邻节点key分配,影响量小。

2.为了避免一致性哈希只影响相邻节点造成节点分配压力,ShardedJedis会对每个Redis节点根据名字(没有,Jedis会赋予缺省名字)会虚拟化出160个虚拟节点进行散列。根据权重weight,也可虚拟化出160倍数的虚拟节点。用虚拟节点做映射匹配,可以在增加或减少Redis节点时,key在各Redis节点移动再分配更均匀,而不是只有相邻节点受影响。

3.ShardedJedis支持keyTagPattern模式,即抽取key的一部分keyTag做sharding,这样通过合理命名key,可以将一组相关联的key放入同一个Redis节点,这在避免跨节点访问相关数据时很重要。

追问哥,还是不太明白啊,有没有案例啊

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com