redis集群的总结、搭建、 springboot整合测试

redis集群的总结、搭建、 springboot整合测试

redis集群的相关总结,测试,springboot整合

一,redis集群总结:主从模式、哨兵模式和Cluster集群

  1. 主从模式:一主多从,不能自动切换主,每台都是全量日志
  2. 哨兵模式:一主多从,主有故障的时候,哨兵投票切换主,是主从模式的升级版,切换主的时候,是不可用状态,每台都是全量日志
  3. Cluster集群:推荐是3主3从,工作方式:key–槽位—节点, 每台只保存该槽位的key, 故障案例:主2挂的时候,从2去顶替,这时候,该节点对应的key可读不可写,如果主2和从2都挂了,整个集群不可用

二,Cluster集群搭建

1.开三台虚拟机,系统为CentOS 7.6 64位。先配置好第一台的环境(安装好redis和集群配置,没有gcc的,需要安装gcc,下面的步骤是配置详情),其余两台克隆即可!

在这里插入图片描述

2.安装redis,本人用的redis-7.0.14.tar.gz版本
  1. 检查是否安装了gcc(redis的编译需要它):gcc -v ,没有的话先安装这个:yum install gcc-c++
  2. 创建工作目录,比如/usr/local/redis,把reids包放进去,并解压:tar -zxvf redis-7.0.14.tar.gz
  3. 进入到解压后的目录(redis-7.0.14)进行编译:make
  4. 进入redis-7.0.14/src 文件目录下进行安装:make install
3.添加集群的配置,比如3主3从的端口分配为:8001,8002,8003,8004,8005,8006
  1. 创建工作目录,比如/usr/local/redis-cluster-work
  2. 在redis-cluster-work里创建2个工作目录,8001和8002
  3. 在8001里面,创建redis.conf配置文件:touch redis.conf
  4. 编写redis.conf文件(vim redis.conf),内容如下,写完之后wq保存:
# 修改为后台启动
daemonize yes
# 修改端口号
port 8001
# 指定数据文件存储位置
dir /usr/local/redis-cluster-work/8001/
# 开启集群模式
cluster-enabled yes
# 集群节点信息文件配置
cluster-config-file nodes-8001.conf
# 集群节点超时间
cluster-node-timeout 15000
# 去掉bind绑定地址
# bind 127.0.0.1 
# 关闭保护模式
protected-mode no
# 开启aof模式持久化
appendonly yes
# 设置连接Redis需要密码123(选配)
requirepass 123456
# 设置Redis节点与节点之间访问需要密码123(选配)
masterauth 123456

**如果是云服务器,需要改一下配置,因为云服务器涉及到公私地址的问题,上面的配置会发生连接的公网地址,当时集群内找的是内部地址
cluster-announce-ip 公网地址
bind 0.0.0.0
在这里插入图片描述

  1. 把这个文件,复制到8002的目录,修改里面端口为本目录的端口
  2. 关闭防护墙(为了测试方便,开着的情况需要放开这6个端口,并且放开这6个端口加10000之后的端口,加1万的端口是通信端口):systemctl stop firewalld
  3. 克隆2台,并修改配置文件为对应的端口
  4. 把这六台redis启动:
redis-server /usr/local/redis-cluster-work/8001/redis.conf
redis-server /usr/local/redis-cluster-work/8002/redis.conf

redis-server /usr/local/redis-cluster-work/8003/redis.conf
redis-server /usr/local/redis-cluster-work/8004/redis.conf

redis-server /usr/local/redis-cluster-work/8005/redis.conf
redis-server /usr/local/redis-cluster-work/8006/redis.conf
  1. 启动之后,用ps -ef | grep redis验证一下,集群启动是带[cluster]标志的:
[root@localhost 8005]# ps -ef | grep redis
root      18478      1  0 08:45 ?        00:01:11 redis-server *:8005 [cluster]
root      18484      1  0 08:45 ?        00:01:11 redis-server *:8006 [cluster]
root      22963  18402  0 15:10 pts/1    00:00:00 grep --color=auto redis

  1. 至此6台redis已启动成功,下面开始启动集群(咱这是5.0之上的版本,用客户端操作即可):
