文档章节

Spring整合redis,通过sentinel进行主从切换。(何志雄)

明舞
 明舞
发布于 2015/07/16 14:24
字数 1032
阅读 218
收藏 11

实现功能描述:

        redis服务器进行Master-slaver-slaver-....主从配置,通过2台sentinel进行failOver故障转移,自动切换,采用该代码完全可以直接用于实际生产环境。

       

       题外话:

         一般来说这样的部署足以支持数以百万级的用户,但如果数量实在是太高,此时redis的Master-Slaver主从不一定能够满足,因此进行redis的分片。

        本文不讲解redis的分片,但如果你使用了,需要注意的按照另一篇文章的介绍:Sentinel&Jedis看上去是个完美的解决方案,这句话只说对了一半,

         在无分片的情况是这样,但我们的应用使用了数据分片-sharing,数据被平均分布到4个不同的实例上,每个实例以主从结构部署,Jedis没有提供

         基于Sentinel的ShardedJedisPool,也就是说在4个分片中,如果其中一个分片发生主从切换,应用所使用的ShardedJedisPool无法获得通知,所有

         对那个分片的操作将会失败。文章中提出了解决方案,请参考《基于Redis Sentinel的Redis集群(主从&Sharding)高可用方案

        

 

 

        该代码模拟多线程向redis中set/get。

 

1、maven依赖配置

<dependency>
		<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
			<version>1.4.1.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.6.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.3.2</version>
	</dependency>


 

2、redis.properties

# Redis settings
#sentinel1的IP和端口
im.hs.server.redis.sentinel1.host=192.168.62.154
im.hs.server.redis.sentinel1.port=26379
#sentinel2的IP和端口
im.hs.server.redis.sentinel2.host=192.168.62.153
im.hs.server.redis.sentinel2.port=26379
#sentinel的鉴权密码
im.hs.server.redis.sentinel.masterName=155Master
im.hs.server.redis.sentinel.password=hezhixiong
#最大闲置连接数
im.hs.server.redis.maxIdle=500
#最大连接数,超过此连接时操作redis会报错
im.hs.server.redis.maxTotal=5000
im.hs.server.redis.maxWaitTime=1000
im.hs.server.redis.testOnBorrow=true
#最小闲置连接数,spring启动的时候自动建立该数目的连接供应用程序使用,不够的时候会申请。
im.hs.server.redis.minIdle=300


3、spring-redis.xml

<?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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- Spring自动将该包目录下标记为@Service的所有类作为spring的Bean -->
	<context:component-scan base-package="com.gaojiasoft.test.redis" />

	<context:property-placeholder location="classpath:conf/redis/redis.properties" />

	<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxTotal" value="${im.hs.server.redis.maxTotal}" />
		<property name="minIdle" value="${im.hs.server.redis.minIdle}" />
		<property name="maxWaitMillis" value="${im.hs.server.redis.maxWaitTime}" />
		<property name="maxIdle" value="${im.hs.server.redis.maxIdle}" />
		<property name="testOnBorrow" value="${im.hs.server.redis.testOnBorrow}" />
		<property name="testOnReturn" value="true" />
		<property name="testWhileIdle" value="true" />
	</bean>

	<bean id="sentinelConfiguration"
		class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
		<property name="master">
			<bean class="org.springframework.data.redis.connection.RedisNode">
				<property name="name" value="${im.hs.server.redis.sentinel.masterName}"></property>
			</bean>
		</property>
		<property name="sentinels">
			<set>
				<bean class="org.springframework.data.redis.connection.RedisNode">
					<constructor-arg name="host"
						value="${im.hs.server.redis.sentinel1.host}"></constructor-arg>
					<constructor-arg name="port"
						value="${im.hs.server.redis.sentinel1.port}"></constructor-arg>
				</bean>
				<bean class="org.springframework.data.redis.connection.RedisNode">
					<constructor-arg name="host"
						value="${im.hs.server.redis.sentinel2.host}"></constructor-arg>
					<constructor-arg name="port"
						value="${im.hs.server.redis.sentinel2.port}"></constructor-arg>
				</bean>
			</set>
		</property>
	</bean>

	<bean id="connectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:password="${im.hs.server.redis.sentinel.password}">
		<constructor-arg name="sentinelConfig" ref="sentinelConfiguration"></constructor-arg>
		<constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
	</bean>

	<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
		<property name="connectionFactory" ref="connectionFactory" />
	</bean>
</beans><strong>
</strong>

 

4、RedisServiceImpl.java

package com.gaojiasoft.test.redis;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

@Service("redisService")
public class RedisServiceImpl {

	private Logger logger = LoggerFactory.getLogger("RedisServiceImpl");

	@Autowired
	RedisTemplate<?, ?> redisTemplate;

	// 线程池
	private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(
			256, 256, 30L, TimeUnit.SECONDS,
			new LinkedBlockingQueue<Runnable>(),
			new BasicThreadFactory.Builder().daemon(true)
					.namingPattern("redis-oper-%d").build(),
			new ThreadPoolExecutor.CallerRunsPolicy());

	public void set(final String key, final String value) {
		redisTemplate.execute(new RedisCallback<Object>() {
			@Override
			public Object doInRedis(RedisConnection connection)
					throws DataAccessException {
				connection.set(
						redisTemplate.getStringSerializer().serialize(key),
						redisTemplate.getStringSerializer().serialize(value));
				logger.debug("save key:" + key + ",value:" + value);
				return null;
			}
		});
	}

