Redis

为什么需要NOSQL:

sql数据库无法承载Web动态页面的高并发读写,而NoSQL可以。

Redis可以对海量数据的高效率存储和访问,而sql不行。

基于Web的架构当中,数据库是最难横向扩展的。(不能通过添加更多的硬件来搭载负载均衡的服务器),NoSQL高扩展、高可用。

NOSQL分类

  • 键值对存储:查询快速 ; 存储的数据缺少结构化
  • 列存储      :查询快速 ,可扩展性强,更容易进行分布式扩展;功能局限 
  • 文档数据库 :数据格式要求不严格; 查询效率不高、缺乏统一的语法
  • 图形数据库 :可以利用图结构算法;需要对整个图做计算才能得出结果

NOSQL特点

  • 易扩展
  • 灵活的数据模型(不需要为数据事先建立字段)
  • 大数据量,高性能
  • 高可用

Redis是什么:

Redis(remote diciionary server) 远程字典服务,支持网络,可基于内存亦可持久化的日志型、Key-Value数据库,提供多种API(多个语言都可以调用redis)、redis会周期性地把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现master-slave(主从)同步。

Redis用来干什么:

1.Redis内存存储、持久化(rdb、aof)可用作数据库

2. 速度快,可以用于高速缓存。(最主要的功能)

3. 发布订阅系统(消息中间件MQ)

4.地图信息分析

5. 计时器、计数器(浏览量的统计)

Redis基本知识

  • Redis有16个数据库。

可以使用select来切换

eg: select 3

可以通过db来查看大小

通过keys * 来查看所有键

可以通过get key 来查看值

eg: get name

使用flushdb来清除当前数据库

使用flushall来清除当前数据库

  •  默认端口号是6379
  •  Redis是基于内存操作的,CPU不是Redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,Redis是c语言写的,并且使用单线程实现。

为什么要使用单线程 ?

高性能的服务器不一定是多线程的,多线程(CPU上下文会切换会消耗cpu资源) 不一定比单线程效率高。  redis数据存放在内存上,对内存系统来说,多次读写都是在一个CPU上,上下文切换非常影响效率,所以用单线程以避免CPU上下文切换,达到最佳效率(现在版本redis支持多线程)。

Redis的数据结构及语法

  • 字符串类型 string
  • 哈希类型 hash
  • 列表类型 list
  • 集合类型 set
  • 有序集合类型 zset

Key不要过长也不要过短,要有统一的命名规范。

存储string

string以二进制安全的方式存入redis,存入和获取的数据相同。

Value最多可以容纳的数据长度是512M。

set key value   设置值

get key            获取值

getset key value   先获取再设置值

del key                  删除值

incr key                增加1,key不存在会新建并加1,如果key不是数字类型会报错

decr key               减1,与上面类似

incrby/decrby key number   增加指定的数

存储Hash

如果hash包含很少字段,那么这个类型的数据也占用很少的数据空间。

存值: hset  名称 key value

存多个值: hmset 名称 多个key value

取值: hget  名称 key

取多个值: hmset 名称 多个 key 

取全部值: hgetall 名称

删除: hdel 名称 多个key

增加数字: hincrby 名称 key value

判断指定属性是否存在: hexists 名称 字段

获得长度: hlen 名称

获得所有key: hkeys 名称

获得所有值: hvals 名称 

存储list

  • ArrayList使用数组方式
  • linkedlist使用双向链接的方式
  • 双向链表增加数据
  • 双向链表删除数据

两端添加:

左侧添加:lpush 列表名 多个value  先添加的最后读到

右侧添加:rpush 列表名 多个value  先添加的最先读到

两端弹出

左边弹出:lpop 列表名 弹出最左边元素

右边弹出:rpop 列表名 弹出最右边元素

查看列表:lrange 列表名 范围(0 5  表示0-5, 0 -2 表示0-倒数第二个)

查看长度: llen 列表名

仅当列表存在时向头部插入元素: lpushx 列表名 value

仅当列表存在时向尾部插入元素: rpushx 列表名 value

从头删除n个某元素: lrem 列表名  n  元素值

从尾删除n个某元素: lrem 列表名  -n  元素值

删除所有某元素: lrem 列表名  0  元素值

设置列表指定位置元素的值:lset 列表名 角标值 指定的值

在某个元素前/后插入元素: linsert  列表名 before/after 元素值  要插入的值

rpoplpush 列表1 列表2 : 将列表1的尾部弹出,插入到列表2首部