10.1随机主从分配的方式:
redis-cli -a 123456 --cluster create --cluster-replicas 1 192.168.208.128:8001 192.168.208.128:8002 192.168.208.129:8003 192.168.208.129:8004 192.168.208.130:8005 192.168.208.130:8006
10.2指定主从分配的方式,需要先指定3台主,然后再指定3台从(需要主的id):

先指定3台主

redis-cli -a 123456 --cluster create  192.168.208.128:8001 192.168.208.129:8003 192.168.208.130:8005
[root@localhost redis-cluster-work]# redis-cli -a 123456 --cluster create  192.168.208.128:8001 192.168.208.129:8003 192.168.208.130:8005
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 3 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
M: 21bd38c67330b802ee88b7fe0843509aa2afb2ad 192.168.208.128:8001
   slots:[0-5460] (5461 slots) master
M: eeb3577336a2d9ade1a195364abca9e96e3cbf30 192.168.208.129:8003
   slots:[5461-10922] (5462 slots) master
M: a2e8be14c508ad72c62a0efb3ee96386188fb626 192.168.208.130:8005
   slots:[10923-16383] (5461 slots) master
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join

>>> Performing Cluster Check (using node 127.0.0.1:8001)
M: 21bd38c67330b802ee88b7fe0843509aa2afb2ad 192.168.208.128:8001
   slots:[0-5460] (5461 slots) master
M: a2e8be14c508ad72c62a0efb3ee96386188fb626 192.168.208.130:8005
   slots:[10923-16383] (5461 slots) master
M: eeb3577336a2d9ade1a195364abca9e96e3cbf30 192.168.208.129:8003
   slots:[5461-10922] (5462 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost redis-cluster-work]# 


再指定3台从,里面的21bd38c67330b802ee88b7fe0843509aa2afb2ad是主的id,通过CLUSTER NODES可以查看每台的id:

[root@localhost redis-cluster-work]# redis-cli -a 123456 -c -h 192.168.208.128 -p 8001
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.208.128:8001> cluster nodes
a2e8be14c508ad72c62a0efb3ee96386188fb626 192.168.208.130:8005@18005 master - 0 1706938093285 3 connected 10923-16383
eeb3577336a2d9ade1a195364abca9e96e3cbf30 192.168.208.129:8003@18003 master - 0 1706938092282 2 connected 5461-10922
21bd38c67330b802ee88b7fe0843509aa2afb2ad 192.168.208.128:8001@18001 myself,master - 0 1706938092000 1 connected 0-5460
192.168.208.128:8001> 

redis-cli  -a 123456 --cluster add-node 192.168.208.128:8002 192.168.208.128:8001 --cluster-slave --cluster-master-id 21bd38c67330b802ee88b7fe0843509aa2afb2ad

说明:上述命令把8002节点加入到8001节点(这里任意写一个集群中节点的端口即可)的集群中,并且当做node_id为21bd38c67330b802ee88b7fe0843509aa2afb2ad的从节点。如果不指定 --cluster-master-id 会随机分配到任意一个主节点

[root@localhost redis-cluster-work]# redis-cli  -a 123456 --cluster add-node 192.168.208.128:8002 192.168.208.128:8001 --cluster-slave --cluster-master-id 21bd38c67330b802ee88b7fe0843509aa2afb2ad
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Adding node 192.168.208.128:8002 to cluster 192.168.208.128:8001
>>> Performing Cluster Check (using node 192.168.208.128:8001)
M: 21bd38c67330b802ee88b7fe0843509aa2afb2ad 192.168.208.128:8001
   slots:[0-5460] (5461 slots) master
M: a2e8be14c508ad72c62a0efb3ee96386188fb626 192.168.208.130:8005
   slots:[10923-16383] (5461 slots) master
