Redis 特点

单线程

执行过程按顺序执行,不会同时执行多个操作,保证操作的原子性,省去了很多上下文切换线程的时间,不必考虑资源竞争和可能出现死锁。

为什么使用单线程 ?

官方FAQ表示:因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。

性能高

官方数据:Redis 能读的速度是 110000次/s,写的速度是 81000次/s。这是因为 Redis 的命令操作都是在内存中进行,可以在纳秒级别就处理完,使用了 epoll 非阻塞 IOepoll 是目前最好的多路复用技术,减少网络 IO 的时间消耗。

注:多路指的是多个网络连接,复用指的是复用同一个线程

丰富的数据类型

基本类型:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)。

扩展类型:HyperLogLoggeobitmap

  • HyperLogLog(string):实现独立用户的统计,会用 0.81% 误差。
  • geo(zset):记录地理位置信息,可以计算两个地点的距离或是某个点的周边范围。
  • bitmap(string):可以实现用户签到等功能,大幅度减少内存消耗。
Bitmap 对于一些特定类型的计算非常有效。如使用 bitmap 实现用户上线次数统计

假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 A 上线了多少天,用户 B 上线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加 beta 测试等活动 —— 这个模式可以使用 SETBIT key offset value 和 BITCOUNT key [start] [end] 来实现。

比如说,每当用户在某一天上线的时候,我们就使用 SETBIT key offset value ,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1 。

举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 SETBIT peter 100 1 ;如果明天 peter 也继续阅览网站,那么执行命令 SETBIT peter 101 1 ,以此类推。

当要计算 peter 总共以来的上线次数时,就使用 BITCOUNT key [start] [end] 命令:执行 BITCOUNT peter ,得出的结果就是 peter 上线的总天数。

Redis 使用场景

热点数据缓存、秒杀、计数器、并发锁、消息队列、分布式 Session、限时/限数(验证码过期,错误次数等)、防爬虫(请求次数在单位时间内超过制定数组则可认为被爬虫采集)。除此之外,Redis 支持事务 、持久化、Lua 脚本、LRU 驱动事件、多种集群方案。

事务

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

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

1、批量操作在发送 EXEC 命令前被放入队列缓存。

2、收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。但出现错误时 ,整个事务会被取消。

3、在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

multi
incr num
incr num
exec
get num #2 # 使用 watch 可以监控某个key值发生变化时,事务会被打断
watch num # A 机器
multi num # A 机器
inrc num # A 机器
inrc num # B 机器
exec # A 机器 ,返回 nil,即操作被打断 discard # 取消事务
unwatch # 取消监视

管道 Pipeline

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

-> 客户端向服务端发送一个查询请求,并监听 Socket 返回,通常是以阻塞模式,等待服务端响应。

-> 服务端处理命令,并将结果返回给客户端。

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

$pipe = $redis->multi(Redis::PIPELINE);   //开启管道
for($i= 0 ; $i<  10000 ; $i++) {
       $pipe->set("key::$i",str_pad($i, 4,'0', 0));
       $pipe->get("key::$i");
}
$pipe->exec(); //提交管道里操作命令

管道和事务的区别

1、Pipeline 选择客户端缓冲,multi 选择服务端缓冲。

2、请求次数的不一致,multi 需要每个命令都发送一次给服务端,Pipeline 最后一次性发送给服务端,请求次数相对于 multi 减少。

3、multi/exec 可以保证原子性,而 Pipeline 不保证原子性。

发布/订阅

Redis 提供的发布/订阅功能只是一个低配版的,无法对消息持久化存储。一旦消息被发送,如果没有订阅者接收,那么消息就会丢失。Redis 并没有提供消息传输保障。如果系统中已经有了Redis,并且只需要基本的发布订阅功能,对消息的安全性没有高要求,那就可以使用 Redis 的发布/订阅功能。

subscribe news
publish news hello # unsubscribe 取消订阅

阻塞队列

使用系统提供的阻塞原语,在新元素到达时立即进行处理,而新元素还没到达时,就一直阻塞住,避免轮询占用资源。也可以实现类似于抢票的功能。

brpop ticket 30 # 0表示一直等待
lpush ticket home

Redis 持久化

RDB 持久化

