超详细Redis

1.什么是Redis,什么是NoSQL数据库

(1)redis

Redis是一个基于内存的key-value结构数据库,使用单线程+多路IO复用技术

基于内存存储,读写性能高
适合存储热点数据
可以用作:数据库、缓存和消息中间件

在这里插入图片描述

(2)NoSQL数据库

(1)减少CPU的压力,通过内存读取
(2)通过缓存,减少IO操作
(1)NoSQL(not only sql),以key-value模式存储,因此大大增加了数据库的扩展能力

(2)不遵循SQL标准,不支持ACID,远超于SQL性能

(3)适用场景:对数据高并发读写,海量数据的读写,对数据高可扩展性的

(4)不适用场景:需要事务支持,基于SQL的结构化存储,处理复杂关系

(3)redis的发布和订阅

(1)发布和订阅是一种消息通信模式,发布者发送消息,订阅者接收消息

(2)redis客户端可以订阅任意数量的频道

(3)订阅者订阅 channel1 这个频道:SUBSCRIBE channel1
	发布者给 channel1 这个频道发送消息 hello :publish channel1 hello,返回值是订阅者的数量
	订阅者就可以收到发布者发送的 hello


2.Redis数据类型

(1)常用数据类型

Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型:
(1)字符串 String
(2)哈希 hash
(3)列表 list
(4)集合 set
(5)有序集合 sorted set

(2)新数据类型

(1)Bitmaps
(2)HyperLogLog
(3)Geospatial

(1)Bitmaps

(1)Bitmaps本身不是一种数据类型,实际上它就是字符串,但是它可以对字符串的位进行操作

(2)Bitmaps单独提供了一套命令,可以把Bitmaps想象成一个以位为单位的数组,数组的每个单元只能存储
	0和1,数组的下标在Bitmaps中叫做偏移量

(3)设置Bitmaps中某个偏移量的值(0/1):setbit key的名字 偏移量 value
				setbit id 12 1 --> key:id,偏移量:12,value:1

(4)获取Bitmaps中某个偏移量的值:getbit key 偏移量

(5)bitcount:统计字符串被设置为1的bit数。一般情况下,给定的整个字符串都会被进行计数,通过
	指定额外的start/end参数,可以让计数只在特定的位上进行
	bitcount key [start end]

(6)bitop:是一个符合操作,可以做多个Bitmaps的and(交集)、or(并集)、not(非)、xor(异或)

(2)HyperLogLog

主要用于基数的计算操作(起到去重)
基数:[1,1,2,3,3,3,4,4,8] --> 的基数就是5个[1,2,3,4,8]

(1)添加指定元素:pfadd key value

(2)统计出基数的数量:pfcount key

(3)合并多个到一个中(比如一个月的活跃用户是30天的活跃用户合并来的)
	pfmerge k k1 k2    -> k:合并后的   k1/k2:被合并的

(3)Geospatial

针对地理信息(经度纬度)

(1)geoadd:添加,geoadd key 经度 纬度 名称 

(2)geopos:查询某个位置的经度纬度  geopos key 名称

(3)geodist:获取两个位置之间的直线距离  geodist key 名称1 名称2 单位

(4)georadius:以给定的经纬度为中心,找出某一半径内的元素
			georadius key 经度 纬度

3.Redis常用命令

(1)字符串操作命令

(2)哈希操作命令

(3)列表操作命令

(4)集合操作命令

(5)有序集合操作命令

(6)通用命令

4.在java中操作Redis

(1)Jedis

    <dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
    </dependencies>
//使用的话只需要将Jedis对象创建出来即可
Jedis jedis=new Jedis("localhost",6379);
//第一个参数是IP地址,第二个参数是端口号
public class JedisDemo1 {

    //操作key
    @Test
    public void demo1(){

        //创建jedis对象
        Jedis jedis=new Jedis("localhost",6379);

        //得到redis中所有的key
        Set<String> keys = jedis.keys("*");
        for (String key:keys){
            System.out.println(key);
        }

        //向redis中添加数据
        jedis.set("cw","tm");
        //从redis中获取数据
        String value = jedis.get("cw");
        System.out.println(value);

        //同时向redis中添加多个key和value
        jedis.mset("k1","v1","k2","v2");
        //获取
        List<String> mget = jedis.mget("k1", "k2");
        System.out.println(mget);

    }