rpoplpush使用场景

redis列表经常用于消息队列,以及多个程序之间的消息交互

例如:用rpoplpush在弹出的同时将消息备份,避免信息的丢失

存储set

set可以看作没有排序的list,与list不同的是,set集合中不允许出现重复的元素

set可以在服务器端高效率地完成多个set之间的聚合,可以节省大量网络的开销。

常用命令

添加:sadd set名 多个值

删除:srem set名 多个值

判断元素是否在set内存在: sismember set名 元素

获得集合中的元素:smembers set名(随机顺序?奇怪的顺序)

集合中的差值运算:sdiff set1 set2  (与顺序有关)

集合的交集运算:sinter set1 set2

集合的并集运算:sunion set1 set2

将差值存到另一个集合:sdiffstroe 要存到的集合 集合1 集合2

交集、并集同理

返回集合内的成员数量: scard myset

随机返回一个成员: srandmember set名

使用场景:

  • 跟踪一些唯一性数据
  • 用于维护数据对象之间的关联关系

储存Sort—Set

和set相比:sort-set会进行排序,只允许分数重复,删除和更新一个成员时,效率很高

常用于:游戏排行榜,热点排行

添加元素:zadd  set名 分数 姓名 分数 姓名

获得分数: zscore set名 姓名

获取元素数量:zcard set名

删除元素 :zrem  set名 姓名 姓名

按照排名范围查找(显示分数):zrange set名 范围 ( withscores)从小到大

按照排名范围查找(显示分数):zrevrange set名 范围 ( withscores)从大到小

按照分数范围查找(显示分数):zrevrangebyscore set名 分数范围 ( withscores)从大到小

按照分数范围删除: zremrangebyscore set名 分数范围

按照排名范围删除: zremrangebyrank set名 排名范围

limit 限制个数  eg: 0 2 表示 0-2

设置指定成员增加分数:zincrby set名 分数 姓名

统计分数在某个范围的个数:zcount set名 分数范围

Keys的通用操作 

查看所有key : keys * (可以模糊查找)

支持的通配符

第一种:*
第二种:?
第三种:[]

* 通配符

匹配多个字符

 Redis_第1张图片  

?通配符

作用是匹配一个字符

eg:

// 知道前面的一些字母,忘记了最后一个字母
keys hell?
// 只记得第一个字母是h,他的长度是5
keys h????

[ ]匹配

作用是匹配括号内的一个字符,一次匹配只能使用一次[ ]

// 知道前面四个字母,最后一个字母有可能是o p t 其中的一个

keys hell[opt]

Redis_第2张图片

删除key: del key1 key2

判断key是否存在:exists key

设置过期时间:expire key 过期时间

查看所剩时间:ttl  key   如果没有设置返回-1

查看key的类型:type key

redis特性

多数据库

一个redis实例最多可以提供16个数据库,默认是0号数据库

可以通过select来选择数据库

将某个数据库的key移动到另一个数据库: move key 要移动到的数据库

事务

multi 开始exec提交 discard回滚 三个命令实现事务

用处:

Redis能保证一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令。

redis的事务执行exec之后让队列中的所有命令作为一个不可分割的整体逐一执行,redis会逐个执行完队列中的命令,之后才会执行其他客户端发来的命令。

单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

编译异常:命令都不会执行
运行异常:正确命令会执行,错误命令不执行

redis监视

redis使用watch key命令监视一个key,实现乐观锁。监视时获取key的版本号,提交事务时,如果发现key的被其他线程修改,那么当前事务执行失败。(watch仅在一次事务中生效)

unwatch key 可以解锁(使用场景尚且不知道)

脚本

Redis 脚本使用 Lua 解释器来执行脚本。 Redis 2.6 版本通过内嵌支持 Lua 环境。执行脚本的常用命令为 EVAL

1.为什么要用脚本

使用脚本的优势:

减少网络开销:多个请求通过脚本一次发送,减少网络延迟

原子操作:将脚本作为一个整体执行,中间不会插入其他命令,无需使用事务

复用:客户端发送的脚本永久存在redis中,其他客户端可以复用脚本

可嵌入性:可嵌入JAVA,C#等多种编程语言,支持不同操作系统跨平台交互

2.基本用法

eval 脚本 numkeys   key [key...]  arg[arg...]

向脚本赋值

Redis_第3张图片

 脚本里的KEYS 和 ARGV 必须是大写。

SCRIPT LOAD script 

把脚本加载到脚本缓存中,返回SHA1校验和。但不会立马执行。

