(转)Spring +Redis 集群集成

项目实现spring 和redis集群集成说明文档

Redis集群方案

选择redis集群方案有:redis3.0版本以上使用Redis Cluster, 3.0版本以下使用Redis +Sentinel 。

Redis +Sentinel 方案

参考: https://wizardforcel.gitbooks.io/redis-doc/content/doc/8.html

http://wiki.jikexueyuan.com/project/redis-guide/high-availability-b.html

优点

  • 监控:监控主从是否正常运行
  • 提醒:问题提醒
  • 故障转移:主从节点自动转移

缺点

  • Sentinel 存在单节点问题,需要对Sentinel进行搭建高可用服务
  • 每个节点需要有Sentinel监控,包含master和slave节点

Redis Cluster方案

参考: https://wizardforcel.gitbooks.io/redis-doc/content/doc/8.html

http://wiki.jikexueyuan.com/project/redis-guide/high-availability-b.html

优点

  • 有Sentinel的监控能力和自动切换主从功能
  • 在扩展添加内存 比较容易
  • 分片功能

缺点

  • 其中一个主从节点服务停止,出现缓存不能使用,hash slot 无法使用,不是很强的数据一致性
  • 存在数据一致性问题,主要体现在数据正在写入的主节点,此节点停止,出现数据写入此节点的数据丢失
  • 添加节点需要分担已有节点的hash slot

 

 

 

 

 

Redis Cluster 环境搭建

Redis Cluster 安装

下载最新的redis稳定版本 :http://redis.io/ 3.07版本

  • 安装 c编译工具: yum install Development Tools

  • 执行编译安装

    cd /root/redis-3.0.7
    

    make install

  • 建立单独文件夹:

    mkdir -p /redis-cluster
    
  • 建立节点目录,
    mkdir 9000 9001 9002 9003 9004 9005
    
  • 拷贝配置文件和执行文件到redis-cluster中,

    拷贝执行脚本:scp redis-cli redis-server  redis-trib.rb /redis-cluster/bin
    
    拷贝配置文件:scp redis.conf /redis-cluster/etc
    
  • 配置一个节点的配置文件,以端口为9000开始节点开始为例,将redis.conf 拷贝到9000文件夹下,并修改一下名称:

    [root@computer redis-cluster]# scp etc/redis.conf 9000
    [root@computer 9000]# mv redis.conf redis-9000.conf
    
  • 修改redis-9000.conf的配置文件,修改点:端口,后台启动,持久化模式,绑定ip

daemonize yes --后台启动

port 9000 --端口

bind 192.168.85.15 绑定

dir /redis-cluster/9000 持久胡保文件目录

appendfsync everysec -保存数据策略,每秒保存写入数据

cluster-config-file nodes-9000.conf --节点文件 可以随意命名

cluster-enabled yes --支持=分布式

  • 复制redis-9000.conf的文件到9001,9002,9003,9004,9005,按照9000的修改方式,这里我这放置一台机器上,只修改一个端口号即可,使用替换命名:
[root@computer 9000]# scp redis-9000.conf ../9001/
[root@computer 9000]# scp redis-9000.conf ../9002/
[root@computer 9000]# scp redis-9000.conf ../9003/
[root@computer 9000]# scp redis-9000.conf ../9004/
[root@computer 9000]# scp redis-9000.conf ../9005/

替换命名:

%s/9000/9001/g
  • 启动各节点
[root@computer bin]# ./redis-server  /redis-cluster/9000/redis-9000.conf 
[root@computer bin]# ./redis-server  /redis-cluster/9001/redis-9001.conf 
[root@computer bin]# ./redis-server  /redis-cluster/9002/redis-9001.conf 
9002/
[root@computer bin]# ./redis-server  /redis-cluster/9002/redis-9002.conf 
[root@computer bin]# ./redis-server  /redis-cluster/9003/redis-9003.conf 
[root@computer bin]# ./redis-server  /redis-cluster/9004/redis-9004.conf 
[root@computer bin]# ./redis-server  /redis-cluster/9005/redis-9005.conf 
[root@computer bin]# ps -ef|grep redis
root      16514      1  0 23:25 ?        00:00:00 ./redis-server 192.168.85.15:9000 [cluster]
root      16518      1  0 23:25 ?        00:00:00 ./redis-server 192.168.85.15:9001 [cluster]
root      16522      1  0 23:25 ?        00:00:00 ./redis-server 192.168.85.15:9002 [cluster]
root      16526      1  0 23:25 ?        00:00:00 ./redis-server 192.168.85.15:9003 [cluster]
root      16530      1  0 23:25 ?        00:00:00 ./redis-server 192.168.85.15:9004 [cluster]
root      16534      1  0 23:25 ?        00:00:00 ./redis-server 192.168.85.15:9005 [cluster]
root      16538   2286  0 23:25 pts/0    00:00:00 grep --color=auto redis
  • 各节节点关联成一个集群,每个主节点只有一个slave模式,需要安装Ruby 安装包,以及ruby 安装redis,此过程需要点时间

    yum install ruby -y
    [root@computer bin]# gem install redis 
    Fetching: redis-3.2.2.gem (100%)
    
  • 关联redis节点 变成一个集群