M: eeeb3577336a2d9ade1a195364abca9e96e3cbf30 192.168.208.129:8003
   slots:[5461-10922] (5462 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
>>> Send CLUSTER MEET to node 192.168.208.128:8002 to make it join the cluster.
Waiting for the cluster to join

>>> Configure node as replica of 192.168.208.130:8005.
[OK] New node added correctly.
[root@localhost redis-cluster-work]# 

  1. 至此集群已配置好,下面的命令,可以查看集群情况:

11.1查看集群信息:redis-cli -a 123456 --cluster info 192.168.208.128:8001

[root@localhost src]# redis-cli -a 123456 --cluster info 192.168.208.128:8001
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
192.168.208.128:8001 (21bd38c6...) -> 0 keys | 5461 slots | 1 slaves.
192.168.208.130:8005 (35dabf60...) -> 0 keys | 5461 slots | 1 slaves.
192.168.208.129:8003 (29b2688d...) -> 0 keys | 5462 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.

11.2连接集群

# -a 密码认证
# -c 连接集群
# -h 集群中任意一个Redis节点IP
# -p 集群中任意一个Redis节点端口
redis-cli -a 123456 -c -h 192.168.208.128 -p 8001

11.3登录到客户端之后的查看集群信息:CLUSTER INFO

192.168.208.128:8001> CLUSTER INFO
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:23854
cluster_stats_messages_pong_sent:25111
cluster_stats_messages_fail_sent:5
cluster_stats_messages_sent:48970
cluster_stats_messages_ping_received:25111
cluster_stats_messages_pong_received:23853
cluster_stats_messages_fail_received:2
cluster_stats_messages_received:48966
total_cluster_links_buffer_limit_exceeded:0

11.4登录到客户端之后的查看集群信息:CLUSTER NODES

192.168.208.128:8001> CLUSTER NODES
21bd38c67330b802ee88b7fe0843509aa2afb2ad 192.168.208.128:8001@18001 myself,master - 0 1704871951000 1 connected 0-5460
febaa75d1df7fe08abf2ac2a3a21331efc883540 192.168.208.128:8002@18002 slave 35dabf604f98dc37da4b1d231b77dd362310901c 0 1704871950374 5 connected
77e839b6c51d92bb98afd6aa84087a9b183a8661 192.168.208.130:8006@18006 slave 29b2688d2fed7f3cdc40b2743f852dc4e5451a67 0 1704871949000 3 connected
35dabf604f98dc37da4b1d231b77dd362310901c 192.168.208.130:8005@18005 master - 0 1704871951403 5 connected 10923-16383
300713f6e6fdd1007131ac82b2f40b194e3e7651 192.168.208.129:8004@18004 slave 21bd38c67330b802ee88b7fe0843509aa2afb2ad 0 1704871950000 1 connected
29b2688d2fed7f3cdc40b2743f852dc4e5451a67 192.168.208.129:8003@18003 master - 0 1704871952425 3 connected 5461-10922

  1. 集群伸缩,比如增加2个节点,一主一从,需要先把主添加到集群,然后再分配槽位,最后把从加入到主,具体命令以后更新~~

三, springboot整合测试

先说一下客户端:Jedis 和 Lettuce 是 Java 操作 Redis 的客户端,在 Spring Boot 1.x 版本默认使用的是 jedis ,而在 Spring Boot 2.x 版本默认使用的就是Lettuce:

  1. Jedis 非线程安全的,配合连接池使用,为每个Jedis实例增加物理连接,可以达到多线程使用的目的
  2. Lettuce 基于Netty的,线程安全的

那么,整合测试是这两种客户端都实现,并对比测试情况

1, springboot整合之Jedis客户端方式

项目依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

配置文件

#RedisCluster集群节点及端口信息
spring.redis.cluster.nodes=192.168.208.128:8001,192.168.208.128:8002,192.168.208.129:8003,192.168.208.129:8004,192.168.208.130:8005,192.168.208.130:8006
#Redis密码
spring.redis.cluster.password=123456
#redis cluster只使用db0
spring.redis.cluster.index=0
#以毫秒为单位的连接超时时间
spring.redis.cluster.timeout=10000
#在群集中执行命令时要遵循的最大重定向数目
spring.redis.cluster.max-redirects=5
#Redis连接池在给定时间可以分配的最大连接数。使用负值无限制
spring.redis.cluster.jedis.pool.max-active=1000
#池中“空闲”连接的最大数量。使用负值表示无限数量的空闲连接
spring.redis.cluster.jedis.pool.max-idle=8
#目标为保持在池中的最小空闲连接数。这个设置只有在设置max-idle的情况下才有效果
spring.redis.cluster.jedis.pool.min-idle=5
#连接分配在池被耗尽时抛出异常之前应该阻塞的最长时间量(以毫秒为单位)。使用负值可以无限期地阻止
spring.redis.cluster.jedis.pool.max-wait=1000

下面是三个配置类

读配置文件的ClusterRedisProperties类:


import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


@Component
public class ClusterRedisProperties {
    @Value("${spring.redis.cluster.timeout}")
    private Integer redisTimeout;
    @Value("${spring.redis.cluster.jedis.pool.max-active}")
    private Integer poolMaxActive;
    @Value("${spring.redis.cluster.jedis.pool.max-idle}")
    private Integer poolMaxIdle;
    @Value("${spring.redis.cluster.jedis.pool.min-idle}")
    private Integer poolMinIdle;
    @Value("${spring.redis.cluster.jedis.pool.max-wait}")
    private Integer poolMaxWait;
    @Value("${spring.redis.cluster.nodes}")
    private String clusterNodes;
    @Value("${spring.redis.cluster.max-redirects}")
    private Integer clusterMaxRedirects;
    @Value("${spring.redis.cluster.password}")
    private String password;


    public Integer getRedisTimeout() {
        return redisTimeout;
    }

    public void setRedisTimeout(Integer redisTimeout) {
        this.redisTimeout = redisTimeout;
    }

    public Integer getPoolMaxActive() {
        return poolMaxActive;
    }

    public void setPoolMaxActive(Integer poolMaxActive) {
        this.poolMaxActive = poolMaxActive;
    }

    public Integer getPoolMaxIdle() {
        return poolMaxIdle;
    }

    public void setPoolMaxIdle(Integer poolMaxIdle) {
        this.poolMaxIdle = poolMaxIdle;
    }

    public Integer getPoolMinIdle() {
        return poolMinIdle;
    }

    public void setPoolMinIdle(Integer poolMinIdle) {
        this.poolMinIdle = poolMinIdle;
    }

    public Integer getPoolMaxWait() {
        return poolMaxWait;
    }

    public void setPoolMaxWait(Integer poolMaxWait) {
        this.poolMaxWait = poolMaxWait;
    }

    public String getClusterNodes() {
        return clusterNodes;
    }

    public void setClusterNodes(String clusterNodes) {
        this.clusterNodes = clusterNodes;
    }

    public Integer getClusterMaxRedirects() {
        return clusterMaxRedirects;
    }

    public void setClusterMaxRedirects(Integer clusterMaxRedirects) {
        this.clusterMaxRedirects = clusterMaxRedirects;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

装配Bean(JedisCluster实例)的JedisClusterConfig类:


import org.springframework.beans.factory.annotation.Autowired;
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;

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

@Configuration
public class JedisClusterConfig {
    @Autowired
    private ClusterRedisProperties redisProperties;

    @Bean
    public JedisCluster getJedisCluster() {
        String[] serverArray = redisProperties.getClusterNodes().split(",");
        Set<HostAndPort> nodes = new HashSet<>();

        for (String ipPort : serverArray) {
            String[] ipPortPair = ipPort.split(":");
            nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim())));

        }

        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(redisProperties.getPoolMaxActive());
        config.setMaxIdle(redisProperties.getPoolMaxIdle());
        config.setMinIdle(redisProperties.getPoolMinIdle());
        config.setMaxWaitMillis(redisProperties.getPoolMaxWait());
        config.setTestOnBorrow(true);

        if (redisProperties.getPassword() == null || "".equals(redisProperties.getPassword())) {
            return new JedisCluster(nodes, redisProperties.getRedisTimeout(), redisProperties.getRedisTimeout(), redisProperties.getClusterMaxRedirects(), config);
        }else {
            return new JedisCluster(nodes, redisProperties.getRedisTimeout(), redisProperties.getRedisTimeout(), redisProperties.getClusterMaxRedirects(), redisProperties.getPassword(), config);
        }
    }

}


