文章目录

  • Redis是什么
  • Redis能做什么
  • Redis使用之前的准备工作
  • Redis-benchmark压力测试工具
  • Redis基础知识
  • Redis的五大数据类型
  • Redis-key
  • String类型
  • List类型
  • Set类型
  • Hash类型
  • Zset有序集合
  • 三大特殊类型
  • Geospatial地理位置
  • Hyperloglog基数统计
  • Bitmaps
  • Redis的基本事务操作
  • Redis实现乐观锁
  • Jedis
  • 连接远程服务器
  • 事务操作
  • Redis整合SpringBoot
  • 整合过程
  • 整合测试
  • 自定义RedisTemplate
  • Redis配置文件详解
  • 持久化的RDB操作
  • 持久化的AOF操作
  • Redis发布订阅
  • Redis主从复制
  • 环境配置
  • 一主二从
  • 哨兵模式
  • 缓存穿透和雪崩
  • 缓存穿透(查不到)
  • 缓存击穿(量太大,缓存过期,一个key)
  • 缓存雪崩(大量key)


Redis是什么

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

Redis能做什么

1、内存存储、持久化,内存中是断电即失、所以说持久化很重要( rdb、 aof )
2、效率高,可以用于高速缓存
3、发布订阅系统
4、地图信息分析
5、计时器、计数器(浏览量!)

Redis使用之前的准备工作

将Redis安装到本地的Linux或者远程的服务器都可以,我这里是选择将Redis安装到了阿里云服务器,可以通过宝塔一键傻瓜式安装,具体教程可以观看【狂神说Java】服务器购买及宝塔部署环境说明。也可以通过自己下载对应的Redis的Linux版本的安装包,通过Xshell和Xftp自行安装。如果是通过宝塔安装完成Redis之后,Redis会存放到以下目录:

redis配环境变量 redis 环境变量_redis配环境变量


因为Redis是用C++编写的,我们使用Xshell连接到远程服务器之后,通过cd命令进入到这个目录,安装一些基本的使用环境,通过:

yum install gcc-c++yum install tcl(redis6.0版本以上需要使用这个)

安装完成之后,我们通过make(宝塔傻瓜式安装好像不用make,因为他已经帮我们准备好了所有的环境,具体使用可以看这篇文章上面一点的一个超链接,但是如果是自己通过下载安装包拷贝的形式的话,需要make一下)将一些环境给配置一下。配置完成后,我们可以通过

make install查看安装情况,出现如下代码则显示安装成功。

redis配环境变量 redis 环境变量_redis配环境变量_02

安装完成之后,我们为了避免直接修改此文件,应该将该目录下的redis.conf文件复制粘贴一份,粘贴到我们的/usr/local/bin/xxx的目录下,可通过Xftp直接复制粘贴,然后在bin目录下新建一个文件夹用于存放我们的redis配置文件。如图所示:

redis配环境变量 redis 环境变量_redis配环境变量_03


随后我们通过shell命令行vim redis.conf或者直接用Xftp右键修改,将

daemonize 修改为yes,设置为默认启动,因为redis不是默认启动的(使用宝塔傻瓜式安装好像这里默认就是yes不用修改)

redis配环境变量 redis 环境变量_redis配环境变量_04


到这里基本准备环境就准备好了,我们可以启动redis了,在/usr/local/bin目录下,我们通过前面一步自己配置的conf文件启动我们的redis,通过shell输入:

redis-server 自己的目录/redis.conf redis6.0版本之后启动成功是不会有提示的,所以到这一步的小伙伴们不要担心是不是自己哪一个步骤除了问题导致启动失败。然后我们链接我们的redis服务器,通过:

redis-cli -h 端口号 -p 6379

其中由于-h是默认的使用的本机,所以因此可以不用写上去,-p是我们的redis服务器,6379是我们的默认端口号。

回车之后,我们通过Ping命令测试是否连接成功,如果返回的是pong,则表示连接成功,如图所示:

redis配环境变量 redis 环境变量_redis配环境变量_05


通过keys *可以查看所有的key值。

redis配环境变量 redis 环境变量_Redis_06

如果我们想要查看我们的进程是否开启,可以通过

ps -ef | grep 进程 查看,如:

redis配环境变量 redis 环境变量_redis_07


如果我们要关闭我们的redis服务,可以通过

shutdown 然后 exit即可,如:

redis配环境变量 redis 环境变量_字符串_08