EVALSHA sha1 numkeys key [key ...] arg [arg ...] 

根据缓存码执行脚本内容

Redis_第4张图片

SCRIPT EXISTS script [script ...] 

通过sha1校验和判断脚本是否在缓存中

Redis_第5张图片

SCRIPT FLUSH 

清空缓存

使用

直接在redis-cli中直接写lua脚本,这样非常不方便编辑,通常情况下都是把lua script放到一个lua文件中,然后执行这个lua脚本,脚本地址:/home/ygw/activeuser.lua

Redis_第6张图片

 注意后面的两个参数的空格

Redis_第7张图片

3. 脚本的安全性

脚本也存在安全隐患,如生成随机数这一命令,如果在master上执行完后,再在slave上执行会不一样,这就破坏了主从节点的一致性。

为了解决这个问题, Redis 对 Lua 环境所能执行的脚本做了一个严格的限制 —— 所有脚本都必须是无副作用的纯函数(pure function)。

Redis 对 Lua 环境做了一些列相应的措施:

  1. 不提供访问系统状态状态的库(比如系统时间库)
  2. 禁止使用 loadfile 函数 如果脚本在执行带有随机性质的命令(比如 RANDOMKEY ),或者带有副作用的命令(比如 TIME )之后,试图执行一个写入命令(比如 SET ),那么 Redis 将阻止这个脚本继续运行,并返回一个错误。
  3. 如果脚本执行了带有随机性质的读命令(比如 SMEMBERS ),那么在脚本的输出返回给 Redis 之前,会先被执行一个自动的字典序排序,从而确保输出结果是有序的。
  4. 用 Redis 自己定义的随机生成函数,替换 Lua 环境中 math 表原有的 math.random 函数和 math.randomseed 函数,新的函数具有这样的性质:每次执行 Lua 脚本时,除非显式地调用 math.randomseed ,否则 math.random 生成的伪随机数序列总是相同的。

密码登录(默认没有密码)

auth abcd2019

redis stream

Redis Stream 主要用于消息队列),Redis 本身是有一个 Redis 发布订阅来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅可以分发消息,但无法记录历史消息。

而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

Redis_第8张图片

每个 Stream 都有唯一的名称,它就是 Redis 的 key,在我们首次使用 xadd 指令追加消息时自动创建。

上图解析:

  • Consumer Group :消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer)。
  • last_delivered_id :游标,每个消费组会有个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。
  • pending_ids :消费者(Consumer)的状态变量,作用是维护消费者的未确认的 id。 pending_ids 记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符)。

消息队列相关命令:

  • XADD - 添加消息到末尾
  • XRANGE - 获取消息列表,会自动过滤已经删除的消息(-代表最小值,+代表最大值,count限制数量)
  • XREVRANGE - 反向获取消息列表,ID 从大到小

Redis_第9张图片

  • XDEL - 删除消息
  • XLEN - 获取流包含的元素数量,即消息长度
  • XTRIM - 对流进行修剪,限制长度  
  • XREAD - 以阻塞或非阻塞方式获取消息列表

消费者组相关命令:

  • XGROUP CREATE - 创建消费者组
  • XREADGROUP GROUP - 读取消费者组中的消息

Redis_第10张图片

 >是个特殊的ID,表示消息到目前为止从未传递给其他消费者

也可以指定一个真实的ID,比如0或者任何其他有效的ID

基本上XREADGROUP可以根据我们提供的ID有以下行为:

如果ID是特殊ID >,那么命令将会返回到目前为止从未传递给其他消费者的新消息,这有一个副作用,就是会更新消费者组的最后ID。

如果ID是任意其他有效的数字ID,那么命令将会让我们访问我们的历史待处理消息。

  • XACK - 将消息标记为"已处理"
  • XGROUP SETID - 为消费者组设置新的最后递送消息ID
  • XGROUP DELCONSUMER - 删除消费者
  • XGROUP DESTROY - 删除消费者组
  • XPENDING - 显示待处理消息的相关信息
  • XCLAIM - 转移消息的归属权
  • XINFO - 查看流和消费者组的相关信息;
  • XINFO GROUPS - 打印消费者组的信息;
  • XINFO STREAM - 打印流信息

redis 数据备份与恢复

RDB快照备份:

SAVE

该命令将在 redis 安装目录中创建dump.rdb文件。

Redis_第11张图片

 如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。获取 redis 目录可以使用 CONFIG 命令。

Bgsave

