经过上次轻松搭建了一个Redis的环境并用Java代码调通后,这次我们要来看看Redis的一些坑以及Redis2.8以后带来的一个新的特性即支持高可用特性功能的Sentinel(哨兵)。
Redis是一个很优秀的NoSql,它支持键值对,查询方便,被大量应用在Internet的应用中,它即可以用作Http Session的分离如上一次举例中的和Spring Session的结合,还可以直接配置在Tomcat中和Tomcat容器结合并可以自动使用Redis作Session盛载器,同时它也可以作为一个分布式缓存。
这边的单线程不是指它就是顺序式工作的,这边的单线程主要关注的是Redis的一个很重要的功能即“持久化”工作机制。Redis一般会使用两种持久化工作机制,这种工作机制如果在单个Redis Node下工作是没有意义的,因此你必须要有两个Redis Nodes,如:
| IP | 端口 | 身份 | 
| 192.168.56.101 | 7001 | 主节点 | 
| 192.168.56.101 | 7002 | 备节点 | 
object=queryFromCache();
if(object==null||queryFromCache throw any exception)
{
  object=queryFromDB();
}echonever > /sys/kernel/mm/transparent_hugepage/enabled
Redis配置文件中的这一行代表Redis会使用系统内存,你不该去限制Redis的内存开销如:JVM中的-xmx这个参数,而是要让Redis自动去使用系统的内存以获得最高的性能,因此我们会把这个值设成0即代表无限使用系统内存,系统内存有多少我们用多少。默认它启动后会消耗掉1个G的系统自有内存。
因此linux系统中有一个系统参数叫overcommit_memory,它代表的是内存分配策略,可选值为:0、1、2。
0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
2, 表示内核允许分配超过所有物理内存和交换空间总和的内存
所以我们结合我们的Redis使用以下的linux命令:
echo1 > /proc/sys/vm/overcommit_memory
sysctl-p
有时位于系统访问高峰时间段突发的大量请求导致redis连接数过大,你会收到这样的错误信息:
Too many open files.
这是因为频繁访问Redis时造成了TCP连接数打开过大的主要原因, 这是因为Redis源码中在accept tcp socket时的实现里面遇到句柄数不够的处理方法为:留在下次处理,而不是断开TCP连接。
但这一行为就会导致监听套接字不断有可读消息,但却accept无法接受,从而listen的backlog被塞满;从而导致后面的连接被RST了。
这里我多啰嗦一下也就是Redis和Memcached的比较,memcached对于这种情况的处理有点特殊,或者说周到!
如果memcache accept 的时候返回EMFILE,那么它会立即调用listen(sfd, 0) , 也就是将监听套接字的等待accept队列的backlog设置为0,从而拒绝掉这部分请求,减轻系统负载,保全自我。
因此为了对付这个too many open files问题我们需要在Linux下做点小动作来改变ulimit的配置。
* soft nofile = 65535 * hard nofile = 65535
ulimit -n 65535
通过上述一些设置,我们基本完成了Redis在做集群前的准备工作了,下面就来使用Redis的Sentinel来做我们的高可用方案吧。
考虑到大多数学习者环境有限,我们使用如下配置:
| IP | 端口 | 身份 | 
| 192.168.56.101 | 7001 | master | 
| 192.168.56.101 | 7002 | slave | 
| 192.168.56.101 | 26379 | sentinel | 
所以我们在一台服务器上安装3个目录:
make PREFIX=/usr/local/redis1 install make PREFIX=/usr/local/redis2 install make PREFIX=/usr/local/redis-sentinel install
port 26379 daemonize yes logfile "/var/log/redis/sentinel.log" sentinel monitor master1 192.168.56.101 7001 1 sentinel down-after-milliseconds master1 1000 sentinel failover-timeout master1 5000 #sentinel can-failover master1 yes #remove from 2.8 and aboved version
在配置Redis Sentinel做Redis的HA场景时,一定要注意下面几个点:
这部分配置除了端口号,所在目录,pid文件与log文件不同其它配置相同,因此下面只给出一份配置:
daemonize yes pidfile "/var/run/redis/redis1.pid" port 7001 tcp-backlog 511 timeout 0 tcp-keepalive 0 loglevel notice logfile "/var/log/redis/redis1.log" databases 16 save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error no rdbcompression yes rdbchecksum yes dbfilename "dump.rdb" dir "/usr/local/redis1/data" slave-serve-stale-data yes slave-read-only yes #slave只读,当你的应用程序试图向一个slave写数据时你会得到一个错误 repl-diskless-sync no repl-disable-tcp-nodelay no slave-priority 100 maxmemory 0 appendonly no # The name of the append only file (default: "appendonly.aof") appendfilename "appendonly.aof" # appendfsync always #appendfsync everysec appendfsync no #关闭AOF no-appendfsync-on-rewrite yes auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "gxE" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-entries 512 list-max-ziplist-value 64 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10
slaveof 192.168.56.101 7002
redis-cli -p 26379 -h 192.168.56.101进入我们配置好的sentinel后并使用: info命令来查看我们的redis sentinel HA配置。
redis-cli -p 7001 -h 192.168.56.101
我们还可以通过命令:
redis-cli -h 192.168.56.101 -p 7002
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>webpoc</groupId>
	<artifactId>webpoc</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.8</java.version>
		<jetty.version>9.3.3.v20150827</jetty.version>
		<slf4j.version>1.7.7</slf4j.version>
		<spring.version>4.2.1.RELEASE</spring.version>
		<spring.session.version>1.0.2.RELEASE</spring.session.version>
		<javax.servlet-api.version>2.5</javax.servlet-api.version>
		<activemq_version>5.8.0</activemq_version>
		<poi_version>3.8</poi_version>
	</properties>
	<dependencies>
		<!-- poi start -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>${poi_version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>${poi_version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-scratchpad</artifactId>
			<version>${poi_version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>${poi_version}</version>
		</dependency>
		<!-- poi end -->
		<!-- active mq start -->
		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-all</artifactId>
			<version>5.8.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-pool</artifactId>
			<version>${activemq_version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.xbean</groupId>
			<artifactId>xbean-spring</artifactId>
			<version>3.16</version>
		</dependency>
		<!-- active mq end -->
		<!-- servlet start -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>${javax.servlet-api.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<!-- servlet end -->
		<!-- redis start -->
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.7.2</version>
		</dependency>
		<dependency>
			<groupId>org.redisson</groupId>
			<artifactId>redisson</artifactId>
			<version>1.0.2</version>
		</dependency>
		<!-- redis end -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<!-- spring conf start -->
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
			<version>1.6.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
			<exclusions>
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session</artifactId>
			<version>${spring.session.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<!-- spring conf end -->
	</dependencies>
	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.4</version>
				<configuration>
					<warSourceDirectory>WebContent</warSourceDirectory>
					<failOnMissingWebXml>false</failOnMissingWebXml>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project><?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">
	<context:property-placeholder location="classpath:/spring/redis.properties" />
	<context:component-scan base-package="org.sky.redis">
	</context:component-scan>
	<bean id="jedisConnectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<constructor-arg index="0" ref="redisSentinelConfiguration" />
		<constructor-arg index="1" ref="jedisPoolConfig" />
	</bean>
	<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxTotal" value="${redis.maxTotal}" />
		<property name="maxIdle" value="${redis.maxIdle}" />
		<property name="maxWaitMillis" value="${redis.maxWait}" />
		<property name="testOnBorrow" value="${redis.testOnBorrow}" />
		<property name="testOnReturn" value="${redis.testOnReturn}" />
	</bean>
	<bean id="redisSentinelConfiguration"
		class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
		<property name="master">
			<bean class="org.springframework.data.redis.connection.RedisNode">
				<property name="name" value="master1" />
			</bean>
		</property>
		<property name="sentinels">
			<set>
				<bean class="org.springframework.data.redis.connection.RedisNode">
					<constructor-arg name="host" value="192.168.56.101" />
					<constructor-arg name="port" value="26379" />
				</bean>
			</set>
		</property>
	</bean>
	<bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
		<property name="connectionFactory" ref="jedisConnectionFactory" />
	</bean>
	<!--将session放入redis -->
	<bean id="redisHttpSessionConfiguration"
		class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
		<property name="maxInactiveIntervalInSeconds" value="1800" />
	</bean>
	<bean id="customExceptionHandler" class="sample.MyHandlerExceptionResolver" />
</beans> <property name="master"> <bean class="org.springframework.data.redis.connection.RedisNode"> <property name="name" value="master1" /> </bean> </property>
# Redis settings redis.host.ip=192.168.56.101 redis.host.port=7001 redis.maxTotal=1000 redis.maxIdle=100 redis.maxWait=2000 redis.testOnBorrow=false redis.testOnReturn=true redis.sentinel.addr=192.168.56.101:26379
package sample;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import util.CountCreater;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
 * Created by xin on 15/1/7.
 */
@Controller
public class SentinelController {
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private StringRedisTemplate redisTemplate;
	@RequestMapping("/sentinelTest")
	public String sentinelTest(final Model model,
			final HttpServletRequest request, final String action) {
		return "sentinelTest";
	}
	@ExceptionHandler(value = { java.lang.Exception.class })
	@RequestMapping("/setValueToRedis")
	public String setValueToRedis(final Model model,
			final HttpServletRequest request, final String action)
			throws Exception {
		CountCreater.setCount();
		String key = String.valueOf(CountCreater.getCount());
		Map mapValue = new HashMap();
		for (int i = 0; i < 1000; i++) {
			mapValue.put(String.valueOf(i), String.valueOf(i));
		}
		try {
			BoundHashOperations<String, String, String> boundHashOperations = redisTemplate
					.boundHashOps(key);
			boundHashOperations.putAll(mapValue);
			logger.info("put key into redis");
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new Exception(e);
		}
		return "sentinelTest";
	}
}
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; UTF-8"> <title>test sentinel r/w</title> </head> <body> </body> </html>
原文:http://blog.csdn.net/lifetragedy/article/details/50660310