再次查看进程,会发现该进程其实已经是被终结了。 至此,我们的基本准备环境已经完成了。

Redis-benchmark压力测试工具

相关参数:

redis配环境变量 redis 环境变量_Redis_09

Redis基础知识

1、redis的数据库有16个,默认使用的是第0个。

redis配环境变量 redis 环境变量_字符串_10


我们可以通过select切换数据库,通过DBSIZE查看当前库大小如图所示:

redis配环境变量 redis 环境变量_Redis_11


如果我们要清空当前数据库的key信息,可以通过

flushdb清除当前库或者通过flushall清除所有的数据库内容

2、redis是单线程的,是基于内存操作的。瓶颈是机器内存和网络带宽。(redis6.0以上是可以开启多线程的)

Redis的五大数据类型

它支持多种类型的数据结构,如字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。Redis 内置了 复制(replication),LUA脚本(Lua scripting),LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence),并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

Redis-key

redis配环境变量 redis 环境变量_Redis_12

String类型

append key value 往key对应的字符串里面追加字符串。如果当前key不存在则相当于set key value

strlen key

可以查看当前key的字符串长度。

incr key

相当于i++的操作,可以用于网页浏览量的使用

decr key

相当于i–

incrby key value(增长量)

一次增加多少增长量

decrby key value(减少量)

一次减少多少的减少量

getrange key start(起始位置) end(结束位置)

获取字符串范围里面的值,例如我有个字符串key名为name,value值为"hello,world",getrange name 0 3,就是截取当前字符串0号索引到3号索引的字符,输出的结果是hell。

getrange key start -1表示的是获取全部字符串,同get key作用

setrange key start(起始索引位置) value(要替换的字符串)

替换指定位置的字符串

redis配环境变量 redis 环境变量_Redis_13


setex key outtime(过期时间) value(字符串)

设置一个存活时间为outtime的key键值对。

setnx key value

不存在设置(常用于分布式锁),如果不存在则建立,存在的话就创建失败。

redis配环境变量 redis 环境变量_字符串_14


mset key1 value1 key2 value2 ……

批量设置

mget key1 key2 key 3……

批量获取

redis配环境变量 redis 环境变量_字符串_15


开发中常用的String存对象 写法如下图所示:

redis配环境变量 redis 环境变量_redis配环境变量_16


getset key

先get然后再set

redis配环境变量 redis 环境变量_字符串_17


其中value除了可以是字符串,也还可以是数字。

List类型

在redis里面,我们可以把list变成栈、队列、阻塞队列。命令前面加L表示是List类型,R是特殊的List类型

Lpush list从左边插入队列

Rpush list从右边插入队列

redis配环境变量 redis 环境变量_字符串_18


具体的执行流程:

redis配环境变量 redis 环境变量_Redis_19


Lpop list 从左边移除第一个元素

Rpop list

从右边移除第一个元素

redis配环境变量 redis 环境变量_redis配环境变量_20


Lindex根据下标取出对应的元素

redis配环境变量 redis 环境变量_字符串_21


Llen

返回List长度

redis配环境变量 redis 环境变量_字符串_22


Lrem

移除指定的个数的value,精确匹配

redis配环境变量 redis 环境变量_Redis_23


trim list start end修剪,通过下表截取指定长度,保留想要的元素

redis配环境变量 redis 环境变量_redis配环境变量_24


rpoplpush

移除list最后一个元素,加入新的list集合中

redis配环境变量 redis 环境变量_redis_25


lset

根据指定下标的值更新为另一个值,相当于update操作

redis配环境变量 redis 环境变量_字符串_26


linsert

插入操作,将某一个具体的value插入到某个元素前面或者后面

redis配环境变量 redis 环境变量_Redis_27


小结:

⚫ list其实是一个链表,可以通过linsert在某个具体元素的前面或后面插入,也可以通过lpush,rpush在首或者尾插入元素。
⚫ 可灵活变换,Lpush,Rpop就成了消息队列。Lpush,Lpop就成了

Set类型

sadd 往set集合里面添加值

smembers

查看set集合所有的值

sismember

判断该元素是否在set集合里

redis配环境变量 redis 环境变量_redis_28


scard set

获取集合中元素的个数

redis配环境变量 redis 环境变量_Redis_29

srem 移除集合具体元素

redis配环境变量 redis 环境变量_Redis_30


srandmember

随机获取set集合中的一个元素。可以用于随机获取

spop 随机删除集合的元素