创建 redis 备份文件也可以使用命令 BGSAVE,该命令在后台执行。

全持久化AOF模式:

如果数据很重要无法承受任何损失,可以考虑使用AOF方式进行持久化,默认Redis没有开启AOF(append only file)方式的全持久化模式。

在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些,开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。

AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改该名称。

Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少,可以在redis.conf中通过appendonly参数开启Redis AOF全持久化模式:

Redis AOF持久化参数配置详解:

appendonly  yes                    #开启AOF持久化功能;
appendfilename appendonly.aof          #AOF持久化保存文件名;
appendfsync always                     #每次执行写入都会执行同步,最安全也最慢;
#appendfsync everysec                  #每秒执行一次同步操作;
#appendfsync no                    #不主动进行同步操作,而是完全交由操作系统来做,每30秒一次,最快也最不安全;
auto-aof-rewrite-percentage  100      #当AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据;
auto-aof-rewrite-min-size    64mb      #允许重写的最小AOF文件大小配置写入AOF文件后,要求系统刷新硬盘缓存的机制。

Redis 性能测试

该命令是在 redis 的目录下执行的,而不是 redis 客户端的内部指令。

Redis_第12张图片

redis 性能测试工具可选参数(菜鸟教程):

Redis_第13张图片

redis持久化

将数据从内存同步到硬盘上

通过RDB或AOF,都可以将redis内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到云服务,如果redis挂了,服务器上的内存和磁盘上的数据都丢了,可以从云服务上拷贝回来之前的数据,放到指定的目录中,然后重新启动redis,redis就会自动根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务。

两种持久化方式

  • RDB方式
  • AOF方式

RDB:默认支持,不需要配置,在指定的时间间隔内,将内存中的数据及快照写入到磁盘中,对redis中的数据执行周期性的持久化。

RDB持久化机制的优点

  1. RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去
  2. RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
  3. 相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速

RDB持久化机制的缺点

  1. 如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据。
  2. RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。

AOF:对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集。

AOF持久化机制的优点

  1. AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据
  2. AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
  3. AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。
  4. AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据。

AOF持久化机制的缺点

  1. 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
  2. AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync(同步内存中所有已修改的文件数据到日志中),性能也还是很高的。
  3. 通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。

RDB和AOF到底该如何选择

仅仅使用RDB,会导致你丢失很多数据

仅仅使用AOF,有两个问题,第一,AOF做冷备不如RDB做冷备;第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug。

综合使用AOF和RDB两种持久化机制用AOF来保证数据不丢失,作为数据恢复的第一选择;

用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复。

如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整。

如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制。

在短网址服务项目中,redis作为缓存,使用RDB做持久化,比较合情合理:宕机发生的概率较小,且丢失一部分缓存数据代价较小,同时使用RDB来做持久化性能损耗相比于AOF较少,也能数据库数据库压力稳定。

 Redis主从复制备份

通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据。但是由于数据是存储在一台服务器上的,如果这台服务器的硬盘出现故障,也会导致数据丢失。

为了避免单点故障,我们希望将数据库复制多个副本以部署在不同的服务器上,即使只有一台服务器出现故障其他服务器依然可以继续提供服务。

这就要求当一台服务器上的数据库更新后,可以自动将更新的数据同步到其他服务器上,Redis提供了复制(replication)功能可以自动实现同步的过程。

通过配置文件在Redis从数据库中配置文件中加入slaveof  master-ip  master-port即可,主数据库无需配置。

Redis主从复制优点及应用场景, WEB应用程序可以基于主从同步实现读写分离以提高服务器的负载能力。在常见的场景中,读的频率一般比较大,当单机Redis无法应付大量的读请求时,可以通过复制功能建立多个从数据库,主数据库只进行写操作,而从数据库负责读操作,还可以基于LVS+keepalived+Redis对Redis实现均和高可用。

       从数据库持久化,持久化通常相对比较耗时,为了提高性能,可以通过复制功能建立一个(或若干个)从数据库,并在从数据库中启用持久化,同时在主数据库禁用持久化。

        当从数据库崩溃时重启后主数据库会自动将数据同步过来,所以无需担心数据丢失。而当主数据库崩溃时,需要在从数据库中使用SLAVEOF NO ONE命令将从数据库提升成主数据库继续服务,并在原来的主数据库启动后使用SLAVE  OF命令将其设置成新的主数据库的从数据库,即可将数据同步回来。

Redis 管道技术

Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。这意味着通常情况下一个请求会遵循以下步骤:

  • 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。
  • 服务端处理命令,并将结果返回给客户端。

Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。

