Redis持久化

FROM: https://www.toutiao.com/a6660250022401016327/?tt_from=weixin&utm_campaign=client_share&wxshare_count=1&timestamp=1550713408&app=news_article&utm_source=weixin&iid=59686152307&utm_medium=toutiao_ios&group_id=6660250022401016327


一、前言

本文主要讲了 Redis 的持久化相关功能,持久化一直是影响 Redis 性能的高发地,也是面试中经常被问到的。

包括 RDB 相关的特定和优缺点,AOF 的优缺点,事实上,由于 RDB 的数据实时性问题,目前用 AOF 比较多了,而持久化恢复也是优先 AOF。

RDB 是旧的模式,现在基本上都使用 AOF,当然,今天两个都会一起聊聊。

二、 RDB

RDB 流程图:

 

RDB 特点:

1、RDB 是一种快照模式,即——保存的是 key value 数据内容。

2、RDB 有 2 种持久方式,同步 save 模式和异步 bgsave 模式。由于 save 是同步的,所以可以保证数据一致性,而 bgsave 则不能。

3、save 可以在客户端显式触发,也可以在 shutdown 时自动触发;bgsave 可以在客户端显式触发,也可以通过配置由定时任务触发,也可以在 slave 节点触发。

4、save 导致 redis 同步阻塞,基本已经废弃。bgsave 则不会导致阻塞,但也有缺点:在 fork 时,需要增加内存服务器开销,因为当内存不够时,将使用虚拟内存,导致阻塞 Redis 运行。所以,需要保证空闲内存足够。

5、默认执行 shutdown 时,如果没有开启 AOF,则自动执行 bgsave。

6、每次的 RDB 文件都是替换的。

关于优化:

Redis 会压缩 RDB 文件,使用 LZF 算法,让最终的 RDB 文件远小于内存大小,默认开启。但会消耗 CPU。

RDB 缺点:

1、无法秒级持久化。

2、老版本 Redis 无法兼容新版本 RDB。

RDB 优点:

1、文件紧凑,适合备份,全量复制场景。例如每 6 小时执行 bgsave,保存到文件系统之类的。

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

三、 AOF

由于 RDB 的数据实时性问题,AOF(append only file) 是目前 Redis 持久化的主流方式。

AOF 特点:

1、默认文件名是 appendonly.aof。和 RDB 一样,保存在配置中 dir 目录下。

2、AOF 相比较于 RDB,每次都会保存写命令,数据实时性更高。

3、AOF 由于每次都会记录写命令,文件会很大,因此需要进行优化,称之为“重写机制”(下面详细说)。

4、AOF 每次保存的写命令都放在一个缓冲区,根据不同的策略(下面详细说)同步到磁盘。

“重写机制” 细节:

1、fork 子进程(类似 bgsave)

2、主进程会写到2个缓冲区,一个是原有的 “AOF 缓存区”,一个是专门为子进程准备的 “AOF 重写缓冲区”;

3、子进程写到到新的 AOF 文件中,批量的,默认 32m;写完后通知主进程。

4、主进程把“AOF 重写缓冲区”的数据写到新 AOF 文件中。

5、将新的 AOF 文件替换老文件。

重写流程图:

 

缓冲区同步策略,由参数 appendfsync 控制,一共3种:

1、always:调用系统 fsync 函数,直到同步到硬盘返回; 严重影响redis性能。

2、everysec:先调用 OS write 函数, 写到缓冲区,然后 redis 每秒执行一次 OS fsync 函数。 推荐使用这种方式。

3、no: 只执行 write OS 函数,具体同步硬盘策略由 OS 决定; 不推荐,数据不安全,容易丢失数据。

四、持久化恢复

AOF 和 RDB 文件都可以用于服务器重启时的数据恢复,具体流程如下图:

 

从图中可以看出优先加载 AOF,当没有 AOF 时才加载 RDB。当 AOF 或者 RDB 存在错误,则加载失败。

五、问题排查和性能优化

Redis 持久化是影响 Redis 性能的高发地,也是面试中常问的问题。

1. fork 操作

当 Redis 做 RDB 或者 AOF 重写时,必然要进行 fork 操作,对于 OS 来说,fork 都是一个重量级操作。而且,fork 还会拷贝一些数据,虽然不会拷贝主进程所有的物理空间,但会复制主进程的空间内存页表。对于 10GB 的 Redis 进程,需要复制大约 20MB 的内存页表,因此 fork 操作耗时跟进程总内存量息息相关,再加上,如果使用虚拟化技术,例如 Xen 虚拟机,fork 会更加耗时。

一个正常的 fork 耗时大概在 20毫秒左右。为什么呢,假设一个 Redis 实例的 OPS 在 5 万以上,如果 fork 操作耗时在秒级,那么僵拖慢几万条命令的执行,对生产环境影响明显。

我们可以在 Info stats 统计中查询 latestforkusec 指标获取最近一次 fork 操作耗时,单位微秒。

如何优化:

