Redis 单机,哨兵,集群模式

        redis的搭建,我是使用docker方式部署。

        首先拉取镜像  

docker pull redis

主从,哨兵,集群的区别 

特性/配置Redis 主从复制Redis 哨兵Redis 集群
主要目的数据备份与读写分离高可用性和故障自动切换高并发和数据分散处理
架构一个主节点和多个从节点监控主从结构并自动切换多个主节点,数据分片
数据复制主节点到从节点监控并管理主从复制每个主节点管理自己的数据集
故障转移机制手动或哨兵自动切换自动故障转移自动处理节点故障
可伸缩性有限,依赖主节点为主从结构增加高可用性高,因为数据分布式处理
使用场景数据备份和读扩展关键应用的高可用性大规模应用的高性能需求
设置复杂度相对简单中等,需配置哨兵复杂,需规划数据分区

JedisConnectionFactory和LettuceConnectionFactory区别

     JedisConnectionFactory和LettuceConnectionFactory区别
     1. 连接方式
     Lettuce 采用 Netty 底层网络框架,使用异步非阻塞式 IO 模型,支持多个 Redis 节点的连接池复用,适合高并发场景。
     Jedis 采用传统的阻塞 IO 模型,每个 Redis 节点需要维护一个连接池,适合低并发场景。
     2. 线程安全性
     Lettuce 是线程安全的,可以在多线程环境下共享连接,而 Jedis 不是线程安全的,需要使用连接池进行连接复用。
      在 Spring Boot 中配置 Redis 哨兵模式使用 Lettuce 和Jedis 作为 Redis 客户端的步骤分别如下。 推荐使用Lettuce 方式配置。

1.单机模式

        启动redis服务

#方式一:无密码
docker run --name=redies-server -p 6379:6379 -d redis

#方式二:有密码认证
docker run --name=redies-server -p 6379:6379 -d redis --requirepass 123456

#方式三:自定义配置,--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
docker run --name=redies-server-master -p 6379:6379 --net=host -v $PWD/redis-master.conf:/etc/redis/redis-master.conf -d redis /etc/redis/redis-master.conf

   redis-master.conf配置文件  

#绑定端口
port 6379

#设置指定的日志
logfile "redis-6379.log"

#Redis持久化擦用aof文件增量增加的方式
appendonly yes

appendfilename appendonly.aof

#设置主节点(master)认证的密码
masterauth 123456

#设置认证密码
requirepass 123456

1.1 SpringBoot连接单机Redis 

SpringBoot方式使用Redis,直接使用RedisTemplete注入即可。SpringBoot配置如下

# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.31.59
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=123456
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=1000

2.哨兵模式

        Redis的主从模式是一种部署多个Redis节点的方式,其中一个节点作为主节点(Master),其他节点作为从节点(Slave)。在这种模式下,主节点负责处理数据的事务性操作(如增删改),而从节点则主要用于提供读取操作。所有从节点的数据都是从主节点同步过来的。属于读写分离。

        哨兵模式相对于主从模式,只是在主从模式的基础上增加了哨兵,实现了主节点宕机的情况下自动实将某一从节点转换成主节点。我这里使用1主2从2哨兵方式。

2.1 主从配置

1. redis-master.conf

#绑定端口
port 6379

#设置指定的日志
logfile "redis-6379.log"

#Redis持久化擦用aof文件增量增加的方式
appendonly yes

appendfilename appendonly.aof

#设置主节点(master)认证的密码
masterauth 123456

#设置认证密码
requirepass 123456

    2. redis-slave1.conf    

replicaof是新版本的命令,旧版本是slaveof命令,redis高版本向下兼容旧版命令

#绑定端口
port 6380
 
#设置指定的日志
logfile "redis-6380.log"
 
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
 
appendfilename appendonly.aof
 
 