管道是将批量的请求放到一起变成一次请求,减少了网络的消耗。不用管道的话10W个查询要发10W个redis请求,用管道把10W个请求一次发过去。

Redis_第14张图片

与事务侧重点不一样:管道是将批量的请求放到一起变成一次请求,减少了网络的消耗。

而事务是将事务里的命令看作一个不可分割的整体逐一执行,redis会逐个执行完事务中的命令,之后才会执行其他客户端发来的命令。

Redis分区

为什么要分区?

1. 性能的提升,单机Redis的网络I/O能力和计算资源是有限的,将请求分散到多台机器,充分利用多台机器的计算能力可网络带宽,有助于提高Redis总体的服务能力。

2、存储的横向扩展,即使Redis的服务能力能够满足应用需求,但是随着存储数据的增加,单台机器受限于机器本身的存储容量,将数据分散到多台机器上存储使得Redis服务可以横向扩展。

分区的方式

1. 范围分区

范围分区就是把一个范围内的key都映射到一个Redis实例上。

例如将用户ID从0到10000的用户数据映射到R0实例,而将用户ID从10001到20000的对象映射到R1实例,依次类推。

优势:

简单、有效

劣势(存在的问题):

每种对象类型都需要一张表来记录映射关系,并且需要对这张表进行维护。

存储数据的key如果不能按照范围划分,就不能使用范围分区了。

2. 哈希分区

哈希分区通过一个哈希函数计算出分区位置。

哈希分区适合任何形式的key。

分区的实现

1. 客户端实现

Redis_第15张图片

 key在redis客户端就决定了要被存储在那台Redis实例中

2. 代理实现

Redis_第16张图片

​客户端将请求发往代理服务器,代理服务器实现了Redis协议,因此代理服务器可以代理客户端和Redis服务器通信。

代理服务器通过配置的分区schema来将客户端的请求转发到正确的Redis实例中,同时将反馈消息返回给客户端。 ​

3. 查询路由

Redis_第17张图片

客户端随机地请求任意一个redis实例,然后由Redis将请求转发给正确的Redis节点。

Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,而是在客户端的帮助下直接重定向到正确的redis节点。

分区下的持久存储和缓存

尽管数据分区对于Redis来说无论是数据持久化存储还是缓存,在概念上都是一样的,然而对于数据持久化存储还是有一个很大的限制。

当我们使用Redis来作为持久化存储的时候,每一个key必须一直被映射到同一个Redis实例。而当Redis被当做缓存使用的时候,对于这个key,如果一个实例不能用了,这个key还可以被映射到其他的实例中。

Consistent hashing的实现通常使得当一个key被映射到的实例不能用的时候将这个key映射到其他实例成为可能。

如果增加了一台机器,一部分的key将会被映射到这台新的机器上:

1、如果Redis被用来当做缓存,且要求容易增加或删除机器,使用consistent hashing是非常简单的。

2、如果Redis被用来当做(持久)存储,一个固定的key到实例的映射是需要的,因此我们不能够再灵活的添加或删除机器。否则,我们需要在增加或删除机器的时候系统能够rebalace,当前Redis Cluster已经支持。

分区的缺点

1、多键操作是不被支持的,比如我们将要批量操作的键被映射到了不同的Redis实例中

2、多键的Redis事务是不被支持的。

3、分区的最小粒度是键,因此我们不能将关联到一个键的很大的数据集映射到不同的实例。

4、当应用分区的时候,数据的处理是非常复杂的,比如我们需要处理多个rdb/aof文件,将分布在不同实例的文件聚集到一起备份。

5、添加和删除机器是很复杂的,例如Redis集群支持几乎运行时透明的因为增加或减少机器而需要做的rebalancing,然而像客户端和代理分区这种方式是不支持这种功能的。

Redis哨兵模式

Redis主从切换方法是:当主服务器宕机以后,需要手动把一台服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间内服务不可用。

Redis的哨兵模式可以帮助我们很好地实现主从切换。

什么是哨兵模式?

哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。

其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

哨兵有两个作用:

  • 监控Redis服务器的运行状态,包括主服务器和从服务器。

  • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

单个哨兵对Redis服务器进行监控可能会出现问题。为了避免误操作,可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。

哨兵模式下故障切换(主从切换)

假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行故障切换过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线

当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,如果投票成功,由一个哨兵进行故障切换操作。

切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线


 

你可能感兴趣的:(笔记,redis,数据库)