当前位置: 首页 > 工具软件 > Redis Shard > 使用案例 >

redis2.x客户端分片

姬振
2023-12-01

微服务缓存系统

常用的缓存技术

缓存一般分为本地缓存和分布式缓存两种,本地缓存指的是将数据存储在本机内存中,操作缓存数据的速度很快,但是缺点也很明显:
1. 缓存数据的数量与大小受限于本机内存
2. 如果有多台应用服务器,可能所有应用服务器都要维护一份缓存,这样就占用了很多的内存
分布式缓存正好解决这两大问题,首先,数据存储在另外的机器上,理论上不断添加缓存机器,所以缓存的数据的数量可以是无限量的,其次的是,缓存几种放置在了远程的缓存服务器上,应用服务器不需要耗费空间来维护缓存,缺点也很明显,就是由于是远程操作,所以操作缓存数据的速度相较于本地缓存要慢很多

当前使用最好的本地缓存是GoogleGuavaCache,用的较多的分布式缓存是Memcachedredis
越来越多的公司使用redis,因为它支持五种数据结构: String , hash , set,
list , sorted list,redis还提供了两种持久化方式:(AOFRDB),redis可以别看作是内存数据库,还支持事件调度,发布订阅等,还可以充当一下队列

下面介绍两种版本的使用方式: redis2.x 的客户都安分片和redis3.x的集群

Redis2.x客户端分片

操作系统: centos7 (两台)
下载 redis-2.6.14.tar.gz

将下载好的redis-2.6.14.tar.gz赋值到两台服务器中
解压安装…

cd /usr/local/src
tar -zxvf redis-2.6.14.tar.gz
cd redis-2.6.14.tar.gz
make && make install

启动服务

nohup redis-server redis.conf & 

直接使用redis默认的配置文件来启动服务,并且设置为后台运行,将相关日志写入nohup.out文件中

使用rdm(redis-desktop-manager)软件连接redis

spring boot集成ShardJedis

客户端分片通常使用redis的ShardJedis来实现
在pom.xml文件中引入如下依赖

<!--jedis-->
<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>

Spring boot 1.4.1版本下,jedis的版本默认是2.8.2,所以我们不需要指定版本,太低的版本的jedis的jar包有一些bug,尽量使用2.0.8+的版本,引入commons-langs,该包有一系列的工具类,如: StringUtils,NumberUtils等,阿里的fastjson相较于Jackson使用起来更加方便
在spring boot项目中的application.properties配置redis信息

redis.shard.servers=ip地址:端口,ip地址:端口
redis.shard.timeout=5000
#最多分配多少个shardJedis实例,默认为8个,设置为-1表示不限制个数
redis.shard.maxTotal=32 

配置好Redis之后,在spring boot中集成分片版的jedis,JedisShardConfig类代码如下:

package com.stscode.common.configure;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedisPool;

import java.util.ArrayList;
import java.util.List;

public class JedisShardConfig {

    //spring boot配置环境对象
    @Autowired
    private Environment env;

    /*
        创建jedis池
     */
    public ShardedJedisPool shardedJedisPool(){
        //获取配置的服务器ip列表
        String[] serverIp = env.getProperty("redis.shard.servers").split(",");
        int timeout = Integer.valueOf(env.getProperty("redis.shard.timeout"));
        int maxTotal = Integer.valueOf(env.getProperty("redis.shard.maxTotal"));
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); //创建jedis池配置信息
        jedisPoolConfig.setMaxTotal(maxTotal); //设置最大jedis实例数量

        //每一个JedisShardInfo就是一个服务器的redis实例
        List<JedisShardInfo> jedisList = new ArrayList<JedisShardInfo>();
        for (String server : serverIp) {
            //将服务器地址和端口分开
            String[] ipAndPort = server.split(":");
            //构建jedis连接资源
            JedisShardInfo jedisShardInfo = new JedisShardInfo(ipAndPort[0] , Integer.valueOf(ipAndPort[1]));
            jedisShardInfo.setConnectionTimeout(timeout); //设置超时时间
            jedisList.add(jedisShardInfo);
        }
        return new ShardedJedisPool(jedisPoolConfig , jedisList);//构建jedis池
    }


}

构建的pool就是之后进行redis操作时获取连接的地方,其中在pool中可以同时获取多少个shardJedisPool,由maxTotal配置而定(ps: 如果不想让这些业务都共用几台redis服务器,可以创建多个ShardJedisPool,在每个pool中放置不同的服务器,之后不同的业务使用不同的ShardJedisPool)

然后,创建一个操作redis的工具类RedisUtils.代码如下:

package com.stscode.common.configure.utils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

@Component
public class RedisUtils {

    //redis池
    private ShardedJedisPool pool;

    /**
     * 存入redis数据库
     * @param key
     * @param value
     */
    public void setData(String key , String value){

        ShardedJedis jedis = null;
        try {
            if (pool != null) {
                //获取redis资源
                jedis = pool.getResource();
                if (jedis != null) {
                    jedis.set(key, value);
                }
            }
        }catch(Exception ex){}
        finally{
            if(jedis!=null){
                jedis.close();
            }
        }
    }

    /**
     * 从redis获取string数据
     * @param key
     * @return
     */
    public String getData(String key){
        ShardedJedis jedis = null;
            try{
                if (pool!=null){
                jedis = pool.getResource();
                if (jedis!=null){
                    return jedis.get(key); //从缓存服务器中获取string数据
                }
            }
        }catch(Exception ex){}
        finally {
            if (jedis!=null){
                jedis.close();
            }
        }
        return StringUtils.EMPTY;
    }
}

其他的数据结构可以自行在工具类中定义,首先先在方法中获取ShardedJedis,可以理解为操作Redis的一个连接,之后使用该连接进行数据库的操作,无论操作成功与否,都要将shardedJedis资源关闭

编写一个缓存前缀指定类DbAndCacheContants,代码:

package com.stscode.common.configure;

/**
 * 前缀类
 */
public class DbAndCacheContants {
    public static final String USER_CACHE_PREFIX = "user:";
}

在该类中指定缓存前缀,重要的作用是放置缓存key冲突和增强语义,一看缓存key就知道缓存是做什么的,缓存的key中不同的单词之间用:分隔,这是redis推荐做法,如果以:分隔的话,在rdm中我们可以看到key是按照:来分层显示的

编写service层代码,如UserService:

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.domain.User;
import com.stscode.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

    @Autowired
    private IUserDao userDao;

    @Autowired
    private RedisUtils redisUtils;

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

    /**
     * 根据用户id查询用户数据
     * @param id
     * @return
     */
    public User getUser(Long id){
        String data = redisUtils.getData(DbAndCacheContants.USER_CACHE_PREFIX + id);
        //如果获取的数据不为空,将该数据返回
        if (data!=null){
            return JSON.parseObject(data , User.class);
        }
        //如果为空,从数据库中获取,并存入redis中
        User user = userDao.selectByPrimaryKey(id);
        //如果获取的用户信息对象不为空,存入reids中
        if (user!=null) {
            redisUtils.setData(DbAndCacheContants.USER_CACHE_PREFIX + id, JSON.toJSONString(user));
        }
        return user;
    }
}

最后编写Controller类的方法并调用该service中的方法即可

 类似资料: