Redis——听说你速度跟甲斗一样快?(上)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: Redis——听说你速度跟甲斗一样快?(上)

Redis官网:

https://redis.io

看到标题各位可能有点懵,这里我必须解释一下——假面骑士甲斗王是以速度著称的骑士,在加速模式下可以做到时间静止,在剧场版里甲斗甚至能让时间倒流,可以说是很快很强了

而本文介绍的Redis数据库也是以速度著称,读写速度能达到每秒十万次!

那么开始我们的Redis之旅吧!

初识Redis

Redis 文档

  • Redis 是一个使用 C 语言写成的,开源的 key-value 数据库,与Memcached类似
  • 它支持存储的value 类型相对更多, 包括string(字符串)、list(链表)、set(集合)、zset(sorted set 有序集合)和hash(哈希类型)这些数据类型都支持 push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的
  • 在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率, 数据都是缓存在内存中。区别是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并在此基础上实现了主从同步

特点

  • 速度快,redis虽然是单线程架构,但由于redis的数据是运行在内存中的,所以速度非常快。官方提供的数据是可以达到100000+的QPS(每秒内查询次数)
  • 支持丰富的数据类型,具有五大基本数据类型
  • 支持事务
  • 丰富的功能特性

1.单线程架构

redis是单线程来处理命令的,所以一条命令从客户端到达服务端不会立刻被执行,所有命令都会进入一个队列中,然后被执行。

当然发送命令、返回结果、命令排队并不是像排队那么简单,redis采用了I/O多路复用的技术来解决I/O的问题

既然是单线程架构为什么还这么快?

  • 纯内存访问,Redis将所有数据放在内存中,内存响应时间大约为100纳秒。这是redis达到每秒万级别的访问的重要基础
  • 非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现。加上Redis自身事件处理模型将epoll中的连接,读写,关闭都转换为事件,不在网络I/O上浪费过多时间
  • 单线程避免了不必要的上下文切换、多线程资源竞争所带来的资源消耗

Client和Server请求过程
image-20220810092734753.png
所有命令在一个队列里等待被执行
image-20220810092804946.png

2.安装部署

  • 软件安装
# 安装官方推荐的稳定版本,需要gcc、libc环境
yum install -y wget gcc gcc-c++ make tar openssl openssl-devel cmake
wget http://download.redis.io/redis-stable.tar.gz
tar -zxvf redis-stable.tar.gz
cd redis-stable/
make
make install
mkdir /var/log/redis /var/lib/redis /etc/redis -p
cp redis.conf /etc/redis/redis.conf.bak
cp sentinel.conf /etc/redis/sentinel.conf.bak

# 调整内核参数
echo 'vm.overcommit_memory = 1'>> /etc/sysctl.conf
echo 'net.core.somaxconn = 65535'>> /etc/sysctl.conf
sysctl -p
  • 创建守护进程
cd /usr/lib/systemd/system

#创建redis-server服务
vim redis-server.service
[Unit]
Description=Redis persistent key-value database
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
ExecStop=/usr/bin/killall redis-server
Type=forking
User=root
Group=root
[Install]
WantedBy=multi-user.target


#创建redis-sentinel服务
vim redis-sentinel.service
[Unit]
Description=Redis sentinel HA solution
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/redis-sentinel /etc/redis/sentinel.conf
ExecStop=/usr/bin/killall redis-sentinel
Type=forking
User=root
Group=root
[Install]
WantedBy=multi-user.target

# 重新加载unit
systemctl daemon-reload
  • 配置文件
==================================基础配置
bind 127.0.0.1 # 绑定IP地址
protected-mode yes # 默认yes,开启之后保护你的redis实例,只能本地使用,外网不允许连接和操作
port 6379 # 监听端口
tcp-backlog 511
timeout 0 # 设置客户端连接超时时间
tcp-keepalive 300 # 检测客户端是否健康的周期时间
daemonize yes # 是否以守护进程方式启动
supervised no #no:开机不会自启动;systemed:开机自启动
pidfile /var/run/redis_6379.pid # PID文件
loglevel notice # 日志等级
logfile /var/log/redis/redis.log # 日志文件
databases 16 # 设置数据库的数目

=================================RDB触发条件
save 900 1 #900s操作一次
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes # 当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据
rdbcompression yes # 对于存储到磁盘中的快照,可以设置是否进行压缩存储
rdbchecksum yes # 在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验
dbfilename dump.rdb # 设置快照的文件名
dir /var/lib/redis # 设置快照文件的存放路径