    //操作list
    @Test
    public void demo2(){

        //创建jedis对象
        Jedis jedis=new Jedis("localhost",6379);

        //添加数据 从左加
        jedis.lpush("number","1","2","3","4","5","6");
        //取出所有数据
        List<String> number = jedis.lrange("number", 0, -1);
        System.out.println(number);
        
        //还有其他方法
    }
    
    //set 具体怎么做看文档就可以了 其它类似

}

(2)模拟验证码发送

(1)输入手机号,点击发送后随机生成6位数字验证码,2分钟有效
(2)输入验证码,点击验证,返回成功或失败
(3)每个手机号每天只能输入5次
public class PhoneCode {

    public static void main(String[] args) {

        //模拟验证码发送
        //verifyCode("15109546897");

        //校验
        getRedisCode("15109546897","323559");
    }

    //1.生成6位数字验证码
    public static String getCode(){
        Random random=new Random();
        String code="";
        for (int i=1;i<=6;i++){
            int rand = random.nextInt(10);
            code+=rand;
        }
        return code;
    }

    //2.每个手机每天只能发送5次,验证码放入redis,设置过期时间120s
    public static void verifyCode(String phone){

        //连接redis
        Jedis jedis=new Jedis("localhost",6379);

        //拼接key
        //手机发送次数key
        String countKey=phone+"count";
        //验证码key
        String codeKey=phone+"code";

        //每个手机每天只能发送5次
        String count = jedis.get(countKey);
        if (count==null){
            //没有发送次数 证明是第一次发送
            //设置发送次数为1   key 过期时间 值
            jedis.setex(countKey,24*60*60,"1");
        } else if (Integer.parseInt(count)<5) {
            //发送次数+1
            jedis.incr(countKey);
        } else if (Integer.parseInt(count)==5) {
            System.out.println("验证码发送次数已经超过5次");
            jedis.close();
            return;
        }

        //发送的验证码放到redis中
        String vCode=getCode();
        jedis.setex(codeKey,120,vCode);
        jedis.close();
    }

    //3.验证码校验
    public static void getRedisCode(String phone,String code){

        //从redis中获取验证码
        //连接redis
        Jedis jedis=new Jedis("localhost",6379);
        //验证码key
        String codeKey=phone+"code";
        String redisCode = jedis.get(codeKey);
        //判断
        if (redisCode==null){
            System.out.println("验证码已过期,请重新获取");
            return;
        }
        if (redisCode.equals(code)){
            System.out.println("success");
        }else {
            System.out.println("error");
        }
        jedis.close();
    }

}

(3)spring Data Redis

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
spring:
  redis:
    host: localhost
    port: 6379
    database: 0 #使用0号数据库
    jedis:
      #redis连接池配置
      pool:
        max-active: 8 #最大连接数
        max-wait: 1ms #连接池最大阻塞等待时间
        max-idle: 4 #连接池中最大空闲连接
        min-idle: 0 #连接池中的最小空闲连接

5.redis事务

(1)redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行
	过程中,不会被其他客户端发送来的命令请求所打断

(2)redis事务的主要作用就是串联多个命令防止别的命令插队

(1)事务基本操作

从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,redis会将
之前的命令队列中的命令依次执行。
组队的过程中,可以通过discard来放弃组队

错误处理

(1)组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消

(2)如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚

(2)事务冲突

多个线程都想操作某一个资源,就会存在事务冲突

可以使用以下两种方式解决:
(1)悲观锁:给数据加锁,每一个线程都会阻塞等待锁
(2)乐观锁:线程读数据不会上锁,在修改数据时会判断一下版本号,看是否有人修改过这个数据

乐观锁

在执行multi之前,先执行 watch key1 key2...,可以监视一个或多个key,如果在事务执行之前这个
或这些key被其他命令所改动,那么事务将被打断

(3)事务三特性

(1)单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行过程中,不会被其他
	客户端发送来的命令请求所打断

(2)没有隔离级别概念:队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会
	被实际执行