# 配置master节点信息
# 格式:slaveof <masterip> <masterport>
##<masterip> 是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名.
#<redis-port> 是被监控节点所监听的端口号
#salveof-read-only  yes   #表示只读,replicaof-read-only   yes    #表示只读,replicaof 192.168.31.59 6379
slaveof 192.168.31.59 6379
 
#设置主节点(master)认证的密码
masterauth 123456
 
#设置认证密码
requirepass 123456

  3. redis-slave2.conf    

#绑定端口
port 6381
 
#设置指定的日志
logfile "redis-6381.log"
 
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
 
appendfilename appendonly.aof
 
 

# 配置master节点信息
# 格式:slaveof <masterip> <masterport>
##<masterip> 是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名.
#<redis-port> 是被监控节点所监听的端口号
#salveof-read-only  yes   #表示只读,replicaof-read-only   yes    #表示只读,replicaof 192.168.31.59 6379
slaveof 192.168.31.59 6379
 
#设置主节点(master)认证的密码
masterauth 123456
 
#设置认证密码
requirepass 123456

然后启动主从redis容器:

docker run --name=redies-server-master -p 6379:6379 -v $PWD/redis-master.conf:/etc/redis/redis-master.conf -d redis /etc/redis/redis-master.conf

docker run --name=redies-server-slave1 -p 6380:6380 -v $PWD/redis-slave1.conf:/etc/redis/redis-slave1.conf -d redis /etc/redis/redis-slave1.conf

docker run --name=redies-server-slave2 -p 6381:6381 -v $PWD/redis-slave2.conf:/etc/redis/redis-slave2.conf -d redis /etc/redis/redis-slave2.conf

 进入主节点容器,输入redis-cli 连接主节点的redis 输入info relication命令查看信息:

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L215bGk5Mg==,size_16,color_FFFFFF,t_70

这里两个从节点的发现ip并不是主机的IP,而是docker容器的IP地址。所以通过查看容器信息docker inspect redies-server-slave2。发现创建容器时未设置网路,默认使用了docker的桥接模式

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L215bGk5Mg==,size_16,color_FFFFFF,t_70

 修改创建容器的命令在创建容器时增加参数--net=host,network_mode设置host模式,就不需要设置ports。

host:使用宿主机网络接口功能与port映射同时使用,逻辑比较容易理解,本身已经使用了本地网络,所有端口是与宿主机同步,再作端口映射是本机映射到本机。network_mode的host模式和ports是互斥的

再次启动容器

docker run --name=redies-server-master --net=host -v $PWD/redis-master.conf:/etc/redis/redis-master.conf -d redis /etc/redis/redis-master.conf

docker run --name=redies-server-slave1  --net=host -v $PWD/redis-slave1.conf:/etc/redis/redis-slave1.conf -d redis /etc/redis/redis-slave1.conf

docker run --name=redies-server-slave2  --net=host -v $PWD/redis-slave2.conf:/etc/redis/redis-slave2.conf -d redis /etc/redis/redis-slave2.conf

启动完成之后连接主节点发现连接正常。

4.主节点和从节点

        主节点可以set和get,从节点只能get。从节点是Redis复制模式的一种,它可以接收并复制主节点的数据,并提供读服务。与主节点不同,从节点不能进行写操作,因为所有写操作都必须由主节点执行。Redis从节点仅可用于读取,以降低主节点的访问压力。

Redis复制有两种模式:主从模式和Sentinel哨兵模式。在主从模式中,从节点只能执行读操作,而在Sentinel哨兵模式中,如果主节点失效时可以自动切换成从节点,变成一个能够写入的主节点,但这个过程需要时间,造成实时性和数据完整性的风险。因此,在实践中,建议把从节点作为读的备份节点使用,以确保数据的安全性和完整性。

4.1 断开主从关系

#连接上redis输入
slaveof no one

4.2 切换主从复制关系 

slaveof {newMasterIp} {newMasterPort} 

5.Springboot连接主从Redis