==================================主从复制
slave-serve-stale-data yes
slave-read-only yes # 配置Redis的Slave实例是否接受写操作
repl-diskless-sync no # 主从数据复制是否使用无硬盘复制功能
repl-diskless-sync-delay 5 # 等待时间
repl-disable-tcp-nodelay no # 同步之后是否禁用从站上的TCP_NODELAY
slave-priority 100

==================================AOF相关配置
appendonly no # 默认redis使用的是rdb方式持久化
appendfilename "appendonly.aof" # 文件名
appendfsync everysec # aof持久化策略的配置
no-appendfsync-on-rewrite no # 在aof重写或者写入rdb文件的时候,不执行持久化策略
auto-aof-rewrite-percentage 100 # 当目前aof文件大小超过上一次重写的aof文件大小的百分之多少进行重写
auto-aof-rewrite-min-size 64mb # 设置允许重写的最小aof文件大小
aof-load-truncated yes # 当截断的aof文件被导入的时候,会自动发布一个log给客户端然后load。
lua-time-limit 5000 # 一个lua脚本执行的最大时间

3.启动

启动时使用redis-server,参数是配置文件(可以指定参数配置文件),也可以不指定使其默认加载)

# 启动所有redis-server节点
systemctl enable redis-server && systemctl start redis-server

登录使用redis-cli工具进行登录

[root@localhost ~]# redis-cli --help
redis-cli 3.2.12
Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
-h <hostname> Server hostname (default: 127.0.0.1).
-p <port> Server port (default: 6379).
-s <socket> Server socket (overrides hostname and port).
-a <password> Password to use when connecting to the server.
-r <repeat> Execute specified command N times.
-i <interval> When -r is used, waits <interval> seconds per command.
It is possible to specify sub-second times like -i 0.1.
-n <db> Database number.
-x Read last argument from STDIN.
-d <delimiter> Multi-bulk delimiter in for raw formatting (default: \n).
-c Enable cluster mode (follow -ASK and -MOVED redirections).
[root@localhost ~]# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379>

Redis基础命令

命令手册: http://redisdoc.com/index.html
由于篇幅有限,关于Redis的基础命令就不在这过多介绍了。

Redis 持久化

我们知道,Redis之所以速度飞快的原因是Redis的数据是在内存中运行的。但是这会导致如果机器一旦断电,Redis的数据就会丢失,为了避免这一情况出现,Redis数据持久化机制因此而生

Redis支持RDB和AOF两种持久化机制,持久化功能能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前之间持久化的文件即可实现数据恢复。

简单点说,redis是将数据运行在内存中的,如果出现服务挂掉或者服务器宕机都可以导致数据全部丢失,为了解决这个问题redis提供了两种解决方案,分别是rdb、aof

1.RDB

  • RDB持久是把当前数据生成快照保存到硬盘的过程
  • 触发RDB持久化过程为手动触发和自动触发
  • 优点

    • RDB是一个非常紧凑(compact)的文件,它保存了redis 在某个时间点上的数据集。这种文件
      非常适合用于进行备份和灾难恢复。
    • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
  • 缺点

    • RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创
      建子进程,属于 重量级操作(内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑),频繁
      执行成本过高(影响性能)
    • RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版
      本Redis服务无法兼容新版RDB格式的问题(版本不兼容)
    • 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(数据有丢失)

触发方式

  • 自动触发

主配置文件中的save字段

分别表示每900秒数据发生一次改变、每300秒数据发生10次改变、每60秒数据发生10000次改变会自动触发rdb持久化机制
save 900 1
save 300 10
save 60 10000
  • 手动触发

    • save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存 比较大的实例会造成
      长时间阻塞,线上环境不建议使用。
    • bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后
      自动结束。阻塞只发生在fork阶段,一般时间很短。
    • 默认情况下执行shutdown命令时,如果没有开启AOF持久化功能则 自动执行bgsave。

image-20220809092427545.png

  1. 执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,如果
    存在,bgsave命令直接返回。
  2. 父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞。通过info stats命令查看
    latest_fork_usec选项,可以获取最近一个fork操作的耗时,单位为微秒。
  3. 父进程fork完成后,bgsave命令返回“Background saving started”信息 并不再阻塞父进程,可以
    继续响应其他命令。
  4. 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行
    lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
  5. 进程发送信号给父进程表示完成,父进程更新统计信息,
#运维提示
当遇到坏盘或磁盘写满等情况时,可以通过config set dir{newDir}在线 修改文件路径到可用的磁
盘路径,之后执行bgsave进行磁盘切换,同样适用 于AOF持久化文件。

Redis默认采用LZF算法对生成的RDB文件做压缩处理,压缩后的文件远远小于内存大小,默认开
启,可以通过参数config set rdbcompression{yes|no}动态修改。

