Redis

    科技2022-08-30  111

    NoSQL 概述

    为什么要用NoSQL?

    大数据时代,大数据一般不能够一般的数据库进行分析处理

    单机MySQL时代

    APP—>DAL(数据库访问层)—>Mysql(多个)

    瓶颈问题

    数据量太大,一台机器难以放置数据的索引 >300w数据量一定要建立索引,不然查询很慢 B+Tree访问量变大(读写混合),一个服务器难以支持

    Memcache(缓存)

    Memcache(缓存) + MySQL +垂直拆分(读写分离)

    网站80%的情况下,都在读数据库中的内容。每次都要重新查询一次数据库就会十分的麻烦,在中间夹一层缓存,可以减轻数据库的压力。

    发展过程:优化数据结构与索引—>文件缓存(I/O)---->Memcached

    分库分表

    分库分表+水平拆分(MySQL集群)

    本质:数据库(读,写)上面的缓存机制解决了读的问题

    早些年MyISAM(表锁,高并发会出现严重的🔒问题)早些年Innodb(行🔒)慢慢使用分库分表来解决写的压力

    Nowadays

    技术爆炸:

    Mysql关系型数据库就不够用了,数据量太大,发生变化也很快,数据类型也复杂。(例如图数据库,文件数据库等等)

    什么是NoSQL

    NoSQL(Not only SQL)不仅仅是SQL,泛指非关系型数据库。

    NoSQL特点

    方便扩展(数据之间没有关系,很好拓展)大数据量高性能(Redis一秒写8w,读11w,NoSQL的缓存记录,是一种细粒度的缓存,性能高)数据类型是多样性的,不需要事先设计数据库传统RDBMS和NoSQL 传统的RDBMS: - 结构化的组织 - SQL - 数据和关系都存储在表中 - 严格的一致性 - 基础的事务 NoSQL - 不仅仅是数据 - 没有固定的查询语言 - 键值对存储,文档存储,图形存储 - 最终一致性 - CAP和BASE理论 - 高性能,高可用,高可拓展

    3V+3高

    Volume(海量)+Variety(多样)+Velocity(实时)

    高性能+高并发+高可扩

    NoSQL+RDBMS 一起使用才是最强的。

    NoSQL的四大分类

    键值对存储(KV)Reids文档性数据库 MongoDB MongoDB是一个针对于分布式文件存储的数据库,主要用来处理大量的文档MongoDB是一个介于关系型数据库与非关系型数据库中间的产品,MongoDB是NoSQL中的功能最丰富最像RDBMS。 列存储的数据库 HBase,分布式文件系统图形关系数据库(社交拓扑图)Neo4j

    Redis概述

    概述

    Redis是什么?

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

    redis能干什么?

    内存存储持久化效率高,可以用于高速缓存地图信息分析计数器,计时器,浏览量

    redis的特性

    开源多种语言API多样的数据类型持久化

    Tips

    官网:

    Mac下安装Redis

    安装命令

    brew install redis

    文件所在位置

    brew info redis # 安装位置 /usr/local/Cellar/redis/6.0.7 # 配置文件的位置 /usr/local/etc/redis.conf

    性能测试

    redis-benchmark -h 测试的主机 -p 测试的端口 -s 指定服务器 -c 指定并发连接数目 -n 指定请求数目 redis-benchmark -h localhost -p 6379 -c 100 -n 100000

    Redis基础

    可以作为数据库,缓存和消息中间件

    Redis默认有16个数据库,可以使用select进行切换。

    Redis是单线程的

    Redis是基于内存操作的,CPU不是Redis的性能瓶颈,Redis的性能瓶颈是根据机器的内存和网络带宽的,既然可以使用单线程来实现,就使用单线程了。

    为什么基于单线程还可以这么快

    误区1:高性能的服务器一定是多线程的误区2:多线程一定比单线程效率高

    核心:redis是将所有的数据全部放在内存中的,所以说使用单线程操作,效率最高。多线程会有上下文的切换。对于内存而言,如果没有上下文的切换效率就是最高的。

    基本命令

    select 1 # 选择数据库 flushdb # 清除当前数据库 flushall # 清除所有的数据库 keys * # 所有的key dbsize # 当前数据库的大小

    Redis-Key

    keys * set name hml exists name move name 1 # 删除key get name expire name 10 # 设置过期时间 ttl name # 查看剩余时间 type name # 查看类型

    String

    set key1 v1 # 设置key-value get key1 # 获得key对应的值 keys * # 所有的key exists key1 # 判断是否存在 append key1 "hello" # 若当前key不存在相当于set key strlen key1 # 获取字符串长度 +++++++++++++++++++++++++++++++++++++++++++++++++ set views 0 incr views decr views incrby views 10 decrby views 5 +++++++++++++++++++++++++++++++++++++++++++++++++ set key "hello,hml" getrange key 0 3 # 闭区间的 截取字符串 getrange key 0 -1 # 获取全部的字符串 和get key是一样的 setrange key 1 xx # replace 替换指定位置开始的字符串 +++++++++++++++++++++++++++++++++++++++++++++++++ setex (set with expire)# 当前的值存在 setex key3 5 "hello" setnx (set if not exists)# 当前的值不存在,才能创建 在分布式锁里面会用到 setnx key5 "hello" setnx key5 "hello" +++++++++++++++++++++++++++++++++++++++++++++++++ # 批量set get mset mget 是一个原子性的操作 mset mset key1 "hello" key2 "world" mget +++++++++++++++++++++++++++++++++++++++++++++++++ mset user:1{name:hml,age:3} # 设置一个user:1对象 json字符串 mset user:1:name hml user:1:age 12 mget user:1:name user:1:age ++++++++++++++++++++++++++++++++++++++++++++++++++ getset name hml # 如果不存在值返回nil get name

    List

    基本的数据类型,列表,在redis中可以把list玩成stack和queue

    所有的list l开头

    lpush list one # 放在列表的top lpush list two lpush list three lrange list 0 -1 lrange list 0 1 +++++++++++++++++++++++++++++++++++++++++ rpush list right # 放在列表的bottom +++++++++++++++++++++++++++++++++++++++++ # 移除 lpop list # 移除列表的pop rpop list # 移除列表的bottom +++++++++++++++++++++++++++++++++++++++++ lindex list 1 # 通过下标获取某一个值 +++++++++++++++++++++++++++++++++++++++++ llen list # 获取列表的元素 +++++++++++++++++++++++++++++++++++++++++ # 移除某一个具体的值 lrem list 1 two # 移除一个叫做two的值 +++++++++++++++++++++++++++++++++++++++++ # 通过下标截取指定的长度 ltrim list 1 2 +++++++++++++++++++++++++++++++++++++++++ rpoplpush

    Set

    set中的值不能重复

    Hash

    hash更适合对象的存储,String更加适合字符串存储

    hset myhash fields hml# set一个具体的key-value hget myhash fields hmset myhash fields1 hello fields2 world hmget myhash fields1 fields2 hgetall myhash hdel myhash fields1 +++++++++++++++++++++++++++++++++++++++++++++++++ hlen myhash hexists myhash fields1 hkeys myhash hvalues myhash +++++++++++++++++++++++++++++++++++++++++++++++++ hincr myhash fields1 1 hdecr myhash fields1 1 hincrby myhash fields1 5 hdecrby myhash fields1 5

    Zset

    Geospatial

    GEO底层的实现就是Zset,我们可以使用Zset的命令来操作GEO

    地理位置

    朋友圈的定位,附近的人,打车距离计算。

    只有6个命令

    # GEOADD 127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing (integer) 1 127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai (integer) 1 127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing (integer) 1 127.0.0.1:6379> geoadd china:city 114.05 22.52 shenzhen (integer) 1 127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou (integer) 1 127.0.0.1:6379> geoadd china:city 108.96 34.26 xian (integer) 1 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GEODIST # 显示距离 127.0.0.1:6379> GEODIST china:city beijing shanghai "1067378.7564" 127.0.0.1:6379> GEODIST china:city beijing shanghai km "1067.3788" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GEOHASH # 编码 127.0.0.1:6379> GEOHASH china:city beijing 1) "wx4fbxxfke0" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GEOPOS 127.0.0.1:6379> geopos china:city beijing 1) 1) "116.39999896287918091" 2) "39.90000009167092543" +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GEORADIUS # 附近的人 127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km 1) "chongqing" 2) "xian" 3) "shenzhen" 4) "hangzhou" +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ GEORADIUSBYMEMBER# 指定位置的附近 127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km 1) "beijing" 2) "xian"

    Hyperloglog

    什么是基数:不重复的元素

    127.0.0.1:6379> pfadd mykey a b c d e f g h i j (integer) 1 127.0.0.1:6379> pfcount mykey (integer) 10 127.0.0.1:6379> pfadd mykey2 a b c d e f g k l m n (integer) 1 127.0.0.1:6379> pfcount mykey2 (integer) 11 127.0.0.1:6379> PFMERGE mykey3 mykey mykey2 OK 127.0.0.1:6379> pfcount mykey3 (integer) 14

    Bitmap

    统计用户信息,活跃,不活跃,登陆,未登陆,大卡 365天打卡

    setbit sign 0 1 setbit sign 1 1 setbit sign 2 0 setbit sign 3 1 getbit 3 getbit 6 bitcount sign # 统计这周的打卡记录

    Redis事务操作

    Redis单条命令是保证原子性的,redis的事物是不保证原子性的。

    Redis事务没有隔离级别的概念。(所有的命令在事务中,并没有直接被执行)Exec

    >事务:要么都发生,要么都不发生。一组命令的集合一块执行

    Redis事务本质:一组命令的集合,一个事务中的所有命令都会被序列化,在事务执行的过程中,会按照顺序执行

    一次性顺序性排他性

    Rediscover事务

    开启事务(multi)命令入队()执行事务(exec) 127.0.0.1:6379> flushall OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> get k3 QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 3) "v2" 4) OK 5) "v3" 127.0.0.1:6379>

    放弃事务

    discard

    错误处理

    编译型异常(代码有问题):事务中所有的命令不会执行

    运行时异常:存在语法性错误,执行命令的时候,其他命令可以正常执行。(事务没有原子性)

    事务监控

    watch unwatch

    悲观锁:很悲观,认为什么时候都会出现问题,无论做什么都会加锁

    乐观锁:很乐观,认为什么时候都不会出现问题,所以不会上锁,更新数据的时候去判断一下,在此期间是否有人改动过这个数据,version字段控制。

    # 事务正常结束 127.0.0.1:6379> set money 100 OK 127.0.0.1:6379> set out 0 OK 127.0.0.1:6379> WATCH money OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> decrby money 20 QUEUED 127.0.0.1:6379> incrby out 20 QUEUED 127.0.0.1:6379> exec 1) (integer) 80 2) (integer) 20 127.0.0.1:6379>

    模拟两个线程操作:会导致事务执行失败

    Jedis

    什么是Jedis 是jedis官方推荐的java连接开发工具,使用Java操作redis中间件。

    导入依赖

    编码测试

    连接数据库

    SpringBoot整合

    自定义Redis工具类

    Redis.conf

    启动的时候,就通过redis配置文件来启动

    容量大小

    # 1k => 1000 bytes # 1kb => 1024 bytes # 1m => 1000000 bytes # 1mb => 1024*1024 bytes # 1g => 1000000000 bytes # 1gb => 1024*1024*1024 bytes

    组合配置

    # include /path/to/local.conf # include /path/to/other.conf

    网络配置

    bind 127.0.0.1 ::1 # ip绑定 protected-mode yes # 保护模式 默认开启 port 6379 # 端口

    日志输出级别

    # This can be one of: # debug (a lot of information, useful for development/testing) # verbose (many rarely useful info, but not a mess like the debug level) # notice (moderately verbose, what you want in production probably) # warning (only very important / critical messages are logged) loglevel notice

    日志输出文件

    logfile ""

    持久化规则

    save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes # 持久化错误继续工作 rdbcompression yes # 压缩.rdb文件 rdbchecksum yes # 校验rdb文件 # The filename where to dump the DB dbfilename dump.rdb # Note that you must specify a directory here, not a file name. dir /usr/local/var/db/redis/ # rdb文件保存目录

    主从复制

    # replicaof <masterip> <masterport>

    客户端链接相关

    # maxclients 10000 # 最大客户端数量限制 # maxmemory <bytes> # 最大内存限制 # maxmemory-policy noeviction # 内存达到限制值的处理策略

    Redis持久化

    Redis是内存数据库,如果不能将内存中的数据库的状态保存到磁盘,那么一旦服务器进程推出,服务器中的数据库状态也会随之消失,所以Redis提供了持久化功能。

    持久化 RDB

    Redis DataBase

    什么是RDB

    在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,他恢复时将快照文件直接读入到内存中。

    Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件,整个过程中,主进程是不进行任何的IO操作。这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是很敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失,我们默认就是RDB,一般情况下不需要要修改这个配置。

    在进行 RDB 的时候,redis 的主线程是不会做 io 操作的,主线程会 fork 一个子线程来完成该操作;

    Redis 调用forks。同时拥有父进程和子进程。子进程将数据集写入到一个临时 RDB 文件中。当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益(因为是使用子进程进行写操作,而父进程依然可以接收来自客户端的请求。)

    rdb保存的文件是dump.rdb

    触发机制

    save的规则满足的情况下,会自动触发rdb原则执行flushall命令,也会触发我们的rdb原则退出redis,也会自动产生rdb文件

    如何恢复rbd文件

    只需要将rbd文件放到redis的启动目录下就好了。

    持久化 AOF

    什么是AOF

    Append Only File

    以日志的形式来记录每一个写操作,将Redis执行过的所有指令都记录下来(读操作不记录),只许追加文件不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写从前到后执行一次完成数据的恢复工作。

    Aof保存的是appendonly.aof文件

    如果appendonly.aof文件有错误,redis是启动不起来的,redis给我们提供了一个工具,

    redis-check-aof --fix appendonly.aof 优点 每一次修改都同步,文件的完整性会更加好(每秒同步一次) 缺点 相对于数据文件而言,aof远远大于rdb,修复的速度也比rdb慢aof运行效率要比rdb慢,所以我们redis的默认的配置就是rdb持久化。

    重写规则

    如果aof文件大于64m,太大了,就会fork一个新的进程重写一个文件。

    RDB和AOP选择

    RDB 持久化方式能够在指定的时间间隔内对你的数据进行快照存储AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始 的数据,AOF命令以Redis 协议追加保存每次写的操作到文件末尾,Redis还能对AOF文件进行后台重 写,使得AOF文件的体积不至于过大。只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化同时开启两种持久化方式 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF 文件保存的数据集要比RDB文件保存的数据集要完整。RDB 的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?作者 建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有 AOF可能潜在的Bug,留着作为一个万一的手段。 性能建议: 因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够 了,只保留 save 900 1 这条规则。如果Enable AOF ,好处是在恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自 己的AOF文件就可以了,代价一是带来了持续的IO,二是AOF rewrite 的后将 rewrite 过程中产 生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite 的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重 写可以改到适当的数值。如果不Enable AOF ,仅靠 Master-Slave Repllcation 实现高可用性也可以,能省掉一大笔IO,也 减少了rewrite时带来的系统波动。代价是如果Master/Slave 同时倒掉,会丢失十几分钟的数据, 启动脚本也要比较两个 Master/Slave 中的 RDB文件,载入较新的那个,微博就是这种架构。

    Redis发布与订阅

    Redis发布订阅(pub/sub)是一种消息通信模式,发送者发送消息,订阅者接收消息。

    SUBSCRIBE hml # 订阅hml频道 PUBLISH hml "hello world"

    原理

    每个 Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer 结构, 结构的 pubsub_channels 属性是一个字典, 这个字典就用于保存订阅频道的信息,其中,字典的键为正在被订阅的频道, 而字典的值则是一个链表, 链表中保存了所有订阅这个频道的客户端。

    缺点

    如果一个客户端订阅了频道,但自己读取消息的速度却不够快的话,那么不断积压的消息会使redis输出缓冲区的体积变得越来越大,这可能使得redis本身的速度变慢,甚至直接崩溃。这和数据传输可靠性有关,如果在订阅方断线,那么他将会丢失所有在短线期间发布者发布的消息。

    应用

    消息订阅:公众号订阅,微博关注等等(起始更多是使用消息队列来进行实现)多人在线聊天室。

    Redis主从复制

    概念

    主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称之为主节点(master/leader),后者称之为从节点(slaver/follower)数据的复制是单向的,只能由主节点到从节点。Master以写为主,Slaver以读为主

    默认情况下,每一台Redis服务器都是主节点,且一个主节点可以有多个从节点(或者说是没有从节点),但是一个从节点只能有一个主节点。

    主从复制的作用主要包括“

    数据冗余:主从复制实现了数据的热备份,是持久化的一种数据冗余方式故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复,实际上是一种服务的冗余。复杂均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负载。尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。高可用基石:除了上述作用外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

    一般而言,要将 Redis运用于工程项目中,只使用一台Redis是万万不能的,原因如下:

    从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力比较大。从容量上,单个Redis服务器内存容量有限。

    环境配置

    只配置从库,不用配置主库

    # 查看当前库的信息 127.0.0.1:6379> info replication # Replication role:master connected_slaves:0 master_replid:99c9b1c3e83e05446033397415de51ccdbdc6579 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

    复制三个配置文件,然后修改对应的信息

    # 端口 port 6381 # pid名字 pidfile /var/run/redis_6381.pid # 日志名字 logfile "6381.log" # 备份文件名字 dbfilename dump6381.rdb

    修改完毕之后,启动三个Redis服务,可以通过进程信息查看

    一主二从

    默认情况下,每一台Redis服务器都是主机。一般情况下,只用配置从机。

    # 在从机中进行配置,找谁当自己的老大 127.0.0.1:6380> SLAVEOF 127.0.0.1 6379 127.0.0.1:6381> SLAVEOF 127.0.0.1 6379 127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 127.0.0.1:6380> info replication # Replication role:slave master_host:127.0.0.1 master_port:6379 127.0.0.1:6381> info replication # Replication role:slave master_host:127.0.0.1 master_port:6379

    真实的主从配置,在配置文件中进行配置,这样的话才是永久的,使用命令才是暂时的。

    replicaof <masterip> <masterport>

    细节

    主机可以写,从机不能写。主机中所有的信息都能够被从机所保存。

    层层链路也只有一个master

    在出现哨兵模式之前,都是需要手动配的,谋朝篡位

    # 使用下面命令成为master slaveof no one

    宕机配置

    主机断开链接,从机依旧是链接到主机的,但是这时候已经没没有写操作了。

    复制原理

    Slave启动成功连接到master后回发送一个sync命令

    Master接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。

    全量复制:slave服务在接收到数据库文件数据之后,将其存盘并加载到内存中。增量复制:master继续将新的所有收集到的修改命令依次传递给slave,完成同步

    但是只要是重新连接master,一次完全同步(全量复制)将会被自动执行。我们的数据一定可以在从机中看到。

    哨兵模式

    概述

    主从切换技术的方法是:当主服务器宕机之后,需要手动的把一台服务器切换成为主服务器,需要人工干预,费时费力,还会造成一段时间内服务的不可用。这不是一种推荐的方式,更多的时候,我们会优先考虑哨兵模式。

    哨兵模式

    哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,她会独立执行,其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

    哨兵的作用:

    通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器与从服务器当哨兵检测到master宕机,会自动将slave切换成为master,然后通过发布订阅的方式通知其他的服务器,修改配置文件,让他们切换主机。然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控,各个哨兵之间还会相互进行监控,这样就形成了多哨兵模式。

    哨兵配置

    botak@huangmaleidembp :/usr/local/etc  vim sentinel.conf # 编写哨兵配置文件 sentinel monitor myredis 127.0.0.1 6379 1 # 1 代表 botak@huangmaleidembp > /usr/local/Cellar/redis/6.0.7/bin  redis-sentinel /usr/local/etc/sentinel.conf 2839:X 05 Oct 2020 16:49:04.747 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 2839:X 05 Oct 2020 16:49:04.747 # Redis version=6.0.7, bits=64, commit=00000000, modified=0, pid=2839, just started 2839:X 05 Oct 2020 16:49:04.747 # Configuration loaded 2839:X 05 Oct 2020 16:49:04.748 * Increased maximum number of open files to 10032 (it was originally set to 256). _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 6.0.7 (00000000/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in sentinel mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 26379 | `-._ `._ / _.-' | PID: 2839 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 2839:X 05 Oct 2020 16:49:04.750 # Sentinel ID is bc16e80295c256ddcbfc957487a0aebd7c0ef934 2839:X 05 Oct 2020 16:49:04.750 # +monitor master myredis 127.0.0.1 6379 quorum 1 2839:X 05 Oct 2020 16:49:04.751 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379 2839:X 05 Oct 2020 16:49:04.751 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379

    若主节点宕机:

    优点

    哨兵集群,基于主从复制模式,所有的主从配置的优点,它全有主从可以切换,故障可以转移,系统的可用性就会更好哨兵模式就是主从模式的升级,手动到自动,更加健壮

    缺点

    Redis不好在线扩容,若集群容量到达上限,在线扩容很麻烦(配置文件中写死了)实现哨兵模式的配置很麻烦

    哨兵模式的全部配置

    # Example sentinel.conf # 哨兵sentinel实例运行的端口 默认26379 port 26379 # 哨兵sentinel的工作目录 dir /tmp # 哨兵sentinel监控的redis主节点的 ip port # master-name 可以自己命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。 # quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了 # sentinel monitor <master-name> <ip> <redis-port> <quorum> sentinel monitor mymaster 127.0.0.1 6379 1 # 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码 # 设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码 # sentinel auth-pass <master-name> <password> sentinel auth-pass mymaster MySUPER--secret-0123passw0rd # 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒 # sentinel down-after-milliseconds <master-name> <milliseconds> sentinel down-after-milliseconds mymaster 30000 # 这个配置项指定了在发生failover主备切换时最多可以有多少个slave同时对新的master进行 同步, # 这个数字越小,完成failover所需的时间就越长, # 但是如果这个数字越大,就意味着越 多的slave因为replication而不可用。 # 可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态。 # sentinel parallel-syncs <master-name> <numslaves> sentinel parallel-syncs mymaster 1 # 故障转移的超时时间 failover-timeout 可以用在以下这些方面: #1. 同一个sentinel对同一个master两次failover之间的间隔时间。 #2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。 #3.当想要取消一个正在进行的failover所需要的时间。 #4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了 # 默认三分钟 # sentinel failover-timeout <master-name> <milliseconds> sentinel failover-timeout mymaster 180000 # SCRIPTS EXECUTION #配置当某一事件发生时所需要执行的脚本,可以通过脚本来通知管理员,例如当系统运行不正常时发邮件通知相关人员。 #对于脚本的运行结果有以下规则: #若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10 #若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。 #如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。 #一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。 #通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本, #这时这个脚本应该通过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数, #一个是事件的类型, #一个是事件的描述。 #如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。 #通知脚本 # sentinel notification-script <master-name> <script-path> sentinel notification-script mymaster /var/redis/notify.sh # 客户端重新配置主节点参数脚本 # 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。 # 以下参数将会在调用脚本时传给脚本: # <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port> # 目前<state>总是“failover”, # <role>是“leader”或者“observer”中的一个。 # 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通信的 # 这个脚本应该是通用的,能被多次调用,不是针对性的。 # sentinel client-reconfig-script <master-name> <script-path> sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

    缓存穿透与雪崩

    Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时,他也会带来一些问题,其中,最要害的问题就是数据的一致性问题,从严格意义上而言,这个问题无解,如果对于数据的一致性要求很高的情况下,就不能使用缓存。

    缓存穿透

    概念

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

    解决方案

    布隆过滤器

    缓存空对象

    缓存击穿

    概述

    这里需要注意与缓存穿透的区别,缓存击穿是指一个key非常热点,在不停的扛着大并发,大的并发集对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就会穿破缓存,直接请求数据库,就相当于在持久化数据层上面点击开了一个洞。

    解决方案

    设置热点数据永不过期 从缓存层面而言,不设置过期时间,所以不会出现热点key过期后产生的问题 加互斥锁

    缓存雪崩

    概述

    缓存雪崩指的是,在某一个时间段,缓存集中过期失效或者Redis宕机。

    解决方案

    redis高可用 多增几台redis 限流降级 在缓存失效之后,通过加锁或者是队列来控制读数据库写缓存的线程数量 数据预热 在正式部署之前,先把可能的数据预处理一遍,为不同活跃度的数据设置不同的枸杞时间,让缓存失效的时间点尽量均匀。
    Processed: 0.012, SQL: 10