spring:
  # redis 配置
  redis:
    master-slave:
      master: 192.168.31.59:6380
      password: 123456
      slaves:
        - 192.168.31.59:6381
        - 192.168.31.59:6379
    # 连接超时时间
    timeout: 10s
    # Lettuce 连接池配置
    lettuce:
      pool:
        # 连接池中的最小空闲连接
        min-idle: 5
        # 连接池中的最大空闲连接
        max-idle: 10
        # 连接池的最大数据库连接数
        max-active: 20
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: 1000ms
@Data
public class RedisMasterSlaveProperties {
    private String master;
    private String password;
    private List<String> slaves;

}

Readform:见 Lettuce 的官方文档: 5.4.4. Read from settings


@Configuration
@ConditionalOnProperty(value = "spring.profiles.active", havingValue = "masterslave")
public class RedisMasterSlaveConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.redis.master-slave")
    public RedisMasterSlaveProperties redisMasterSlaveProperties() {
        return new RedisMasterSlaveProperties();
    }

    @Bean
    public RedisTemplate redisTemplate(@Autowired @Qualifier("mylettuceConnectionFactory") RedisConnectionFactory connectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }

    @Bean("mylettuceConnectionFactory")
    public RedisConnectionFactory lettuceConnectionFactory(RedisMasterSlaveProperties redisMasterSlaveProperties) {
        // 解析主节点
        String[] masterParts = redisMasterSlaveProperties.getMaster().split(":");
        RedisStaticMasterReplicaConfiguration masterReplicaConfig = new RedisStaticMasterReplicaConfiguration(
                masterParts[0], Integer.parseInt(masterParts[1])
        );
        masterReplicaConfig.setPassword(redisMasterSlaveProperties.getPassword());

        // 添加从节点
        for (String slave : redisMasterSlaveProperties.getSlaves()) {
            String[] parts = slave.split(":");
            masterReplicaConfig.addNode(parts[0], Integer.parseInt(parts[1]));
        }

        // 配置Lettuce客户端与读取策略
        LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
                .readFrom(ReadFrom.REPLICA_PREFERRED)
                .build();

        return new LettuceConnectionFactory(masterReplicaConfig, lettuceClientConfiguration);
    }
}

2.2 哨兵配置

1. sentinel-26379.conf

#绑定端口
port 26379
 
#设置redis的工作目录
dir "/app/application"

sentinel resolve-hostnames yes
 
# 配置哨兵的监控参数
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# <master-name> 是为这个被监控的master起的名字
#<ip> 是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名.只有版本高于 6.2 的 sentinel 才能解析主机名,但默认情况下不启用此功能。sentinel resolve-hostnames yes sentinel.conf。如果您的哨兵具有较旧的版本,则主机名应替换为 和 ip。
#<redis-port> 是被监控节点所监听的端口号
#<quorom> 设定了当几个哨兵判定这个节点失效后,才认为这个节点真的失效了
sentinel monitor mymaster 192.168.31.59 6379 2
 
# master在连续多长时间无法响应PING指令后,就会主观判定节点下线,默认是30秒
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 10000
 
 
sentinel failover-timeout mymaster 60000
 
# 连接主节点的密码
# 格式:sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster 123456

#设置认证密码
requirepass 123456

2. sentinel-26380.conf

#绑定端口
port 26380
 
#设置redis的工作目录
dir "/app/application"

sentinel resolve-hostnames yes
 
# 配置哨兵的监控参数
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# <master-name> 是为这个被监控的master起的名字
#<ip> 是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名.只有版本高于 6.2 的 sentinel 才能解析主机名,但默认情况下不启用此功能。sentinel resolve-hostnames yes sentinel.conf。如果您的哨兵具有较旧的版本,则主机名应替换为 和 ip。
#<redis-port> 是被监控节点所监听的端口号
#<quorom> 设定了当几个哨兵判定这个节点失效后,才认为这个节点真的失效了
sentinel monitor mymaster 192.168.31.59 6379 2
 