smove set1 set2(目标集合) key 移动一个指定的元素到另外一个集合

redis配环境变量 redis 环境变量_redis_31

sdiff set1 set2 以set1为基准比较set1和set2,找出set1差集。

sinter set1 set2 交集,找出set1,set2并集的部分

sunion set1 set2 并集

redis配环境变量 redis 环境变量_redis_32

Hash类型

Map集合,村的是key—value的形式,相当于key value(key,value>。

hset key key,value

redis配环境变量 redis 环境变量_redis配环境变量_33


hdel key key

删除某一个key的某一个具体字段

redis配环境变量 redis 环境变量_字符串_34


hlen

获取哈希表字段数量hexists 判断hash中指定字段是否存在

redis配环境变量 redis 环境变量_redis_35


hkeys key

只获取所有字段

hvals key

只获取所有值

redis配环境变量 redis 环境变量_字符串_36


incr


decr


redis配环境变量 redis 环境变量_redis_37

Zset有序集合

zadd key source value 添加操作,其中source是分数,可以理解为权值,主要用于排序

redis配环境变量 redis 环境变量_redis_38


zrangebyscore key min max

排序

redis配环境变量 redis 环境变量_字符串_39

zrem key value 移除元素

redis配环境变量 redis 环境变量_redis配环境变量_40


zcard key

查看集合元素个数

redis配环境变量 redis 环境变量_Redis_41

zcount 查看区间内成员个数

redis配环境变量 redis 环境变量_redis配环境变量_42

小结:
具体应用,zset可以用于排行榜实时热搜的实现。
具体的使用和set无异,差别是多了一个权重,一个scores分数而已。

三大特殊类型

Geospatial地理位置

Geoadd 添加地理位置

redis配环境变量 redis 环境变量_字符串_43


getpos

获取指定城市的经度纬度,获得当前定位。

redis配环境变量 redis 环境变量_redis_44


geodist

返回两个坐标之间的距离。距离单位有m米,km千米,mi英里,ft英尺

redis配环境变量 redis 环境变量_redis配环境变量_45


georadius

以给定的经纬度为中心,查找某一半径中的具体元素

redis配环境变量 redis 环境变量_redis_46


redis配环境变量 redis 环境变量_redis配环境变量_47


GEORADIUSBYMEMBER

找出指定元素周围的元素

redis配环境变量 redis 环境变量_redis配环境变量_48

小结:
Geo的底层使用原理其实是zset,因此我们要删除某些元素,我们可以通过zrem移除:

redis配环境变量 redis 环境变量_Redis_49

Hyperloglog基数统计

常用于页面浏览量统计

redis配环境变量 redis 环境变量_字符串_50

Bitmaps

非0即1,操作二进制位来进行储存。

redis配环境变量 redis 环境变量_redis_51

Redis的基本事务操作

Redis单条命令是保证原子性的,但事务不保证原子性,没有隔离级别的概念。Redis事务的本质其实就是一组指令的集合,一个事务中的所有命令都会被序列化,按顺序执行。

开启事务:
命令入队:
执行事务:(注意,执行完事务之后,当前事务就已经结束了,如果还要开启事务,还要重新输入multi命令)

redis配环境变量 redis 环境变量_redis_52


放弃事务:


redis配环境变量 redis 环境变量_redis配环境变量_53


异常事务:


编译时异常,所有的代码都不会被执行。


redis配环境变量 redis 环境变量_Redis_54


运行时异常:


错误的指令不会执行,不会影响其他指令的正常执行。


redis配环境变量 redis 环境变量_字符串_55

Redis实现乐观锁

通过watch监视器监视,这里的watch其实就相当于上锁。具体用法:watch key

正常执行的情况:

redis配环境变量 redis 环境变量_redis_56


异常操作

redis配环境变量 redis 环境变量_字符串_57

如何解决?
如果发现事务执行失败,就先通过unwatch解锁,然后再通过watch加锁。检查版本看看是否发生了修改,再进行execute。

Jedis

连接远程服务器

是Java来操作redis的中间件,通过Jedis可以对redis进行操作。具体操作步骤如下:
第一步、引入相关测试Jar包

<dependencies>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
        <!--导入fastJson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>
    </dependencies>

第二步、编写测试用例
这里由于我使用的是远程服务器进行测试,因此这里的ip写各自的ip即可,如果是安装在本地的服务器,可以直接使用127.0.0.1进行测试。

public class testPing {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("your ip",6379);
        System.out.println(jedis.ping());
    }
}