1、优先使用物理机或者高效支持 fork 的虚拟化技术,避免使用 Xen。

2、控制 redis 实例最大内存,尽量控制在 10GB 以内。

3、合理配置 Linux 内存分配策略,避免内存不足导致 fork 失败。

4、降低 fork 的频率,如适度放宽 AOF 自动触发时机,避免不必要的全量复制。

2. 子进程开销

fork 完毕之后,会创建子进程,子进程负责 RDB 或者 AOF 重写,这部分过程主要涉及到 CPU,内存,硬盘三个地方的优化。

1、CPU 写入文件的过程是 CPU 密集的过程,通常子进程对单核 CPU 利用率接近 90%。 如何优化呢?既然是 CPU 密集型操作,就不要绑定单核 CPU,因为这样会和父 CPU 进行竞争。同时,不要和其他 CPU 密集型服务不是在一个机器上。如果部署了多个 Redis 实例,尽力保证统一时刻只有一个子进程执行重写工作。

2、内存 子进程通过 fork 操作产生,占用内存大小等同于父进程,理论上需要两倍的内存完成持久化操作,但 Linux 有 copy on write 机制,父子进程会共享相同的物理内存页,当父进程处理写操作时,会把要修改的页创建对应的副本,而子进程在 fork 操作过程中,共享整个父进程内存快照。 即——如果重写过程中存在内存修改操作,父进程负责创建所修改内存页的副本。这里就是内存消耗的地方。 如何优化呢?尽量保证同一时刻只有一个子进程在工作;避免大量写入时做重写操作。

3、硬盘 硬盘开销分析:子进程主要职责是将 RDB 或者 AOF 文件写入硬盘进行持久化,势必对硬盘造成压力,可通过工具例如 iostat,iotop 等,分析硬盘负载情况。

如何优化:

1、不要和其他高硬盘负载的服务放在一台机器上,例如 MQ,存储。

2、AOF 重写时会消耗大量硬盘 IO,可以开启配置 no-appendfsync-on-rewrite,默认关闭。表示在 AOF 重写期间不做 fsync 操作。

3、当开启 AOF 的 Redis 在高并发场景下,如果使用普通机械硬盘,每秒的写速率是 100MB左右,这时,Redis 的性能瓶颈在硬盘上,建议使用 SSD。

4、对于单机配置多个 Redis 实例的情况,可以配置不同实例分盘存储 AOF 文件,分摊硬盘压力。

3. AOF 追加阻塞

当开启 AOF 持久化时,常用的同步硬盘的策略是“每秒同步” everysec,用于平衡性能和数据安全性,对于这种方式,redis 使用另一条线程每秒执行 fsync 同步硬盘,当系统资源繁忙时,将造成 Redis 主线程阻塞。

流程图如下:

 

通过上图可以发现:everysec 配置最多可能丢失 2 秒数据,不是 1 秒;如果系统 fsync 缓慢,将会导致 Redis 主线程阻塞影响效率。

问题定位:

1、发生 AOF 阻塞时,会输入日志。用于记录 AOF fsync 阻塞导致拖慢 Redis 服务的行为。

2、每当 AOF 追加阻塞事件发生时,在 info Persistence 统计中,aofdelayedfsync 指标会累加,查看这个指标方便定位 AOF 阻塞问题。

3、AOF 同步最多运行 2 秒的延迟,当延迟发生时说明硬盘存在性能问题,可通过监控工具 iotop 查看,定位消耗 IO 的进程。

4. 单机多实例部署

Redis 单线程架构无法充分利用多核CPU,通常的做法是一台机器上部署多个实例,当多个实例开启 AOF 后,彼此之间就会产生CPU 和 IO 的竞争。

如何解决这个问题呢?

让所有实例的 AOF 串行执行。

我们通过 info Persistence 中关于 AOF 的信息写出 Shell 脚本,然后串行执行实例的 AOF 持久化。

整个过程如图:

 

通过不断判断 AOF 的状态,手动执行 AOF 重写,保证 AOF 不会存在竞争。具体的 Shell 编写以及 info 信息判断,可以查看下图:

六、总结

本文主要讲了 Redis 的持久化相关功能,持久化一直是影响 Redis 性能的高发地,也是面试中经常被问到的。包括 RDB 相关的特定和优缺点,AOF 的优缺点,事实上,由于 RDB 的数据实时性问题,目前用 AOF 比较多了。而持久化恢复也是优先 AOF。

关于持久化的问题排查,就很麻烦了,但无非几个方面,fork 耗时,子进程的 CPU,内存,硬盘开销,AOF 的同步阻塞,单机多实例部署。