# master在连续多长时间无法响应PING指令后,就会主观判定节点下线,默认是30秒
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 10000
 
 
sentinel failover-timeout mymaster 60000
 
# 连接主节点的密码
# 格式:sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster 123456

#设置认证密码
requirepass 123456

然后启动哨兵,哨兵启动需要增加redis-sentinel参数

docker run --name=redies-server-sentinell --net=host -p 26379:26379 -v $PWD/sentinel/sentinel-26379.conf:/etc/redis/sentinel-26379.conf -d redis redis-sentinel /etc/redis/sentinel-26379.conf

docker run --name=redies-server-sentinel2 --net=host -p 26380:26380 -v $PWD/sentinel/sentinel-26380.conf:/etc/redis/sentinel-26380.conf  -d redis redis-sentinel /etc/redis/sentinel-26380.conf

然后连接其中一个哨兵,就可以查看当前主从节点信息

 停止主节点看下主节点是否变化,发现主节点已经变化成6380的端口

3 SpringBoot连接Redis配置

#redis  哨兵模式
spring.redis.database=0
spring.redis.password=123456
#哨兵的配置列表,master地址哨兵会自动返回
spring.redis.sentinel.password=123456
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=192.168.31.59:26379,192.168.31.59:26380
#最大连接数据库连接数,设 0 为没有限制
spring.redis.lettuce.pool.max-active=8
#最大等待连接中的数量,设 0 为没有限制
spring.redis.lettuce.pool.max-idle=8
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
spring.redis.lettuce.pool.max-wait=-1ms
#最小等待连接中的数量,设 0 为没有限制
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.shutdown-timeout=100ms
    @Autowired
    RedisTemplate redisTemplate;

    @PostConstruct
    public void redisTemplate() {
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setValueSerializer(RedisSerializer.string());
        redisTemplate.setDefaultSerializer(RedisSerializer.string());
    }

2.集群模式

Redis集群介绍

Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。

Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.

Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

Redis 集群的数据分片

Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念.

Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:

  • 节点 A 包含 0 到 5500号哈希槽.
  • 节点 B 包含5501 到 11000 号哈希槽.
  • 节点 C 包含11001 到 16384号哈希槽.

这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.

Redis 集群的主从复制模型

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品.

在我们例子中具有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用.

然而如果在集群创建的时候(或者过一段时间)我们为每个节点添加一个从节点A1,B1,C1,那么整个集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会选举B1为新的主节点继续服务,整个集群便不会因为槽找不到而不可用了

不过当B和B1 都失败后,集群是不可用的.

以上都是我摘抄的Reds官网消息,主要就是描述Redis集群是分片处理数据,如果需要高可用就需要依赖哨兵模式。这里我只创建集群模式。

redis-node1.conf


#绑定端口
port 6379

#设置指定的日志
logfile "redis-6379.log"

#Redis持久化擦用aof文件增量增加的方式
appendonly yes

appendfilename appendonly.aof

#开启集群配置
cluster-enabled yes

#集群配置文件
cluster-config-file nodes-node-1.conf

#集群超时时间
cluster-node-timeout 15000

#设置主节点(master)认证的密码
masterauth 123456

#设置认证密码
requirepass 123456

redis-node2.conf

#绑定端口
port 6380

#设置指定的日志
logfile "redis-6380.log"

#Redis持久化擦用aof文件增量增加的方式
appendonly yes

appendfilename appendonly.aof

#开启集群配置
cluster-enabled yes

#集群配置文件
cluster-config-file nodes-node-1.conf

#集群超时时间
cluster-node-timeout 15000

#设置主节点(master)认证的密码
masterauth 123456

#设置认证密码
requirepass 123456

redis-node3.conf

#绑定端口
port 6381