如果使用的远程服务器,运行到这里,可能又会报错,会显示
Failed connecting to host IP 6379 提示报错我们的访问被拒绝了,其实很简单改。

首先我们得在阿里云服务器安全组,开放redis6379的端口,如图所示:

redis配环境变量 redis 环境变量_字符串_58


第二步,我们得修改相对应的redis启动配置文件,具体要修改的地方有两个,第一个是将

bind 127.0.0.1

进行注释,允许所有IP进行访问,或者将其修改为0.0.0.0。第二个是将保护模式关闭,将protected-mode no设置为no。


第三步,将防火墙打开,允许6379访问,由于我使用的是宝塔安装,因此我管理对应的防火墙端口非常方便,只需要手动添加放行即可,如图所示:


redis配环境变量 redis 环境变量_redis_59


如果不是使用宝塔安装的朋友,可以参考这篇文章:


Redis:客户端连接远程服务器方法

最后,我们在客户端进行连接,如果响应为PONG,则连接成功啦。


redis配环境变量 redis 环境变量_redis_60


但是为了安全,我们最好还是为我们的redis设置一个密码,具体的设置流程可以参考这篇文章:

Jedis连接 HelloWorld实现

具体的操作API同上文讲的五大基本类型无异,无非是通过jedis操作罢了,下面展示测试结果:


redis配环境变量 redis 环境变量_redis配环境变量_61


redis配环境变量 redis 环境变量_redis_62

事务操作

public class testTX {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("Your IP",your port);
        jedis.flushDB();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("username","redis");
        jsonObject.put("password","123");

        //开启事务
        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();
        jedis.watch(result);//加锁以确定result没被修改
        try {
            multi.set("key1",result);
            multi.set("key2",result);
            multi.exec();//执行事务
        } catch (Exception e) {
            multi.discard();//放弃事务
            e.printStackTrace();
        }finally {
            System.out.println(jedis.get("key1"));
            System.out.println(jedis.get("key2"));
            jedis.close();//关闭客户端
        }


    }

}

Redis整合SpringBoot

首先说明,在springboot2.x以后,我们所导入的springboot-redis整合包,他采用的不再是jedis操作redis,而使用的是lettuce操作redis。这样做的目的是因为jedis采用的是直连,多个线程操作是不安全的,如果要避免不安全,得使用jedis pool线程池。而采用lettuce的话,它是用netty实现的,实例可以在多线程中共享,不存在线程不安全的情况。

整合过程

整合步骤,通过springboot脚手架,创建一个基本项目。

redis配环境变量 redis 环境变量_字符串_63


创建完项目后,因为使用的是springboot整合的redis,springboot帮我们整合了redis的配置文件,但是如果我们想自己配置,但是又不知道有什么可以配置,可以自己去寻找相关的配置文件。如下所示

redis配环境变量 redis 环境变量_Redis_64


redis配环境变量 redis 环境变量_Redis_65


通过ctrl+鼠标左键,点击进入该配置文件

redis配环境变量 redis 环境变量_redis_66


我们就找到我们的redis配置文件啦

源码分析:

@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")//我们可以自定义一个叫redisTemplate的类来替换这个类,使这个类失效,因为这个类很多都没有设置,默认序列化格式是jdk序列化
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		//两个泛型都是obj,obj形式,后面得强转为str,obj形式
		//默认redisTemplate没有过多设置,redis对象都需要序列化
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

整合测试

@SpringBootTest
class RedisSpringbootApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        //opsFor  操作不同数据类型
        redisTemplate.opsForValue().set("key1","test");
        System.out.println(redisTemplate.opsForValue().get("key1"));

        //操作数据库,获取redis连接对象
//        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
//        connection.flushDb();
//        connection.flushAll();
    }
}

redis配环境变量 redis 环境变量_redis配环境变量_67

自定义RedisTemplate

前面说到我们的RedisTemplate默认配置其实有很多都是没有配置的,包括我们的序列化设置,如果使用的是默认的序列化配置,我们通过redis的keys *操作,会看到已经被转义了的value值,如上一步测试操作里,我set的value明明是test,但是我在redis服务器get的值如图所示:

redis配环境变量 redis 环境变量_redis配环境变量_68