### Orangepi硬件与YOLOv1模型的兼容性和开发环境搭建 #### 一、Orangepi硬件特性及其对深度学习的支持 Orangepi系列设备,尤其是提到的OrangePi AI Pro型号,具备强大的性能和丰富的接口资源[^1]。其支持多种主流操作系统(如Ubuntu、openEuler),并能够运行常见的编程语言(如Python、C++)。这些特点使其成为嵌入式AI项目的一个理想平台。 对于深度学习框架而言,OrangePi AI Pro可以通过安装TensorFlow Lite、PyTorch Mobile或其他轻量级推理引擎来执行神经网络模型推断操作[^2]。然而需要注意的是,在实际部署过程中可能会受到处理器架构限制的影响——ARM Cortex-A7/A53这类CPU核虽然功耗低但算力有限;因此如果要高效运行复杂的CNNs比如YOLO家族成员,则可能还需要借助GPU加速或者专用NPU单元(视具体产品版本而定)。 #### 二、YOLO v1简介及移植可行性分析 YOLO (You Only Look Once) 是一种实时目标检测算法,其中第一个版本即YOLOv1以其简洁快速著称。它通过单次前向传播完成边界框预测与类别分类任务,相比传统两阶段方法显著提升了速度表现[^3]。 考虑到Orangepi所搭载硬件的能力水平,理论上是可以适配YOLOv1这样的较早期版本的目标检测系统的。不过由于原生训练好的权重文件通常是基于桌面端高性能显卡优化过的浮点数精度格式(.weights),所以在将其迁移到资源受限环境中之前通常要做一些转换工作: - **量化处理**:将FP32参数降低到INT8甚至更低位宽表示形式以减少内存占用同时加快运算速率; - **裁剪简化结构**:去掉不必要的层或节点从而进一步缩小规模适应小型化场景需求。 #### 三、开发环境配置指南 以下是针对如何在Orangepi平台上构建适合运行YOLOv1项目的软件栈建议列表: ##### 1. 操作系统选择 推荐选用长期稳定版(LTS)类型的Linux发行版作为基础OS,例如Ubuntu Mate 20.04 LTS ARM64镜像包。这样可以获得较好的社区技术支持同时也便于后续扩展其他依赖组件库。 ##### 2. Python生态准备 确保已正确设置了pip工具链以便管理第三方模块插件。接着按照官方文档指示依次下载必要的科学计算类库numpy, opencv-python头文件集以及deep learning framework本身(pytorch/tensorflow)[^4]: ```bash sudo apt update && sudo apt upgrade -y sudo apt install python3-pip build-essential cmake git libgtk2.0-dev pkg-config \ libavcodec-dev libavformat-dev libswscale-dev libjpeg-dev libpng-dev \ libtiff-dev gfortran openblas-dev libatlas-base-dev protobuf-compiler \ libgoogle-glog-dev libgflags-dev libeigen3-dev libhdf5-serial-dev \ libleveldb-dev libsnappy-dev liblmdb-dev wget unzip -y # Install specific version of OpenCV compatible with YOLO requirements. pip3 install numpy==1.19.3 scipy matplotlib pillow seaborn jupyterlab ipython pandas scikit-image h5py keras_applications tensorflow_addons torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cpu ``` ##### 3. Darknet源码编译 Darknet是由Joseph Redmon维护的一套用于计算机视觉研究的小型开源框架,默认情况下提供了完整的YOLO实现方案。为了能够在Arm架构机器上顺利加载预训练模型数据集,有必要自行克隆仓库地址并对Makefile做适当调整后再提交make命令生成最终可执行程序binary file darknet[^5]: ```bash git clone https://github.com/pjreddie/darknet.git ~/darknet_repo/ cd ~/darknet_repo/ sed -i 's/GPU=0/GPU=1/g' Makefile # Enable GPU support if available hardware supports CUDA/OpenCL etc.. sed -i 's/CUDNN=0/CUDNN=1/g' Makefile # Same as above line but related to cuDNN library usage flag setting. make clean all # Rebuild entire project after modification done on configuration files. ``` ##### 4. 测试样例脚本编写 最后一步就是结合摄像头输入流或者其他多媒体素材来源设计一段简单的演示代码片段用来验证整个流程是否通畅无误: ```python import cv2 from pydarknet import Detector, Image if __name__ == "__main__": net = Detector(bytes("cfg/yolov1.cfg", encoding="utf-8"), bytes("weights/yolov1.weights", encoding="utf-8"), 0, bytes("data/coco.names",encoding="utf-8")) cap = cv2.VideoCapture(0) while True: ret,img=cv2.read(cap) if not ret:break img_darknet=Image(img) results=net.detect(img_darknet) for cat,score,bounds in results: x,y,w,h=bounds cv2.rectangle(img,(int(x-w*0.5),int(y-h*0.5)),(int(x+w*0.5),int(y+h*0.5)),(255,0,0)) cv2.putText(img,str(cat.decode())+" "+str(round(score*100))+"%",(int(x),int(y)),cv2.FONT_HERSHEY_SIMPLEX,.5,(255,255,0),2) cv2.imshow('Detection Results',img) keypress=cv2.waitKey(1)&0xFF if keypress==ord('q'):break del(net) cap.release() cv2.destroyAllWindows() ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值