#设置指定的日志
logfile "redis-6381.log"

#Redis持久化擦用aof文件增量增加的方式
appendonly yes

appendfilename appendonly.aof

#开启集群配置
cluster-enabled yes

#集群配置文件
cluster-config-file nodes-node-1.conf

#集群超时时间
cluster-node-timeout 15000

#设置主节点(master)认证的密码
masterauth 123456

#设置认证密码
requirepass 123456

然后分别启动三个redis容器

docker run --name=redies-cluster-node1 -p 6379:6379  --net=host -v $PWD/redis-node1.conf:/etc/redis/redis-node1.conf  -d redis /etc/redis/redis-node1.conf

docker run --name=redies-cluster-node2 -p 6380:6379  --net=host -v $PWD/redis-node2.conf:/etc/redis/redis-node2.conf -d redis /etc/redis/redis-node2.conf

docker run --name=redies-cluster-node3 -p 6381:6379  --net=host -v $PWD/redis-node3.conf:/etc/redis/redis-node3.conf -d redis /etc/redis/redis-node3.conf

启动完成之后连接任意一个redis,查看集群的状态是失败的watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L215bGk5Mg==,size_16,color_FFFFFF,t_70

 这时候需要进入容器执行redis集群的构建命令

redis-cli -h 192.168.31.193 -p 6379 -a 123456 --cluster create 192.168.31.193:6379  192.168.31.193:6380  192.168.31.193:6381 --cluster-replicas 0


redis-cli的参数说明:
1)# --cluster create 表示需要集群的redis主机和端口.
2) --cluster-replicas 0
表示为集群中的每一个主节点指定一个从节点,即一比一的复制,1表示一主一从。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L215bGk5Mg==,size_16,color_FFFFFF,t_70

 再次连接redis,发现redis集群初始化成功。

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L215bGk5Mg==,size_16,color_FFFFFF,t_70

使用redis客户端连接redis集群(注意加-c)

redis-cli -c -h 192.168.31.193 -a 123456 -p 6379

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L215bGk5Mg==,size_16,color_FFFFFF,t_70

 springboot配置使用

spring:
  redis:
    cluster:
      nodes:
        - 192.168.31.193:6379
        - 192.168.31.193:6380
        - 192.168.31.193:6381
      max-redirects: 3  # 获取失败 最大重定向次数
    password: 123456
    pool:
      max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)
      max-idle: 10    # 连接池中的最大空闲连接
      max-wait: -1   # 连接池最大阻塞等待时间(使用负值表示没有限制)
      min-idle:  5     # 连接池中的最小空闲连接
    timeout: 6000  # 连接超时时长(毫秒)

 参考:

Docker部署Redis哨兵模式 - 小白一只726 - 博客园

https://www.jianshu.com/p/ce1d78cd368a

REDIS cluster-tutorial -- Redis中文资料站 -- Redis中国用户组(CRUG)

基于Docker的Redis集群搭建 - niceyoo - 博客园

再谈Redis三种集群模式:主从模式、哨兵模式和Cluster模式 - 知乎

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis可以以不同的模式运行,包括单机模式、主从模式哨兵模式集群模式。在单机模式下,Redis只有一个实例,所有的数据都存储在这个实例中。主从模式中,有一个主节点和多个从节点,主节点负责写入数据,从节点负责复制主节点的数据。哨兵模式是在主从模式的基础上引入了哨兵节点,哨兵节点负责监控整个Redis集群的状态,并在主节点出现故障时自动将一个从节点升级为新的主节点。集群模式是在主从模式的基础上引入了分片,将数据分散存储在多个节点上,提高了存储和访问的能力。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [redis单机、主从、哨兵集群模式](https://blog.csdn.net/weixin_43989347/article/details/125293740)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [一文读懂Redis的四种模式单机、主从、哨兵集群(*)](https://blog.csdn.net/weixin_42408447/article/details/120995478)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值