所以,我们要配置一个自己的配置类。

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate1(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //设置连接方式为默认的lettuce
        template.setConnectionFactory(redisConnectionFactory);
        //所有的object对象都要经过该json序列化
        Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);

        //对序列化对象进行转义,确保不出现诸如\xac\xed\x00\x05t\x00\这种格式的情况
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL);
        objectJackson2JsonRedisSerializer.setObjectMapper(om);

        //String字符串类型的序列化方式
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        /**
         * 此处是设置各数据类型key的序列化格式
         * */
        //key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        //hash的key采用String序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        //value序列化采用的是jackson
        template.setValueSerializer(objectJackson2JsonRedisSerializer);
        //hash的value采用的是jackson
        template.setHashValueSerializer(objectJackson2JsonRedisSerializer);

        template.afterPropertiesSet();

        return template;
    }

}

测试:
POJO类:

@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
/**
 * 序列化对象,不然的话在通过redisTemplate传对象的时候传不了
 * */
public class user implements Serializable {

    private String name;
    private String password;

}

测试类:

@SpringBootTest
class RedisSpringbootApplicationTests {

    @Autowired
    @Qualifier("redisTemplate1")
    private RedisTemplate redisTemplate;
    
    @Test
    void test(){
        user user = new user("learn", "good");
        redisTemplate.opsForValue().set("user",user);
        System.out.println(redisTemplate.opsForValue().get("user"));

    }
}

Redis配置文件详解

redis配置文件中常用配置详解

持久化的RDB操作

因为redis是基于内存操作的,断电即失,因此我们需要将相关的数据持久化操作。 Redis会单独创建( fork )-个子进程来进行持久化
,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何I0操作的。这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比A0F方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
我们默认的就是RDB , -般情况下不需要修改这个配置!rdb保存的文件是dump.rdb都是在我们的配置文件中快照中进行配置的!

redis配环境变量 redis 环境变量_redis_69


我们可以去定制自己的保存规则,在redis.conf文件里面修改即可,如下图所示。


redis配环境变量 redis 环境变量_redis配环境变量_70


默认情况下,有三种情况会触发我们的RDB操作,第一个是save规则,第二个是flushAll操作,第三个是exit退出redis。


那么,我们如何恢复rdb文件呢?其实只需要放到redis.conf的启动目录下就可以了,即bin目录下即可。

持久化的AOF操作

一个文件将我们所有的操作记录下来,恢复的时候就将该文件重新执行一遍。默认是不开启的,需要手动开启。

redis配环境变量 redis 环境变量_字符串_71


修改策略


redis配环境变量 redis 环境变量_Redis_72

Redis发布订阅

订阅端

127.0.0.1:6379> subscribe jieshouduan //订阅一个消息的接收端
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "jieshouduan"
3) (integer) 1
//等待读取推送的信息
1) "message"//消息
2) "jieshouduan"//哪一个频道的消息
3) "nihao"//具体消息
1) "message"
2) "jieshouduan"
3) "hello,redis"

发送端

127.0.0.1:6379> publish jieshouduan "nihao"//发送端需要指定具体的接收端名称,后面接的具体消息
(integer) 1
127.0.0.1:6379> publish jieshouduan "hello,redis"
(integer) 1

redis配环境变量 redis 环境变量_redis_73

Redis主从复制

主从复制,是指将一台Redis服务器的数据 ,复制到其他的Redis服务器。前者称为主节点(master/leader) ,后者称为从节点(slave/follower);数据的复制是单向的,只能由主节点到从节点。Master以写为主, Slave 以读为主。默认情况下,每台Redis服务器都是主节点;且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
redis的主要作用:

redis配环境变量 redis 环境变量_redis_74

环境配置

查看当前库信息:

127.0.0.1:6379> info replication
# Replication
role:master//主机
connected_slaves:0//从机
master_replid:1b577a2810ea61d1f05cbabdaadc18e804c920c9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

要实现主从复制,主要有以下几个步骤:

第一步:复制conf文件

redis配环境变量 redis 环境变量_redis配环境变量_75


第二步,依次修改每个config的文件内容,主要修改的有如下几个:

1、端口

2、pid名字

3、log文件名字

4、dump.rdb名字

第三步,通过redids-server启动服务,查看进程,如果启动了三个进程,则配置成功

redis配环境变量 redis 环境变量_Redis_76

一主二从

默认情况,每台Redis都是主节点,一般情况下只用配置从机就可以了。一主(6379),二从(6380,6381),从机通过SLAVEOF host port即可。通过info replication可以查看是否配置成功。需要注意的是,如果要配置的主机是有密码认证的,需要在从机的配置文件中修改masterauth 主机密码。

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=28,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=28,lag=0
master_replid:12c74a12389a3f02b53582ae27dc655293848366
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:28
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:28
127.0.0.1:6379>