(3)不保证原子性:事务中如果有一条命令执行失败,其后地命令仍然会被执行,没有回滚

(4)秒杀案例

基本实现

public class SecKill {

    //秒杀过程
    public static boolean doSecKill(String uid,String prodId){
        //1.uid和prodId非空判断
        if (uid==null||prodId==null){
            return false;
        }

        //2.连接redis
        Jedis jedis=new Jedis("localhost",6379);

        //3.拼接key
        //库存key
        String kcKey="sk"+prodId;
        //秒杀成功用户key
        String userKey="uk"+uid;

        //4.获取库存,如果库存为null,秒杀还没有开始
        String kc=jedis.get(kcKey);
        if (kc==null){
            System.out.println("秒杀还未开始");
            jedis.close();
            return false;
        }

        //5.判断用户是否重复秒杀操作
        if (jedis.sismember(userKey, uid)){
            System.out.println("已经秒杀成功,不能重复秒杀");
            jedis.close();
            return false;
        }

        //6.如果库存数量等于0,秒杀结束
        int i = Integer.parseInt(kc);
        if (i<=0){
            System.out.println("秒杀已经结束");
            jedis.close();
            return false;
        }

        //7.秒杀过程
        //库存减一
        jedis.decr(kcKey);
        //秒杀成功的用户添加清单里边
        jedis.sadd(userKey,uid);

        System.out.println("秒杀成功");
        jedis.close();
        return true;
    }

}

并发场景下秒杀

(1)解决连接超时问题

使用线程连接池可以解决
/**
 * 单例模式 保证整个项目只有一个jedis线程连接池
 */
public class JedisPoolUtil {

    private static volatile JedisPool jedisPool=null;

    private JedisPoolUtil(){

    }

    public static JedisPool getJedisPoolInstance(){
        if (jedisPool==null){
            synchronized (JedisPoolUtil.class){//锁住JedisPoolUtil这个类
                if (jedisPool==null){
                    JedisPoolConfig poolConfig=new JedisPoolConfig();
                    poolConfig.setMaxTotal(200);//总连接的最大连接数
                    poolConfig.setMaxIdle(32);//空闲连接的最大数量
                    poolConfig.setMaxWaitMillis(100*1000);//等待时间
                    poolConfig.setBlockWhenExhausted(true);//超过等待时间是否等待
                    poolConfig.setTestOnBorrow(true);//

                    //60000是超时时间
                    jedisPool=new JedisPool(poolConfig,"localhost",6379,60000);
                }
            }
        }
        return jedisPool;
    }

    public static void release(Jedis jedis){
        if (jedis!=null){
            jedis.close();
        }
    }

}


public class SecKill {

    //秒杀过程
    public static boolean doSecKill(String uid,String prodId){
        //1.uid和prodId非空判断
        if (uid==null||prodId==null){
            return false;
        }

        //2.连接redis
        //Jedis jedis=new Jedis("localhost",6379);
        //通过连接池得到jedis对象
        JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();
        Jedis jedis = jedisPoolInstance.getResource();

        //3.拼接key
        //库存key
        String kcKey="sk"+prodId;
        //秒杀成功用户key
        String userKey="uk"+uid;

        //4.获取库存,如果库存为null,秒杀还没有开始
        String kc=jedis.get(kcKey);
        if (kc==null){
            System.out.println("秒杀还未开始");
            jedis.close();
            return false;
        }

        //5.判断用户是否重复秒杀操作
        if (jedis.sismember(userKey, uid)){
            System.out.println("已经秒杀成功,不能重复秒杀");
            jedis.close();
            return false;
        }

        //6.如果库存数量等于0,秒杀结束
        int i = Integer.parseInt(kc);
        if (i<=0){
            System.out.println("秒杀已经结束");
            jedis.close();
            return false;
        }

        //7.秒杀过程
        //库存减一
        jedis.decr(kcKey);
        //秒杀成功的用户添加清单里边
        jedis.sadd(userKey,uid);

        System.out.println("秒杀成功");
        jedis.close();
        return true;
    }

}

(2)解决超卖问题

利用乐观锁解决
public class SecKill {