自定义的工具类RedisClientTemplate:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisCluster;


@Service
public class RedisClientTemplate {
    private static final Logger log = LoggerFactory.getLogger(RedisClientTemplate.class);

    @Autowired
    private JedisCluster jedisCluster;

    public boolean setToRedis(String key, Object value) {
        try {
            String str = jedisCluster.set(key, String.valueOf(value));
            if ("OK".equals(str))
                return true;
        } catch (Exception ex) {
            log.error("setToRedis:{Key:" + key + ",value" + value + "}", ex);
        }
        return false;
    }

    public Object getRedis(String key) {
        String str = null;
        try {
            str = jedisCluster.get(key);
        } catch (Exception ex) {
            log.error("getRedis:{Key:" + key + "}", ex);
        }
        return str;
    }

}

测试的3个类:
Test02多线程并发测试
Test03单线程下写5000个String测试耗时
Test04单线程下读5000个String测试耗时

import com.wd.testRedisCluster.util.SpringUtil;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Test02 {
    private final static ExecutorService executorServiceHandlerData = Executors.newFixedThreadPool(200);

    public static void test() {
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        RedisClientTemplate redisClientTemplate = SpringUtil.getBean("redisClientTemplate", RedisClientTemplate.class);
        for (int i = 1; i <= 5000; i++) {
            final Integer index = i;
            executorServiceHandlerData.submit(new Runnable() {
                @Override
                public void run() {
                    try {

                        System.out.println("t" + index + "设置结果:" + redisClientTemplate.setToRedis("t" + index, new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())));
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("第" + index + "次异常");
                    }
                }
            });
        }


        try {
            executorServiceHandlerData.shutdown();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }
}

