redis3.x集群

redis3.x集群

客户端分片都不会共享数据,容易造成单点缓存丢失的问题,集群会自动在多个redis节点之间共享数据,不会造成单点问题

搭建redis集群

简历redis集群,至少需要3个master实例,同时,为了使集群高可用,需要为每个master实例至少分配一个salve

  1. 下载redis-3.2.6.tar.gz ,下载地址
  2. 将下载好的压缩包赋值到指定的服务器上
  3. 解压安装
cd /usr/local/src
tar -zxvf redis-3.2.6.tar.gz
cd redis-3.2.6/
make && make install
  1. 创建目录,赋值配置文件
cd /usr/local
mkdir cluster-test
cs cluster-test
mkdir 7000 7001 7002 7003 7004 7005
cp /usr/local/redis-3.2.6/redis.conf 7000
cd 7000
vi redis.conf

修改7000目录下的reids.conf配置

bind 指定的ip
port 指定的端口
daemonize yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
appendonly yes

之后将该配置文件分别赋值到7001-7005中,并将配置文件中的port修改为7001-7005
daemonize指定redis是否在后台运行
cluster-enable指定是否启用集群方式
cluster-config-file指定了集群配置文件,该配置文件存储集群的一些信息,例如各个节点的状态信息,这些信息是不让开发或运维人员编辑的
cluster-node-timeout表示集群中某节点超过指定时间,就认为该节点失效了

  1. 启动6个实例
cd /usr/local/cluster-test/7000
redis-server redis.conf

之后,分别进入7001-7005的目录,启动服务

  1. 下载redis-3.2.2.gem ,下载地址
  2. 将下载好的redis-3.2.2.gem复制到服务器
scp redis-3.2.2.gem root@ip地址:/usr/local/
  1. 安装redis-3.2.2.gem
yum install ruby rubygems -y
cd /usr/local
gem install redis-3.2.2.gem
  1. 创建集群
cd /usr/local/redis-3.2.6/src/ ./redis-trib.rb create --replicas 1 ip地址:7000 ip地址:7001 ip地址:7002 ip地址:7003 ip地址:7004 ip地址:7005  

使用了redis-3.2.6/src/下的redis-trib.rb命令来创建集群,其中--replicas 1指定一个master有一个slave,之后是6个reids实例,这就是三主三从,执行命令后,显示如下信息表示成功

[ok] All nodes agree about slots configuration
  1. 使用redis-desktop-manager软件连接redis

spring boot 集成 JedisCluster

使用Jedis的JedisCluster操作集群版的redis
pom.xml

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.3.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.1.15</version>
</dependency>

在application.properties中配置redis集群信息

#配置集群信息
redis.cluster.servers=ip:port,...
#连接超时时间connectionTimeout,也是读取超时时间soTimeout
redis.cluster.commandTimeout=5000

spring boot中集成jedisCluster , 编写JedisClusterConfig代码

package com.stscode.common.configure;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;

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

@Configuration
public class JedisClusterConfig {

    @Autowired
    private Environment env;

    @Bean
    public JedisCluster jedisCluster(){
        String[] ipAddress = env.getProperty("redis.cluster.servers").split(",");
        Set<HostAndPort> hostAndPortSet = new HashSet<HostAndPort>();
        for (String address : ipAddress) {
            String[] ipAndPort = address.split(":");
            hostAndPortSet.add(new HostAndPort(ipAndPort[0].trim() , Integer.valueOf(ipAndPort[1])));
        }
        return new JedisCluster(hostAndPortSet , Integer.valueOf(env.getProperty("redis.cluster.commandTimeout")));
    }
}

该类是一个核心类,通过集群的server节点集合和读取超时时间创建了一个JedisCluster单例,之后直接使用该实例直接操作Redis
接下来编写业务代码

package com.stscode.service.impl;

import com.alibaba.fastjson.JSON;
import com.stscode.common.configure.DbAndCacheContants;
import com.stscode.common.configure.utils.RedisUtils;
import com.stscode.dao.IUserDao;
import com.stscode.dao.impl.UserDaoImpl;
import com.stscode.domain.User;
import com.stscode.service.IUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCluster;

@Service("userService")
public class UserServiceImpl implements IUserService {

    @Autowired
    private IUserDao userDao;

    @Autowired
    private JedisCluster jedisCluster;

    @Override
    public User selectByPrimaryKey(Long id) {
        return userDao.selectByPrimaryKey(id);
    }

    /**
     *
     * @param id
     * @return user
     */
     @Override
    public User getUser(Long id){
        User user = null;
        String userAsString = jedisCluster.get(DbAndCacheContants.USER_CACHE_PREFIX + id);
        if(StringUtils.isNotBlank(userAsString)){
            user = JSON.parseObject(userAsString , User.class);
            return user;
        }
        user = userDao.selectByPrimaryKey(id);
        if(user!=null){
            jedisCluster.set(DbAndCacheContants.USER_CACHE_PREFIX + id , JSON.toJSONString(user));
        }
        return user;
    }
}

该方法中不需要担心资源的释放问题了,在jedisCluster.get(String key)源码中可以看到其中finally中释放了资源(内部首先根据key获取一个Jedis,之后进行redis的get操作,执行完毕后,会将该jedis释放掉,所以不需要获取jedis,也不需要释放jedis)

使用 GuavaCache实现本地缓存

使用本地缓存: GoogleGuavaCache
pom.xml中引入

<!-- guava cache -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>14.0.1</version>
</dependency>

在业务逻辑中使用本地缓存获取对象数据

package com.stscode.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.stscode.common.configure.DbAndCacheContants;
import com.stscode.common.configure.utils.RedisUtils;
import com.stscode.dao.IUserDao;
import com.stscode.dao.impl.UserDaoImpl;
import com.stscode.domain.User;
import com.stscode.service.IUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCluster;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

@Service("userService")
public class UserServiceImpl implements IUserService {

    @Autowired
    private IUserDao userDao;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private JedisCluster jedisCluster;

	/*
		设置本地缓存对象
	*/
    LoadingCache<String , User> userCache = CacheBuilder.newBuilder()
            .expireAfterWrite(20 , TimeUnit.MINUTES) //最久缓存20分钟
            .maximumSize(1000) //设置最多缓存多少个数据
            .build(new CacheLoader<String, User>() {
                @Override
                /*
                    如果本地缓存中没有user数据,
                    则会调用该load方法去从数据库获取,
                    然后自动存储到userCache中
                 */
                public User load(String s) throws Exception {
                    User user = null;
                    //切割key,并将id作为参数传入查询,并返回数据
                    user = userDao.selectByPrimaryKey(Long.valueOf(s.split(":")[1]));
                    if (user == null){
                        //如果user为空',则创建空user对象
                        user = new User();
                    }
                    return user; //返回
                }
            });

    @Override
    public User selectByPrimaryKey(Long id) {
        return userDao.selectByPrimaryKey(id);
    }

    /**
     *
     * @param id
     * @return user
     */
    public User getUserForCache(Long id){
        User user = null;
        try {
            //从本地缓存中获取数据,如果没有获取到,则调用内部的load方法从数据库中查询
            user = userCache.get(DbAndCacheContants.USER_CACHE_PREFIX + id);
        }catch(Exception ex){
            ex.printStackTrace();
        }
        return user;
    }
}

执行load方法时,会从数据库中获取信息,然后自动存储到userCache中,之后再从userCache中获取user数据,传给调用方,如果使用redis,我们从数据库获取数据后,还需要手动插入到Redis

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘子君ee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值