    //秒杀过程
    public static boolean doSecKill(String uid,String prodId){
        //1.uid和prodId非空判断
        if (uid==null||prodId==null){
            return false;
        }

        //2.连接redis
        //Jedis jedis=new Jedis("localhost",6379);
        //通过连接池得到jedis对象
        JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();
        Jedis jedis = jedisPoolInstance.getResource();

        //3.拼接key
        //库存key
        String kcKey="sk"+prodId;
        //秒杀成功用户key
        String userKey="uk"+uid;

        //监视库存
        jedis.watch(kcKey);

        //4.获取库存,如果库存为null,秒杀还没有开始
        String kc=jedis.get(kcKey);
        if (kc==null){
            System.out.println("秒杀还未开始");
            jedis.close();
            return false;
        }

        //5.判断用户是否重复秒杀操作
        if (jedis.sismember(userKey, uid)){
            System.out.println("已经秒杀成功,不能重复秒杀");
            jedis.close();
            return false;
        }

        //6.如果库存数量等于0,秒杀结束
        int i = Integer.parseInt(kc);
        if (i<=0){
            System.out.println("秒杀已经结束");
            jedis.close();
            return false;
        }

        //7.秒杀过程
        //使用事务
        Transaction multi = jedis.multi();
        //组队操作
        multi.decr(kcKey);库存减一
        multi.sadd(userKey,uid);//秒杀成功的用户添加清单里边
        //执行
        List<Object> results = multi.exec();
        
        if (results==null||results.size()==0){
            System.out.println("秒杀失败");
            jedis.close();
            return false;
        }

        //库存减一
        //jedis.decr(kcKey);
        //秒杀成功的用户添加清单里边
        //jedis.sadd(userKey,uid);
        
        System.out.println("秒杀成功");
        jedis.close();
        return true;
    }

}

(3)解决库存遗留问题

使用了乐观锁,一个线程修改版本号之后,其他线程发现版本号不一致,导致购买不成功,导致库存遗留

(1)使用LUA脚本执行复杂或多步的redis操作,写为一个脚本,一次提交给redis执行,减少反复连接
	redis操作的次数,提升性能。
	
(2)LUA脚本类似redis事务,有一定的原子性,不会被其他命令插队,可以完成一些redis事务性的操作

(3)实际上是redis利用其单线程的特性,用任务队列的方式解决多任务并发问题

6.持久化操作

(1)RDB

(1)在指定的时间间隔内将内存中的数据集快照写入磁盘
	它恢复时是将快照文件直接读到内存里
(2)redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化
	过程都结束了,再用这个临时文件替换上次持久化好的文件。

(3)整个过程中,主进程是不进行任何IO操作的,提高了性能

(4)如果需要进行大规模的数据恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式
	更加高效

(5)RDB的缺点是最后一次持久化后的数据可能丢失
(6)在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统
	调用,出于效率考虑,Linux中引入了"写时复制技术"

(7)一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会
	将父进程的内容复制一份给子进程

优点

(1)适合大规模的数据恢复
(2)对数据完整性和一致性要求不高的场景更适合使用
(3)节省磁盘空间
(4)恢复速度快

缺点

(1)fork()的时候,内存中的数据被克隆了一份,大致2被的膨胀性需要考虑
(2)虽然redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能
(3)在备份周期在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后
	的所有修改

(2)AOF(Append Only File)

(1)以日志的形式来记录每个写操作,将redis执行过的所有写指令记录下来(读操作不记录),只许
	追加文件但不可以改写文件

(2)redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将
	写指令从前到后执行一次以完成数据的恢复工作

持久化流程

(1)客户端的请求写命令会被append追加到AOF缓冲区内
(2)AOF缓冲区根据AOF持久化策略将操作sync同步到磁盘的AOF文件中
(3)AOF文件大小超过重写策略或手动重写时,会对AOF文件重写,压缩AOF文件容量
(4)redis服务重启时,会重新加载AOF文件中的写操作达到数据恢复的目的

持久化策略

(1)appendfsync always:始终同步,每次redis的写入(修改)都会立刻记入日志
						性能较差,但数据完整性较好

(2)appendfsync everysec:每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失