import com.wd.testRedisCluster.util.SpringUtil;
import java.text.SimpleDateFormat;
import java.util.Date;


public class Test03 {

    public static void test() {
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        RedisClientTemplate redisClientTemplate = SpringUtil.getBean("redisClientTemplate", RedisClientTemplate.class);
        long begin = System.currentTimeMillis();
        for (int i = 1; i <= 5000; i++) {
            final Integer index = i;
            redisClientTemplate.setToRedis("t" + index, new SimpleDateFormat("HH:mm:ss.SSS").format(new Date()));
//            System.out.println("t" + index + "设置结果:" + redisClientTemplate.setToRedis("t" + index, new SimpleDateFormat("HH:mm:ss.SSS").format(new Date())));
        }
        System.out.println("存储完成耗时:" + (System.currentTimeMillis() - begin) + "毫秒");


    }
}

import com.wd.testRedisCluster.util.SpringUtil;

public class Test04 {
    
    public static void test() {
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        RedisClientTemplate redisClientTemplate = SpringUtil.getBean("redisClientTemplate", RedisClientTemplate.class);
        long begin = System.currentTimeMillis();
        for (int i = 1; i <= 5000; i++) {
            System.out.println("t" + i + "获取结果:"  +redisClientTemplate.getRedis("t" + i));
        }
        System.out.println("读取完成耗时:" + (System.currentTimeMillis() - begin) + "毫秒");
        
    }
}

启动主类中测试


import com.wd.testRedisCluster.config.Test02;
import com.wd.testRedisCluster.config.Test03;
import com.wd.testRedisCluster.config.Test04;
import com.wd.testRedisCluster.util.GlobalUtil;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;



@SpringBootApplication
public class StartMain {


    public static void main(String[] args) {
        //自定义配置文件路径
        new SpringApplicationBuilder(StartMain.class)
                .properties("spring.config.location=file:" + GlobalUtil.getProperty() + "application.properties")
                .build()
                .run(args);



//        Test02.test();
        Test03.test();
//        Test04.test();

    }
}

2, springboot整合之lettuce客户端方式

依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
<!--            <version>2.3.4.RELEASE</version>-->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- lettuce pool 缓存连接池-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.50.Final</version>
        </dependency>

        <!--添加fastjson包-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.16.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.16.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.16.1</version>
        </dependency>

配置文件

spring.redis.cluster.nodes=192.168.208.128:8001,192.168.208.128:8002,192.168.208.129:8003,192.168.208.129:8004,192.168.208.130:8005,192.168.208.130:8006
#Redis密码
spring.redis.password=123456
#redis cluster只使用db0
spring.redis.cluster.index=0
#在群集中执行命令时要遵循的最大重定向数目
spring.redis.cluster.max-redirects=5
#以毫秒为单位的连接超时时间
spring.redis.timeout=10000