RDB 持久化是把当前进程数据生成快照保存到硬盘的过程,触发 RDB 持久化过程分为手动触发 save 和自动触 bgsave

save 900 1  # 900 秒之内,如果超过 1 个 key 被修改,则发起快照保存;
save 300 10 # 300 秒内,如果超过 10 个 key 被修改,则发起快照保存;
save 60 10000 # 1 分钟之内,如果 1 万个 key 被修改,则发起快照保存;

优点:

1、RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每6小时执行 bgsave 备份,并把 RDB 文件拷贝到远程机器或者文件系统中(如hdfs),用于灾难恢复。

2、Redis 加载 RDB 恢复数据远远快于 AOF 的方式。

缺点:

1、RDB 方式数据没办法做到实时持久化/秒级持久化。因为 bgsave 每次运行都要执行 fork 操作创建子进程,属于重量级操作,频繁执行成本过高。

2、RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个格式的 RDB 版本,存在老版本 Redis 服务无法兼容新版 RDB 格式的问题。针对 RDB 不适合实时持久化的问题,Redis 提供了 AOF 持久化方式来解决。

AOF 持久化

AOF(append only file) 持久化:以独立日志的方式记录每次写命令,重启时再重新执行 AOF 文件中的命令达到恢复数据的目的。AOF 的主要作用是解决了数据持久化的实时性,目前已经是Redis 持久化的主流方式。

AOF 工作流程:

-> 将命令转换成协议文本。

-> 所有的写入命令会追加到 aof_buf(缓冲区)中。

-> AOF 缓冲区根据对应的策略向硬盘做同步操作 everysec

-> 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。

-> 当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。

重写机制:

1、REWRITE 在主线程中重写 AOF,会阻塞工作线程,在生产环境中很少使用,处于废弃状态。

2、BGREWRITE 在后台(子进程)重写 AOF, 不会阻塞工作线程,能正常服务,此方法最常用 bgrewriteaof

开启 AOF,通过修改 redis.conf 配置文件

appendonly yes    ##默认不开启。
# appendfsync always
appendfsync everysec ## 默认每秒同步一次
# appendfsync no

AOF 文件名通过 appendfilename 配置设置,默认文件名 appendonly.aof 。保存路径同 RDB 持久化方式一致,通过 dir 配置指定。

AOF 后台 Rewrite 解决方案:

1、官方解决方案:主要思路是 AOF 重写期间,主进程跟子进程通过管道通信,主进程实时将新写入的数据发送给子进程,子进程从管道读出数据交缓存在 buffer 中,子进程等待存量数据全部写入 AOF 文件后,将缓存数据追加到 AOF 文件中,此方案只是解决阻塞工作线程问题,但占用内存过多问题并没有解决。

2、新解决方案:主要思路是 AOF 重写期间,主进程创建一个新的 aof_buf,新的 AOF 文件用于接收新写入的命令,sync 策略保持不变,在 AOF 重写期间,系统需要向两个 aof_buf,两个 AOF 文件同时追加新写入的命令。当主进程收到子进程重写 AOF 文件完成后,停止向老的 aof_bufAOF 文件追加命令,然后删除旧的 AOF 文件(流程跟原来保持一致)。将子进程新生成的 AOF 文件重命名为 appendonly.aof.last,具体流程如下:

-> 停止向旧的 aof_bufAOF 文件追加命令。

-> 删除旧的的 appendonly.aof.last 文件。

-> 交换两个 aof_bufAOF 文件指针。

-> 回收旧的 aof_bufAOF 文件。

-> 重命令子进程生成的 AOF 文件为 appendonly.aof.last

系统运行期间同时存在两个 AOF 文件,一个是当前正在写的 AOF,另一个是存量的 AOF 数据文件。因此需要修改数据库恢复相关逻辑,加载 AOF 时先要加载存量数据 appendonly.aof.last,再加载 appendonly.aof

混合持久化

AOF 持久化方式在重启加载数据的时候,效率远不如 RDB 方式。因此,Redis 官方在 4.0 版本之后,引入了混合持久化的方式。配置选项是 aof-use-rdb-preambleyes 表示开启。策略是在生成或者写入 AOF 文件时,将 RDB 数据写在前面。AOF 数据追加在后面。在每次重新启动的时候,先加载 RDB,再加载 AOF。