(3)appendfsync no:redis不主动进行同步,把同步时机交给操作系统

优点

(1)备份机制更稳健,丢失数据概率更低

(2)可读的日志文件,通过操作AOF文件,可以处理误操作

缺点

(1)比起RDB占用更多的磁盘空间

(2)恢复备份速度慢

(3)每次读写都同步的话,有一定的性能压力

(4)存在个别bug,造成不能恢复

(3)使用哪个

(1)如果对数据不敏感,可以单独使用RDB

(2)不建议单独使用AOF,因为可能出现bug

(3)如果只是做纯内存缓存,可以都不用

7.主从复制

(1)主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,master以写为主,
	slave以读为主。一主多从

(2)读写分离,性能扩展

(3)容灾性好,挂掉之后可以快速恢复。如果一个从服务器挂掉重启之后,需要再加入到之前那个主服务器,
	才会变成从服务器,会把主机现在有的数据全部复制过来。

(4)如果主服务器挂掉之后,从服务器依然是从服务器,主服务器重启之后依然是主服务器

(5)存在复制延时,由于所有的写操作都现在主服务器上,然后同步更新到从服务器,所以从主服务器
	同步到从服务器有一定的延迟,当系统很繁忙时,延迟问题会更加严重,从服务器数量的增加也会
	使这个问题更加严重。

(1)主从复制的原理

(1)当从服务器连接上主服务器之后,从服务器向主服务器发送进行数据同步消息

(2)主服务器接到从服务器发送过来的同步消息,会把主服务器的数据持久化到rdb文件中,把rdb
	文件发送给从服务器,从服务器拿到rdb文件进行读取数据

(3)每次主服务器进行写操作之后,会主动和从服务器同步数据

(2)薪火相传

(3)哨兵模式

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库

8.集群

(1)解决容量不够问题

(2)解决并发写操作

(3)主从模式下,如果主机发生宕机,导致IP地址发生变化,应用程序中的配置需要修改对应的主机地址、
	端口信息等

(4)redis集群实现了对redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个
	节点中,每个节点存储总数居的1/N。一个集群中至少有3个主节点

(5)redis集群通过分区来提供一定程度的可用性:即使集群中有一部分节点失效或者无法进行通讯,
	集群也可以继续处理命令请求

9.缓存穿透

特点:
(1)应用服务器压力变大
(2)redis命中率降低
(3)一直查询数据库

原因:
(1)redis查询不到数据
(2)出现很多非正常的url访问(遭受到了恶意攻击)

解决方案:
(1)对空值进行缓存:如果一个查询返回的数据为空(不管数据存不存在),仍要把这个空结果进行缓存,
				 设置空结果的过期时间会很短,最长不超过5分钟
(2)采用布隆过滤器:将所有可能存在的数据都哈希到一个足够大的位图里,一个一定不存在的数据会被
				 这个bitmaps拦截掉,从而避免了对数据库的查询压力
(3)进行实时监控:当发现redis的命中率开始急速降低,需要排查访问对象和访问的数据,可以设置
			   黑名单限制服务

10.缓存击穿

特点:
(1)数据库访问压力瞬时增加
(2)redis中没有出现大量key过期
(3)redis正常运行

原因:
(1)redis中某个key过期了,大量请求来访问这个key

解决:
(1)预先设置热门数据:在redis高峰访问之前,把一些人们数据提前存入到redis中,加大这些热门
			       key的过期时间
(2)实时调整:现场监控哪些key是热门key,实时调整key的过期时间
(3)使用锁:一个线程获取锁之后去访问数据库的数据,其他线程阻塞等待,将这个线程访问到的数据
		   放入缓存中,其他线程去访问redis缓存

11.缓存雪崩

特点:
(1)数据库压力变大
(2)服务器崩溃

原因:
(1)在极少时间段内,出现大量key过期的现象

解决:
(1)构造多级缓存架构:nginx缓存+redis缓存+其他缓存
(2)使用锁或队列:一个线程获取锁之后去访问数据库的数据,其他线程阻塞等待,将这个线程访问到的数据
		   		放入缓存中,其他线程去访问redis缓存。不适用于高并发情况