但是这种通过命令配置的主从机,只是暂时的,真实的情况我们要配置的信息其实应该是永久的。需要在配置文件的REPLICATION里面配置

redis配环境变量 redis 环境变量_字符串_77


其中,主机的信息,从机中可以保存。主机只管写,从机只管读。主机断开连接,从机依旧执行,但是从机依然只能读操作。主机回来了,依然可写,从机依然能读到写的信息。如果是通过命令SLAVEOF配置的主从机,是暂时的,从机断开重连就又是主机。

redis配环境变量 redis 环境变量_redis配环境变量_78


通过手动命令,当主机宕机了,从机可以通过命令SLAVEOF NO ONE自己升级为主机,其他节点可以手动重连到这个主机。但是这个时候如果主机重连,升级的主机并不会自动变为从机,还是得手动配置。

哨兵模式

其实就是手动版的升级自动版切换。哨兵模式能够后台自动监控主机是否故障,如果故障了则通过投票数自动将从库变为主库。哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应.从而监控运行的多个Redis实例。

redis配环境变量 redis 环境变量_redis配环境变量_79


当然,一个哨兵也可能会出现’‘死亡’'的情况,因此,一般的情况下,我们的哨兵也是会有多个


redis配环境变量 redis 环境变量_redis配环境变量_80


假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象称为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。

代码实现:
第一步、配置哨兵配置文件sentinel.conf,名字不能写错。如果主机配置了密码的,此处还要配置多一个密码信息。

//sentinel monitor 被监控的名称 IP 端口 1代表主机挂了,哨兵投票选举主机
sentinel monitor myredis 127.0.0.1 6379 1
sentinel auth-pass master(这里的名字是上面这一行你自定义的名字,例如我的名字是myredis) yourpassword

第二步、启动哨兵

[root@username bin]# redis-sentinel yourconfig/sentinel.conf

出现如下界面则配置成功:

11049:X 09 Dec 2020 16:18:58.155 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
11049:X 09 Dec 2020 16:18:58.155 # Redis version=6.0.9, bits=64, commit=00000000, modified=0, pid=11049, just started
11049:X 09 Dec 2020 16:18:58.155 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 6.0.9 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 11049
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

11049:X 09 Dec 2020 16:18:58.156 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
11049:X 09 Dec 2020 16:18:58.156 # Sentinel ID is xxxxxxxxxxxxxxxxxxx(我省略了)
11049:X 09 Dec 2020 16:18:58.156 # +monitor master myredis 127.0.0.1 6379 quorum 1
11049:X 09 Dec 2020 16:18:58.156 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379//我的从节点
11049:X 09 Dec 2020 16:18:58.160 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379//我的从节点

如果这个时候主机宕机了,会自动重新选择一个主机,但是并不是说宕机了就会马上被看到,他需要一定的时间。此时如果主机重连的话,就会变成从机。

redis配环境变量 redis 环境变量_字符串_81

缓存穿透和雪崩

缓存穿透(查不到)

什么是缓存穿透?

缓存穿透的概念很简单,用户想要查询一、一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中(秒杀! ) , 于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

解决?

1、布隆过滤器
对所有可能查询的参数以hash的形式储存,在控制层校验,不符合就丢弃

redis配环境变量 redis 环境变量_redis配环境变量_82


2、缓存空对象


当储存层不命中的时候,即使返回的空对象也会被储存起来,同时设置一个过期时间,之后哦再访问这个数据就会从缓存中获取。


redis配环境变量 redis 环境变量_redis配环境变量_83

缓存击穿(量太大,缓存过期,一个key)

1、什么是缓存击穿
这里需要注意和缓存击穿的区别,缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。当某个key在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。
2、解决方案
设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题。
加互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务 ,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。这个时候只需要等待回写缓存key即可。

缓存雪崩(大量key)

1、 什么是缓存雪崩?
缓存雪崩,是指在某个时间段,缓存集中过期失效。Redis宕机!产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。 那么到了凌晨一点钟的时候 ,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
2、解决方案
redis集群
搭建redis集群,提高可用性。
限流降级
在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key ,设置不同的过期时间,让缓存失效的时间点尽量均匀。
设立随机过期时间
随即过期时间避免缓存雪崩。