如果想要恢复相关数据,只需要将相关的RDB文件拷贝到相关的目录下面即可,redis启动时会自动
将rdb文件里的内容加载到内存中。

2.AOF

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

    • AOF 持久化的方法提供了多种的同步频率,即使使用默认的同步频率每秒同步一次,Redis 最多也就丢失 1 秒的数据而已
    • AOF 文件使用 Redis 命令追加的形式来构造,因此,即使 Redis 只能向 AOF 文件写入命令的
      片断,使用 redis-check-aof 工具也很容易修正 AOF 文件。
    • AOF 文件的格式可读性较强,这也为使用者提供了更灵活的处理方式。例如,如果我们不小
      心错用了 FLUSHALL 命令,在重写还没进行时,我们可以手工将最后的 FLUSHALL 命令去
      掉,然后再使用 AOF 来恢复数据
  • 缺点

    • 对于具有相同数据的的 Redis,AOF 文件通常会比 RDB 文件体积更大。
    • 虽然 AOF 提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。但
      在 Redis 的负载 较高时,RDB 比 AOF 具好更好的性能保证。
    • RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF
      文件中,因此从 理论上说,RDB 比 AOF 方式更健壮。官方文档也指出,AOF 的确也存在一
      些 BUG,这些 BUG 在 RDB 没有存在。

开启AOF

开启AOF功能需要设置配置:appendonly yes,默认不开启。AOF文件名 通过appendfilename
置设置,默认文件名是appendonly.aof。保存路径同 RDB持久化方式一致,通过dir配置指定

appendonly yes # 将配置文件中 appendonly字段设置为yes即可

工作流程

image-20220809092905301.png

1. 所有的写入命令会追加到aof_buf(缓冲区)中。
2. AOF缓冲区根据对应的策略向硬盘做同步操作。
3. 随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。
4. 当Redis服务器重启时,可以加载AOF文件进行数据恢复。

重写机制

随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis 引入AOF重写机制压缩文件体
积。

手动触发:直接调用bgrewriteaof命令

自动触发:根据auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage参数确定自动触发时机。

  • 重写后的AOF文件会变小,原因如下

    • 进程内已经超时的数据不再写入文件。
    • 旧的AOF文件含有无效命令,如del key1、hdel key2、srem keys、set a111、set a222等。
      重写使用进程内数据直接生成,这样新的AOF文件只保 留最终数据的写入命令。
    • 多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为:lpush
      list a b c。为了防止单条命令过大造成客户端缓冲区溢 出,对于list、set、hash、zset等类型
      操作,以64个元素为界拆分为多条。

image-20220809093047846.png

1.执行AOF重写请求
2.父进程fork一个子进程,父进程fork完成后继续响应其他命令。所有修改命令先写入AOF缓冲区并根据appendfsync策略同步到硬盘,保证原有AOF机制正确性。
4.由于fork操作运用了写时复制技术,子进程只能共享fork操作时的内存数据,由于父进程依然响应命令,Redis使用“AOF重写缓冲区”保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。
5.子进程根据内存快照,按照命令合并规则将命令写入到新的AOF文件。每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘数据过多造成硬盘阻塞
6.新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息(具体见info persistence下的aof_*相关统计)
7.父进程把AOF重新缓冲区的数据写入新AOF文件
8.用新AOF文件替换老文件,完成AOF重写

3.重启加载持久化文件

image-20220809093509382.png

  1. AOF持久化开启且存在AOF文件时,优先加载AOF文件
  2. AOF关闭或者AOF文件不存在时,加载RDB文件
  3. 加载AOF/RDB文件成功后,Redis启动成功。
  4. AOF/RDB文件存在错误时,Redis启动失败并打印错误信息。

4.混合持久化

重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。

Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是 自持久化开始到持久化结束 的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小

于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
存储 运维 负载均衡
Redis—听说你速度跟甲斗一样快?——cluster
Redis—听说你速度跟甲斗一样快?——cluster
19500 1
|
NoSQL 算法 Redis
Redis—听说你速度跟甲斗一样快?——哨兵
Redis—听说你速度跟甲斗一样快?——哨兵
|
存储 缓存 负载均衡
Redis—听说你速度跟甲斗一样快?——主从复制
现如今,Redis变得越来越流行,在很多业务场景都使用到了Redis。那么在一些高并发、大流量的业务场景里,Redis是如何高效、稳定地提供服务呢?
|
1月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
|
1月前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
77 6
|
11天前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
13天前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
6天前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
22 5
|
21天前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
113 22