(3)设置过期标志更新缓存:记录缓存数据是否过期,如果过期会触发通知另外的线程去后台去更新实际key
					  缓存

(4)将缓存失效时间分散开:可以在原有的失效时间的基础上加一个随机值

12.分布式锁

由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制所策略失效,
单纯的 java API 并不能提供分布式锁的能力。

为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题

分布式锁主流的实现方案:
(1)基于数据库实现分布式锁
(2)基于缓存(redis等):redis性能最高
(3)基于Zookeeper,可靠性最高

(1)基于redis实现分布式锁

(1)使用setnx上锁,通过del释放锁

(2)如果锁一直没有释放,可以通过设置key的过期时间,自动释放锁

(3)上锁之后如果突然出现问题,就无法设置过期时间了
	所以要在上锁的同时设置过期时间:set users 10 nx ex 12
	10:值    nx:表示要上锁    ex:设置过期时间    12:过期时间

13.redis缓存删除策略

(1)LRU

最近最少使用策略

当内存不足以存储新数据时,redis会尝试删除最近最少被访问过的数据
这个策略通常适用于数据访问具有时效性的场景

(2)LFU

最不经常使用策略

这种策略会删除访问次数最少的数据
适用于数据频率访问不均匀的场景

(3)TTL

生存时间策略

当设置了缓存数据的生存时间,当数据的存活时间超过设定值,redis会自动删除这些数据

(4)随机删除

随机选择一些数据进行删除

相对简单,但可能导致缓存数据的有效性降低

(5)Partial Redis Del

如果一个键关联了多个元素,例如一个列表、集合等,当删除某个元素时,不会删除整个键,而是只删除
指定元素

14.redis集群数据hash分片算法

redis cluster 将所有数据划分为 16384 个槽位,每个节点负责其中一部分槽位,槽位的信息存储
于每个节点中

当 redis cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息,并将其缓存在客户端
本地。这样当客户端要查找某个 key 时,可以根据槽位定位算法定位到目标节点

槽位定位算法:
cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后利用这个整数值对
16384 进行取模得到具体槽位。再根据槽位值和redis节点的对应关系就可以定位到key具体是落在
哪个redis节点上的

在这里插入图片描述

15.redis主从风暴

如果 redis 主节点有很多从节点,在某一时刻如果所有从节点都同时连接主节点,那么主节点会同时
把内存快照 RDB 发给多个从节点,这样会导致 redis 主节点压力非常大

可以采用如下的树形复制架构来解决

16.redis集群为什么至少需要三个master节点

因为新master的选举至少需要大于半数的集群master节点同一才能选举成功,如果只有两个master节点,
当一个挂了,剩下一个达不成选举条件
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
配置Redis在Linux系统中可以使用以下步骤进行操作: 1. 首先,你需要在Linux系统上安装Redis。你可以使用以下命令下载并安装Redis: ``` sudo apt-get update # 更新软件包列表 sudo apt-get install redis-server # 安装Redis ``` 2. 安装完成后,你可以通过以下命令启动Redis服务: ``` sudo service redis-server start ``` 3. 如果你想对Redis进行配置,你可以编辑Redis的配置文件。在Linux系统上,Redis的配置文件通常位于`/etc/redis/redis.conf`。你可以使用以下命令打开配置文件: ``` sudo vi /etc/redis/redis.conf ``` 4. 在配置文件中,你可以根据需要进行各种配置。例如,你可以更改Redis的监听地址、端口号、数据库路径等。另外,你还可以配置Redis的持久化选项、内存优化等。 5. 在完成配置后,你可以保存并关闭配置文件。然后,重新启动Redis服务以使配置更改生效: ``` sudo service redis-server restart ``` 这样,你就成功地在Linux系统上进行了Redis的配置。请注意,这只是Redis配置的基本步骤,具体的配置选项和更高级的使用方法可以参考Redis的官方文档。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Linux 详细 Redis 安装配置教程(多图文,推荐)](https://blog.csdn.net/weixin_44652781/article/details/113103875)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [linux 安装redis 配置 详细图文教程 一看就会](https://blog.csdn.net/weixin_51613454/article/details/127387178)[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^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cw旧巷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值