具体的配置如下:

# When rewriting the AOF file, Redis is able to use an RDB preamble in the
# AOF file for faster rewrites and recoveries. When this option is turned
# on the rewritten AOF file is composed of two different stanzas:
#
# [RDB file][AOF tail]
#
# When loading Redis recognizes that the AOF file starts with the "REDIS"
# string and loads the prefixed RDB file, and continues loading the AOF
# tail.
aof-use-rdb-preamble yes

主从复制

在主从复制的概念中,数据库分为两类,一类是主数据库 master,另一类是从数据库[1] slave。主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。而从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。

优点:

1、实现了对 Master 数据的备份,一旦 Master 出现故障,Slave 节点可以提升为新的 Master,顶替旧的 Master 继续提供服务(需要手动切换)。

2、实现读扩展,使用主从复制架,一般都是为了实现读扩展。Master 主要实现写功能, Slave 实现读的功能。

缺点:

1、当 Maser 宕机后,需要人工参与。

-> 在 Slave1 上执slaveof no one 命令提升 Slave1 为新的 Master 节点。

-> 在 Slave1 上配置为可写,这是因为大多数情况下,都将 Slave 配置只读。

-> 告诉 Client 端(也就是连接 Redis 的程序)新的 Master 节点的连接地址(改代码)。

-> 配置 Slave2 从新的 Master 进行数据复制。

2、虽然实现了读写分离,但是主节点的性能会成为主要瓶颈。

Sentinel 哨兵机制

Redis SentinelRedis 提供了高可用方案。从实践方面来说,使用 Redis Sentinel 可以创建一个无需人为干预就可以预防某些故障的 Redis 环境。实现自动切换。在部署 Sentinel 的时候,建议使用奇数个 Sentinel 节点,最少三个 Sentinel 节点。

功能:

1、 监控,Sentinel 会不断的检查 masterslave 是否像预期那样正常运行。

2、通知,通过 APISentinel 能够通知系统管理员、程序监控的 Redis 实例出现了故障。

3、自动故障转移,如果 Master 不像预想中那样正常运行,Sentinel 可以启动故障转移过程,其中的一个 Slave 会提成为 Master,其它 Slave 会重新配置来使用新的 Master,使用Redis 服务的应用程序,当连接时,也会被通知使用新的地址。

4、配置提供者,Sentinel 可以做为客户端服务发现的认证源:客户端连接 Sentinel 来获取目前负责给定服务的 Redis master 地址。如果发生故障转移,Sentinel 会报告新的地址。

三个定时任务

  • 每 10 秒每个 sentinelmasterslave 执行 info replication,以发现新的 slave 节点并确认主从关系。
  • 每 2 秒每个 sentinel 通过 master 节点的 channel__sentinel__:hello)交换信息,以交换对节点的”看法“和自身信息。
  • 每 1 秒每个 sentinel 对其他 sentinel 和主、从节点发送 ping 命令来做心跳检测。

故障切换实现原理

  • Sentinel 之间进行选举,选举出一个 leader ,由选举出的 leader 进行 failover
  • Sentinel leader 选取 slave 节点中的一个 slave 作为新的 Master 节点。对 slave 选举需要对 slave 进行选举的方法如下:
    • master 断开时间,如果与 Master 断开的时间超过 down-after-milliseconds (sentinel配置) * 10秒加上从 sentinel 判定 Master 不可用到 sentinel 开始执行故障转移之间的时间,就认为该 Slave 不适合提升为 Master
    • slave 优先级,每个 Slave 都有优先级,保存在 redis.conf 配置文件里。如果优先级相同,则继续进行。
    • 复制偏移位置,复制偏移纪录着从 Master 复制数据复制到哪里,复制偏移越大表明从 Master 接受的数据越多,如果复制偏移量也一样,继续进行选举。
    • Run ID,选举具有最小 Run IDSlave 作为新的 Master
  • Sentinel leader 会在上一步选举的新 master 上执行 slaveof no one 操作,将其提升为 master 节点。
  • Sentinel leader 向其它 slave 发送命令,让剩余的 slave 成为新的 master 节点的 slave
  • Sentinel leader 会让原来的 master 降级为 slave,当恢复正常工作,Sentinel leader 会发送命令让其从新的 master 进行复制。

配置文件说明

daemonize yes #以后台进程模式运行

port 27000 # 哨兵的端口号,该端口号默认为26379。

#redis-master

sentinel monitor redis-master 192.168.1.51 7000 2

# redis-master是主数据的别名,考虑到故障恢复后主数据库的地址和端口号会发生变化,哨兵提供了命令可以通过别名获取主数据库的地址和端口号。
# 192.168.1.51 7000为初次配置时主数据库的地址和端口号,当主数据库发生变化时,哨兵会自动更新这个配置,不需要我们去关心。
# 2,该参数用来表示执行故障恢复操作前至少需要几个哨兵节点同意,一般设置为N/2+1(N为哨兵总数)。 sentinel down-after-milliseconds redis-master 5000
#如果master在多少秒内无反应哨兵会开始进行master-slave间的切换,使用“选举”机制 sentinel failover-timeout redis-master 900000
# 如果master 在 900000 秒后恢复,则把它加入到 slave 中 logfile "/data/bd/redis/sentinel/sentinel.log" #log文件所在地

Docker+Redis 实例

设置配置

# redis-master.conf
port 7000
daemonize yes
pidfile /var/run/redis.pid
logfile "7000.log" sed 's/7000/7001/g' redis-master.conf > redis-slave1.conf
sed 's/7000/7002/g' redis-master.conf > redis-slave2.conf echo "slaveof redis-master 7000" >> redis-slave1.conf
echo "slaveof redis-master 7000" >> redis-slave2.conf

启动 Redis-Master 容器

# 启动 Redis-Master容器
sudo docker run -d -p 7000:7000 -v /home/summer/homework/redis/config/redis-master.conf:/etc/redis/redis.conf --name redis-master redis redis-server /etc/redis/redis.conf

启动 Redis-Slave 容器

# 启动 Redis-Slave1 容器
sudo docker run -d -p 7001:7001 -v /home/summer/homework/redis/config/redis-slave1.conf:/etc/redis/redis.conf --name redis-slave1 --link redis-master:master redis redis-server /etc/redis/redis.conf # 启动 Redis-Slave2 容器
sudo docker run -d -p 7002:7002 -v /home/summer/homework/redis/config/redis-slave2.conf:/etc/redis/redis.conf --name redis-slave2 --link redis-master:master redis redis-server /etc/redis/redis.conf

注意问题

1、禁止线上执行 keys *msetmgethmgethmset 等操作,会造成阻塞。

2、避免同一时间缓存大面积失效,造成缓存雪崩。

3、内存数据库,键名长度影响有限内存空间,所以命名应该控制长度,简短易懂。

4、大小写规范。

5、根据业务命名,相同业务统一的 Key 前缀。

常用命令

debug sleep 10

config set xx yy

config  get  xx*

info replication  # 查看主从信息

info server

info sentinel

参考资料

Redis 的简单介绍的更多相关文章

  1. Redis主从复制简单介绍

    由于本地环境的使用,所以搭建一个本地的Redis集群,本篇讲解Redis主从复制集群的搭建,使用的平台是Windows,搭建的思路和Linux上基本一致! (精读阅读本篇可能花费您15分钟,略读需5分 ...

  2. Redis的简单介绍及在Windows下环境搭建

    简单介绍 1,Redis是什么 最直接的还是看官方的定义吧. Redis is an open source (BSD licensed), in-memory data structure stor ...

  3. Redis实战——简单介绍

    出自:https://www.cnblogs.com/moonlightL/p/7364107.html Redis简单介绍 Redis是一个开源,高级的键值存储和一个适用的解决方案,用于构建高性能, ...

  4. redis之(一)redis的简单介绍

    [一]:概念 --->Redis是一个开源的,高性能的,基于键值对的缓存与存储系统 --->Redis数据库中的多有数据都存储在内存中,由于内存的读写速度远快于硬盘,一秒读写超过10万键值 ...

  5. Python redis 简单介绍

    Python redis 简单介绍 1.安装 终端输入: pip(or)pip3.6 install redis 安装成功 2.哈哈,发现我并没有redis服务可以访问,所以到这里,在本机安装了red ...

  6. Redis简单介绍

    redis简单介绍 Redis VS key-value缓存产品 Redis支持数据的持久化,能够将内存中的数据保持在磁盘中,重新启动的时候能够再次载入进行使用. Redis不只支持简单的key-va ...

  7. Redis简单介绍以及数据类型存储

    因为我们在大型互联网项目其中.用户訪问量比較大,比較多.会产生并发问题,对于此.我们该怎样解决呢.Redis横空出世,首先,我们来简单的认识一下Redis.具体介绍例如以下所看到的: Redis是一个 ...

  8. 消息队列介绍、RabbitMQ&Redis的重点介绍与简单应用

    消息队列介绍.RabbitMQ&Redis的重点介绍与简单应用 消息队列介绍.RabbitMQ.Redis 一.什么是消息队列 这个概念我们百度Google能查到一大堆文章,所以我就通俗的讲下 ...

  9. C#中Fun简单介绍及运用到项目中与缓存(本地缓存,Redis)结合使用

     1.简单介绍Fun C#中Fun和Action有点类似,都是一个委托方法,不同的是Func是有返回值的,而Action没有. (T)此委托封装的方法的参数类型. 备注:详情了解Fun到(https: ...

  10. Redis常用数据类型介绍、使用场景及其操作命令

    Redis常用数据类型介绍.使用场景及其操作命令 本文章同时也在cpper.info发布. Redis目前支持5种数据类型,分别是: 1.String(字符串) 2.List(列表) 3.Hash(字 ...

随机推荐

  1. SpringBoot+阿里云OCR图片识别

    准备条件:阿里云OCR图片识别API购买,初次购买1分钱500次接口调用 一.控制层 @GetMapping("/uploadManual") @ApiOperation(&quo ...

  2. 痞子衡嵌入式:使能i.MXRT1050,1060 Hab签名或加密启动时App链接在片内SRAM的限制

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是使能i.MXRT1050, 1060 Hab签名或加密启动时App链接在片内SRAM的限制. 最近有客户反馈,在 RT1060 上测试 ...

  3. mysql 简单进阶 ———— 多列索引[一]

    前文 整理一下mysql 的一些简单进阶技巧,来源于高性能mysql,但不是根据书的序列来的. 正文 库地址: https://dev.mysql.com/doc/index-other.html 有 ...

  4. JavaScript如何判断一个元素是否在可视区域中?

    一.用途 可视区域即我们浏览网页的设备肉眼可见的区域,如下图 在日常开发中,我们经常需要判断目标元素是否在视窗之内或者和视窗的距离小于一个值(例如 100 px),从而实现一些常用的功能,例如: 图片 ...

  5. python爬虫实战以及数据可视化

    需要准备的环境: (1)python3.8 (2)pycharm (3)截取网络请求信息的工具,有很多,百度一种随便用即可. 第一:首先通过python的sqlalchemy模块,来新建一个表. 第二 ...

  6. js判断元素内文字是否超出元素宽度,溢出隐藏

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 基于 PTS 压测轻松玩转问题诊断

    ​简介:性能测试 PTS(Performance Testing Service)是具备强大的分布式压测能力的 SaaS 压测平台,可模拟海量用户的真实业务场景,全方位验证业务站点的性能.容量和稳定性 ...

  8. 【ESSD技术解读-02】企业级利器,阿里云 NVMe 盘和共享存储

    简介: 当前 NVMe 云盘结合了业界最先进的软硬件技术,在云存储市场,首创性同时实现了 NVMe 协议 + 共享访问 + IO Fencing 技术.它在 ESSD 之上获得了高可靠.高可用.高性能 ...

  9. Snowflake如日中天是否代表Hadoop已死?大数据体系到底是什么?

    ​简介: 本文作者关涛是大数据系统领域的资深专家,在微软(互联网/Azure云事业群)和阿里巴巴(阿里云)经历了大数据发展20年过程中的后15年.本文试从系统架构的角度,就大数据架构热点,每条技术线的 ...

  10. Go 调用 Java 方案和性能优化分享

    ​简介: 一个基于 Golang 编写的日志收集和清洗的应用需要支持一些基于 JVM 的算子. ​ 作者 | 响风 来源 | 阿里技术公众号 一 背景 一个基于 Golang 编写的日志收集和清洗的应 ...