#Redis连接池在给定时间可以分配的最大连接数。使用负值无限制
spring.redis.lettuce.pool.max-active=1000
#池中“空闲”连接的最大数量。使用负值表示无限数量的空闲连接
spring.redis.lettuce.pool.max-idle=8
#目标为保持在池中的最小空闲连接数。这个设置只有在设置max-idle的情况下才有效果
spring.redis.lettuce.pool.min-idle=5
#连接分配在池被耗尽时抛出异常之前应该阻塞的最长时间量(以毫秒为单位)。使用负值可以无限期地阻止
spring.redis.lettuce.pool.max-wait=1000

配置类RedisConfig

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;



@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisSerializer<Object> serializer = redisSerializer();
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public RedisSerializer<Object> redisSerializer() {
        // 创建JSON序列化器
        Jackson2JsonRedisSerializer<Object> serializer =
                new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 必须设置,否则无法将json转化为对象,会转化为Map类型
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(objectMapper);
        return serializer;
    }
}

剩下的就是3个测试类了
Test02多线程并发测试
Test03单线程下写5000个String测试耗时
Test04单线程下读5000个String测试耗时

import com.wd.testRedisCluster.util.SpringUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Test02 {
    private final static ExecutorService executorServiceHandlerData = Executors.newFixedThreadPool(200);

    public static void test() {
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        StringRedisTemplate redisClientTemplate = SpringUtil.getBean("stringRedisTemplate", StringRedisTemplate.class);
        for (int i = 1; i <= 5000; i++) {
            final Integer index = i;
            executorServiceHandlerData.submit(new Runnable() {
                @Override
                public void run() {
                    try {

                        redisClientTemplate.opsForValue().set("t" + index, new SimpleDateFormat("HH:mm:ss.SSS").format(new Date()));
                        System.out.println("t" + index + "设置结果:true"  );
                    } catch (Exception e) {
                        e.printStackTrace();
                        System.out.println("第" + index + "次异常");
                    }
                }
            });
        }


        try {
            executorServiceHandlerData.shutdown();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }
}

import com.wd.testRedisCluster.util.SpringUtil;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Test03 {
    
    public static void test() {
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        StringRedisTemplate redisClientTemplate = SpringUtil.getBean("stringRedisTemplate", StringRedisTemplate.class);
        long begin = System.currentTimeMillis();
        for (int i = 1; i <= 5000; i++) {
            redisClientTemplate.opsForValue().set("t" + i, new SimpleDateFormat("HH:mm:ss.SSS").format(new Date()));
//            System.out.println("t" + i + "设置结果:true"  );
        }
        System.out.println("存储完成耗时:" + (System.currentTimeMillis() - begin) + "毫秒");
    }
}

import com.wd.testRedisCluster.util.SpringUtil;
import org.springframework.data.redis.core.StringRedisTemplate;


public class Test04 {

    public static void test() {
        try {
            Thread.sleep(8000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        StringRedisTemplate redisClientTemplate = SpringUtil.getBean("stringRedisTemplate", StringRedisTemplate.class);
        long begin = System.currentTimeMillis();
        for (int i = 1; i <= 5000; i++) {
            System.out.println("t" + i + "获取结果:"  +redisClientTemplate.opsForValue().get("t" + i));
        }
        System.out.println("读取完成耗时:" + (System.currentTimeMillis() - begin) + "毫秒");
        
    }
}

启动类中测试:

import com.wd.testRedisCluster.config.Test02;
import com.wd.testRedisCluster.config.Test03;
import com.wd.testRedisCluster.config.Test04;
import com.wd.testRedisCluster.util.GlobalUtil;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;




@SpringBootApplication
public class StartMain  {

    public static void main(String[] args) {
        //自定义配置文件路径
        new SpringApplicationBuilder(StartMain.class)
                .properties("spring.config.location=file:" + GlobalUtil.getProperty() + "application.properties")
                .build()
                .run(args);


//        Test02.test();
        Test03.test();
//        Test04.test();

    }
}

3, 两种客户端操作的对比:
test02中线程并发,都支持,虽然jedis是线程不安全的,但是它有连接池
test03中写的测试,lettuce比jedis快
次数jedislettuce
1次3026毫秒2769毫秒
2次3419毫秒3208毫秒
3次2891毫秒3188毫秒
4 次3358毫秒3151毫秒
5次3326毫秒3039毫秒
6 次3216毫秒2958毫秒
7次3438毫秒3107毫秒
8次3532毫秒3125毫秒
9次3397毫秒3169毫秒
10次3372毫秒3098毫秒
test04中写的测试,lettuce比jedis快,结果就不贴了
4, 两种客户端操作的选择:lettuce的,速度快,不用自己去读配置然后再装配,也不用自己去定义使用类,跟单机版完美结合,用StringRedisTemplate即可,只需要搭建集群环境和更改配置文件即可
5,项目附上
  • 14
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
天猫商城是一个基于SSM框架的综合性B2C电商平台,需求设计主要参考天猫商城的购物流程:用户从注册开始,到完成登录,浏览商品,加入购物车,进行下单,确认收货,评价等一系列操作。 作为模拟天猫商城系统的核心组成部分之一,采用SSM框架的天猫数据管理后台包含商品管理,订单管理,类别管理,用户管理和交易额统计等模块,实现了对整个商城的一站式管理和维护。本课程是一门专业的Java微服架构开发实战课程,主要讲解了当下流行的SpringBoot框架、SpringCloud架构以及与第三方技术整合开发实战内容。通过本课程的学习,能够理解并掌握SpringBoot的基础知识,同时能够掌握SpringBoot与常用的第三方技术整合实现实际开发中的业务需求,包括实现Web开发、数据访问、缓存管理、安全管理、消息服务、任务管理等;了解并掌握SpringCloud微服务架构的基础知识及相关组件的应用,掌握微服务架构在企业级开发的实践,建立起微服架构思想。项目技术栈:采用SpringBoot简化商城系统的初始搭建以及开发过程采用SpringMVC+Spring+IBatis完成项目的整合采用Mysql作为数据库存储,Druid配置数据库连接池采用SpringCloud+Netflix 微服务技术栈的实战开发使用Redis完成缓存的数据存储,搭建Redis搭建主从、哨兵、集群应用,保证Redis的高可用使用ElasticSearch全文检索系统进行商品数据搜索,使用ElasticSearch搭建搜索服务的高可用使用Ngnix实现页面动静分离与负载均衡的配置采用FastDFS文件储存系统文件存储,完成广告图片、商品图片的上传和存储系统使用采用CAS+shiro单点登录系统实现用户认证使用ECharts根据后台查询数据生成图表使用POI实现了商城盈利状况的Excel表格导出。商品的详情页使用Thymeleaf完成页面静态化,减少页面数据展示延迟项目中使用SpringBoot下的Aop + 自定义注解完成用户行为记录,日志采集后台管理系统使用Shiro实现登录验证和权限管理(超级管理员、管理员、产品编辑员)项目整合微信完成订单的支付使用Redission完成分布式锁,生成订单的编号使用SpringCloud Alibaba Seat完成下订单模块的分布式事务(新增订单表,库存减少,库存超卖设计)使用RabbitMQ 做消息队列,完成订单未支付自动取消和模块直接的解耦合使用Quartz任务调度,完成缓存的定时刷新,保证缓存的一致性使用本地消息表机制完成消息然队列RabbitMQ消息可靠性传输订单支付模块使用微信扫码支付,并设置订单超时自动取消通过Jquery实现前端校验,通过基于Hibernate的Valida注解实现后端的校验功能使用Base64编码对Json数据传输进行编码和解码项目使用RESTful设计风格实现资源的访问,实现前后端分离项目使用聚合数据第三方短信平台完成用户的登陆功能项目使用SpringBoot整合JavaMail完成邮件的发送项目使用SpringBoot整合Swagger2生成接口文档使用PostMan完成接口的测试项目的测试:SpringTest、dbunit、EasyMock使用Docker 进行应用的自动化打包和发布、自动化测试和持续集成、部署和调整其他应用使用 PowerDesigner,完成数据库的建模项目使用禅道进行BUG管理环境采用Maven实施多模块项目构建,采用Git进行项目版本管理 架构解读:  项目部分截图:              讲义部分截图:          
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值