[root@computer bin]# ./redis-trib.rb  create  --replicas 1  192.168.85.15:9000 192.168.85.15:9001  192.168.85.15:9002 192.168.85.15:9003 192.168.85.15:9004 192.168.85.15:9005 
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.85.15:9000
192.168.85.15:9001
192.168.85.15:9002
Adding replica 192.168.85.15:9003 to 192.168.85.15:9000
Adding replica 192.168.85.15:9004 to 192.168.85.15:9001
Adding replica 192.168.85.15:9005 to 192.168.85.15:9002
M: d922ee9e4d7dd0ccce63e6b4e7f04faed2d51181 192.168.85.15:9000
   slots:0-5460 (5461 slots) master
M: 5c15d98e5f0316a8ec8309689ece938bdae4c200 192.168.85.15:9001
   slots:5461-10922 (5462 slots) master
M: dd02b536abd6fe98b2fd025d45b87e38aa4c321b 192.168.85.15:9002
   slots:10923-16383 (5461 slots) master
S: 52aee1c458ed407d4ae0121f6c101c46a640a13f 192.168.85.15:9003
   replicates d922ee9e4d7dd0ccce63e6b4e7f04faed2d51181
S: 9c4c7cbccfc52b6b864fef38a8844fa4ed499969 192.168.85.15:9004
   replicates 5c15d98e5f0316a8ec8309689ece938bdae4c200
S: ae0616372c550085a4035b1b720aef7af0e351a0 192.168.85.15:9005
   replicates dd02b536abd6fe98b2fd025d45b87e38aa4c321b

验证集群

  • 默认情况下所有的slave的节点不支持读,写操作,所以在所有的slave节点上执行readonly即可。

以下可以看出主节点的端口是:9000,9001,9002 slave节点的端口:9003,9004,9005

即在9003,9004,9005节点上执行readonly命令,不执行的话,在slave节点是不能读取数据的。

[root@computer log]# redis-cli -h 192.168.85.15  -p 9000 cluster nodes
d922ee9e4d7dd0ccce63e6b4e7f04faed2d51181 192.168.85.15:9000 myself,master - 0 0 1 connected 0-5460
dd02b536abd6fe98b2fd025d45b87e38aa4c321b 192.168.85.15:9002 master - 0 1458059365417 3 connected 10923-16383
ae0616372c550085a4035b1b720aef7af0e351a0 192.168.85.15:9005 slave dd02b536abd6fe98b2fd025d45b87e38aa4c321b 0 1458059364406 6 connected
9c4c7cbccfc52b6b864fef38a8844fa4ed499969 192.168.85.15:9004 slave 5c15d98e5f0316a8ec8309689ece938bdae4c200 0 1458059366427 5 connected
52aee1c458ed407d4ae0121f6c101c46a640a13f 192.168.85.15:9003 slave d922ee9e4d7dd0ccce63e6b4e7f04faed2d51181 0 1458059368449 4 connected
5c15d98e5f0316a8ec8309689ece938bdae4c200 192.168.85.15:9001 master - 0 1458059367436 2 connected 5461-10922
[root@computer log]# redis-cli -h 192.168.85.15  -p 9003
192.168.85.15:9003> readonly
OK
192.168.85.15:9003> 
[root@computer log]# redis-cli -h 192.168.85.15  -p 9004
192.168.85.15:9004> readonly
OK
192.168.85.15:9004> 
[root@computer log]# redis-cli -h 192.168.85.15  -p 9005
192.168.85.15:9005> readonly
OK
192.168.85.15:9005> keys *
(empty list or set)
192.168.85.15:9005> 
[root@computer log]# redis-cli -h 192.168.85.15  -p 9003
192.168.85.15:9003> keys *
1) "hello"
192.168.85.15:9003> get hello
"word"
192.168.85.15:9003>











Spring和Redis Cluster集成

采用spring boot ,redis,maven集成一个demo实例。

  • maven依赖的spring的jar,pom.xml如下:
<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>Spring-RedisCluster</groupId>
  <artifactId>com.yirui.nestoop.spring.redis</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>com.yirui.nestoop.spring.redis</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.5.RELEASE</version>
    </parent>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>1.3.3.RELEASE</version>
    </dependency>
    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>1.6.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.8.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>
  </dependencies>
</project>
  • 开始运行App.java,直接上代码,如是看
package com.yirui.nestoop.redis;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.yirui.nestoop.redis.*")
@EnableConfigurationProperties
@EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
public class App {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(App.class);
        System.out.println("redis cache 测试 start!");
        application.run(args);
    }
}
  • 设置spring boot 集成tomcat的端口号,需要在src 下建立一个resource资源文件夹,文件名命名为:application.properties,内容是端口:9005
server.port=9005
  • 连接Reis Cluster的配置加载的类:RedisConfig.java
package com.yirui.nestoop.redis.spring.conf;

import java.util.HashSet;
import java.util.Set;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public JedisCluster jedisCluster() {
        String hosts = "192.168.85.15:9000,192.168.85.15:9001,192.168.85.15:9002,192.168.85.15:9003,192.168.85.15:9004,192.168.85.15:9005";
        Set<HostAndPort> nodes = new HashSet<HostAndPort>();
        for (String host : hosts.split(",")) {
            String[] hs = host.split(":");
            nodes.add(new HostAndPort(hs[0], paseInt(hs[1])));
        }
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(1000);
        config.setMaxIdle(100);
        config.setTestOnBorrow(true);
        return new JedisCluster(nodes, config);
    }

    @Bean
    public CacheManager cacheManager(JedisCluster jedisCluster){

        return null;
    }

    public int paseInt(String number){

        return Integer.parseInt(number);
    }



}
  • 创建一个Controller ,实现通过浏览器,向redis cluster集群插入数据,测试需要,只写了插入数据和查询数据的方法。代码:RedisController.java
package com.yirui.nestoop.redis.spring.controller;

import javax.annotation.Resource;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.yirui.nestoop.redis.spring.service.RedisCacheService;

@RestController
public class RedisController {

    @Resource
    private RedisCacheService redisCacheService;

    @RequestMapping(value = "add", method = RequestMethod.GET)
    public int addCache(){
        return redisCacheService.pushKeyAndValue("test", "test");
    }

    @RequestMapping(value = "query", method = RequestMethod.GET)
    public String queryCacheNum(){
        return redisCacheService.pullBykey("test");
    }

}
  • 创建controller访问的service

    service接口

    package com.yirui.nestoop.redis.spring.service;
    
    public interface RedisCacheService {
    
        public int pushKeyAndValue(String key,String value);
    
        public String pullBykey(String key);
    
    }
    

service 实现

    package com.yirui.nestoop.redis.spring.service.impl;

  import javax.annotation.Resource;

  import org.springframework.stereotype.Service;

  import com.yirui.nestoop.redis.spring.conf.RedisConfig;
  import com.yirui.nestoop.redis.spring.service.RedisCacheService;

  import redis.clients.jedis.JedisCluster;

  @Service(value="redisCacheService")
  public class RedisCacheServiceImpl implements  RedisCacheService{

      @Resource
      private RedisConfig redisConfig;

      /**
       * 
       * 加入缓存数据
       */
      public int pushKeyAndValue(String key,String value){

          JedisCluster jedisCluster =redisConfig.jedisCluster();

          String ss=jedisCluster.set(key.getBytes(), value.getBytes());

          System.out.println("set ss==="+ss);

          return 1;

      }
      /**
       * 查询数据
       */

      public String  pullBykey(String key) {

          JedisCluster jedisCluster =redisConfig.jedisCluster();

          byte[] byte_value=jedisCluster.get(key.getBytes());

          if(byte_value !=null && byte_value.length>0){
              System.out.println(String.format("查询缓存 key:%s,value:%s", key,new String(byte_value)));
              return new String(byte_value);
          }
          return "null";

      }



  }
  • 在测试时需要使用的的命令,停止一个redis 的主节点,查看slave 节点是否变为master节点。

查看所有节点情况:redis-cli -h ip -p port cluster nodes

[root@computer ~]# redis-cli -h 192.168.85.15  -p 9000 cluster nodes
52aee1c458ed407d4ae0121f6c101c46a640a13f 192.168.85.15:9003 master - 0 1458136357102 7 connected 0-5460
ae0616372c550085a4035b1b720aef7af0e351a0 192.168.85.15:9005 slave dd02b536abd6fe98b2fd025d45b87e38aa4c321b 0 1458136359453 6 connected
5c15d98e5f0316a8ec8309689ece938bdae4c200 192.168.85.15:9001 master,fail - 1458136116693 1458136113431 2 disconnected
9c4c7cbccfc52b6b864fef38a8844fa4ed499969 192.168.85.15:9004 master - 0 1458136358127 8 connected 5461-10922
d922ee9e4d7dd0ccce63e6b4e7f04faed2d51181 192.168.85.15:9000 myself,slave 52aee1c458ed407d4ae0121f6c101c46a640a13f 0 0 1 connected
dd02b536abd6fe98b2fd025d45b87e38aa4c321b 192.168.85.15:9002 master - 0 1458136359147 3 connected 10923-16383

关闭一个节点:redis-cli -h ip -p port shutdown

 
posted @ 2017-09-05 10:58  LatteYan  阅读(150)  评论(0)    收藏  举报