	public String get(final String key) {
		return redisTemplate.execute(new RedisCallback<String>() {
			@Override
			public String doInRedis(RedisConnection connection)
					throws DataAccessException {
				byte[] byteKye = redisTemplate.getStringSerializer().serialize(
						key);
				if (connection.exists(byteKye)) {
					byte[] byteValue = connection.get(byteKye);
					String value = redisTemplate.getStringSerializer()
							.deserialize(byteValue);
					logger.debug("get key:" + key + ",value:" + value);
					return value;
				}
				logger.error("valus does not exist!,key:"+key);
				return null;
			}
		});
	}

	public void delete(final String key) {
		redisTemplate.execute(new RedisCallback<Object>() {
			public Object doInRedis(RedisConnection connection) {
				connection.del(redisTemplate.getStringSerializer().serialize(
						key));
				return null;
			}
		});
	}

	/**
	 * 线程池并发操作redis
	 * 
	 * @param keyvalue
	 */
	public void mulitThreadSaveAndFind(final String keyvalue) {
		executor.execute(new Runnable() {
			@Override
			public void run() {
				try {
					set(keyvalue, keyvalue);
					get(keyvalue);
				} catch (Throwable th) {
					// 防御性容错,避免高并发下的一些问题
					logger.error("", th);
				}
			}
		});
	}
}


5、RedisTest.java   (Junit测试用例)

package com.gaojiasoft.test.redis;

import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class RedisTest {

	private static ConfigurableApplicationContext context;

	RedisServiceImpl service;

	@Test
	public void testSave() throws InterruptedException {
		context = new ClassPathXmlApplicationContext(
				"classpath:conf/redis/spring-redis.xml");
		service = (RedisServiceImpl) context.getBean("redisService");

		int i = 1;
		while (true) {
			Thread.sleep(1);
			try {
				service.mulitThreadSaveAndFind("" + i);
			} catch (Exception e) {
				e.printStackTrace();
			}
			i++;
		}
	}
}


 



 

版权声明:本文为博主原创文章,未经博主允许不得转载。

本文转载自:http://blog.csdn.net/tzszhzx/article/details/44590871

共有 人打赏支持
明舞
粉丝 227
博文 424
码字总数 516555
作品 0
程序员
私信 提问
玩转 Redis 集群之 Sentinel

Redis作为内存数据库,需要具备高可用的特点,不然如果服务器宕机,还在内存里的数据就会丢失。我们最常用的高可用方法就是搭建集群,master机器挂了,可以让slave机器顶上,继续提供服务。但...

微笑向暖wx
2018/11/07
0
0
基于Redis Sentinel的Redis集群(主从&Sharding)高可用方案

基于Redis Sentinel的Redis集群(主从&Sharding)高可用方案 http://www.tuicool.com/articles/naeEJbv 基于Redis Sentinel的Redis集群(主从&Sharding)高可用方案 时间 2014-02-21 15:15:17 IT......

毛朱
2015/08/30
0
0
求知识,这样可否管理负载均衡的用户登录?

求知识,这样可否管理负载均衡的用户登录? (1)redis 主从配置 + spring配置 redis一主一从,web网站是spring mvc,在spring里面增加redis支持,sentinel,主挂了,自动切到从 (2)cooki...

猫神
2015/09/08
108
1
redis的哨兵(sentinel)配置和python程序应用示例

一、Sentinel概述: 当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,...

青苗飞扬
2017/10/19
0
0
推荐几个自己写的Java后端相关的范例项目(转载)

http://wosyingjun.iteye.com/blog/2312553 这里推荐几个自己写的范例项目,主要采用SSM(Spring+SpringMVC+Mybatis)框架,分布式架构采用的是(dubbo+zookeeper)。范例项目的好处是简单易...

指尖的舞者
2016/09/27
147
0

没有更多内容

加载失败,请刷新页面

加载更多

linux 服务管理 Crontba、Ntpdate、Logrotate、Supervisor

crond linux 系统则是由 cron (crond) 这个系统服务来控制的。Linux 系统上面原本就有非常多的计划性工作,因此这个系统服务是默认启动的。 另外, 由于使用者自己也可以设置计划任务,所以,...

狼王黄师傅
37分钟前
1
0
Sobel算子和Scharr滤波器

Sobel算子在数学上的本质是微分,对离散信号,是求邻域内的增量。 基本原理:在图像上,对图像信号在某点进行微分,表示图像的某个特征(如,强度、色调或者饱和度)在该点的变换程度。以强度...

yepanl
54分钟前
1
0
Jenkins API 使用

Jenkins 是一款流行的开源持续集成工具,可以用来做一些软件开发的自动化工作,如打包,测试,自动部署等。 Jenkins 中有 view 和 job 的概念, view 相当于组, job 则是具体的任务。 view...

YanWen
55分钟前
5
0
聊聊jest的NodeChecker

序 本文主要研究一下jest的NodeChecker NodeChecker jest-common-6.3.1-sources.jar!/io/searchbox/client/config/discovery/NodeChecker.java public class NodeChecker extends AbstractS......

go4it
今天
3
0
深入分析String.intern和String常量的实现原理

背景 字符串类型在实际应用场景中使用非常频繁,如果为每个字符串常量都生成一个对应的String对象,明显会造成内存的浪费,针对这一问题,虚拟机实现一个字符串常量池的概念,提供了如下实现...

群星纪元
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部