Redis 开发陷阱及避坑指南!

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: Linux 配置优化我们在使用 Redis 过程中,可能更多的关注 Redis 本身的一些配置优化,如 AOF、RDB 配置、数据结构配置优化等。但是很少关心 Redis 的载体,服务器的优化。而这往往为我们的项目运行带来灾难性的打击。因此服务器优化也是必不可少的。

Linux 配置优化

我们在使用 Redis 过程中,可能更多的关注 Redis 本身的一些配置优化,如 AOF、RDB 配置、数据结构配置优化等。


但是很少关心 Redis 的载体,服务器的优化。而这往往为我们的项目运行带来灾难性的打击。因此服务器优化也是必不可少的。


内存分配控制

Redis 启动时,可能会出现下面的日志

# WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit\_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.

overcommit 是 Linux 的一种内存处理机制:Linux 对绝大多数内存申请都会回复 yes,以便运行更多的程序。因为申请内存后,并不会马上使用内存。这种机制就是 overcommit 。


而 overcommit_memory 是用来设置内存分配策略的,有三种取值


image.png


日志中 Background save 指的是 bgsave 和 bgrewriteaof 。根据操作系统的配置,如果 overcommit_memory 设置为 0 则可能会造成内存申请失败而导致后台持久化失败。


因此 Redis 建议将这个值设置为 1 是为了 fork 操作在低内存下也能执行成功。


设置方法

通过命令修改,立即生效。重启后会失效

sysctl vm.overcommit_memory=1

再将改动写入系统配置文件,使其永久有效

echo "vm.overcommit_memory=1" >> /etc/sysctl.conf

建议

采用 Redis 建议的配置是为了在极端情况下 Linux 可以挤出来一些内存供 Redis 备份,但是更建议优先配置好 maxmemory ,给机器留 20%~30% 的空闲内存。


硬盘虚拟内存

swap 是指当物理内存不足时,拿出部分硬盘空间当 SWAP 分区(虚拟成内存)使用。我们都知道硬盘的读写速度相对于内存实在是太鸡肋,对于高并发、高吞吐的应用来说,磁盘IO通长会成为系统瓶颈。Linux 系统中 swappiness 的值控制操作系统使用 swap 的倾向程度。

查看内核版本:

uname -sr

image.png

动使用 SWAP


PS:OOM Killer 是指当 Linux 发现操作系统内存不足时,主动杀死一些非内核进程的操作


设置方法

echo {value} > /proc/sys/vm/swappiness


echo vm.swappiness={value} >> etc/sysctl.conf


监控swap

查看 Swap 的总体情况

free -m

image.png

最后一行即展示了 Swap 的使用情况,一共 2047 Mb,以使用 0 Mb,空闲 2047 Mb


实时查看 Swap 的使用

image.png


参数 si 表示 swap in ,so 表示 swap out 在我的机器上都是 0 表示没有使用交换


查看指定进程的 Swap 情况

通过 ps -ef |grep redis 查看 Redis 进程号,例如 1621


通过 cat /proc/1621/smaps | grep Swap 命令查看每个内存块 Redis Swap 的使用情况


THP 内存页大小

Redis 启动时可能会看到下面的日志

WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

提示告诉我们建议修改 Transparent Huge Pages (THP) 的配置,Linux kernel 在 2.6.38 内核增加了 THP 特性,支持大内存页(2MB)分配,默认开启。


开启后可加快 fork 子进程的速度,但是 fork 操作后,每个内存页从原来的 4KB 变为 2MB,会大幅加重重写期间父进程内存消耗。


同时每次写命令引起的复制内存页单位放大了512倍。会拖慢写操作的执行时间。造成大量的写操作慢查询因此 Redis日志中建议禁用它。另外关注Java技术栈公众号在后台回复面试可以获取一份面试题大全。

方法如下:

echo never > /sys/kernel/mm/transparent_hugepage/enabled

另外在 /etc/rc.local 中追加

echo never > /sys/kernel/mm/transparent_hugepage/enabled

对于某些发行版本(例如红帽6以上)配置文件不在这个位置(在 /sys/kernel/mm/redhat_transparent_hugepage/enabled),但是 Redis 检查 THP 是写死的此位置,所以虽然这么修改后 Redis不报警然而实际是没有作用的,需要注意。应该改动对应位置的值


使用NTP 同步时间

在集群或哨兵环境中,多台服务器使用相同的网络时间协议同步时间能更方便的阅读日志,排查问题


可以设置定时任务同步时间

crontab -u //设定某个用户的cron服务
crontab -l //列出某个用户cron服务的详细内容
crontab -r //删除某个用户的cron服务
crontab -e //编辑某个用户的cron服务
crontab -i //打印提示,输入yes等确认信息

添加每小时执行一次的任务

0 * * * * /usr/sbin/ntpdate cn.pool.ntp.org > dev/null 2>&1

最大连接数限制

通过 ulimit -a 命令查看和设置当前用户进程的资源数,其中包含 open files 参数,是单个用户同时打开的最大文件描述符个数。虽然 Redis 中可以配置最大的客户端连接数(默认 10000) 。

Redis 内部最多使用 32 个文件描述符。当 open files = 4096 时,Redis 最大提供 4096-32=4064 个连接。因为它不能突破操作系统的限制。如果需要,使用如下命令修改:

ulimit -Sn {max-open-files}

TCP backlog

tcp backlog 配置的是 tcp 握手时候的队列大小。如果该值过小。会导致高并发场景下部分连接第三次握手ACK被丢弃。关于 backlog

The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

Redis启动时,会告诉我们系统配置中该值是 128,而 Redis 511。这个 511 是没用的,因为系统比这个小。需要修改系统 backlog 的值。

echo 511 > /proc/sys/net/core/somaxconn
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6月前
|
存储 缓存 NoSQL
在Python Web开发过程中:数据库与缓存,Redis在Web开发中的常见应用场景有哪些?
Redis在Python Web开发中常用于缓存、会话管理、分布式锁、排行榜、消息队列和实时分析。作为内存数据存储,它提供高效的数据结构(如字符串、哈希、列表、集合、有序集合),支持会话存储、互斥操作、计数与排名、队列实现及实时数据处理。其高速性能和丰富功能使其成为多场景下的理想选择。
69 5
|
28天前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
22 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
24天前
|
NoSQL API Redis
如何使用 C++ 开发 Redis 模块
如何使用 C++ 开发 Redis 模块
|
6月前
|
NoSQL API Redis
最佳实践|如何使用c++开发redis module
本文将试着总结Tair用c++开发redis module中遇到的一些问题并沉淀为最佳实践,希望对redis module的使用者和开发者带来一些帮助(部分最佳实践也适用于c和其他语言)。
76633 0
|
4月前
|
NoSQL API Redis
c++开发redis module问题之为什么在使用RedisModule_GetApi之前要通过((void**)ctx)[0]这种方式获取其地址
c++开发redis module问题之为什么在使用RedisModule_GetApi之前要通过((void**)ctx)[0]这种方式获取其地址
|
4月前
|
Rust NoSQL API
c++开发redis module问题之如果在加载module时,该module没有执行权限,Redis会如何解决
c++开发redis module问题之如果在加载module时,该module没有执行权限,Redis会如何解决
|
4月前
|
编解码 NoSQL Redis
c++开发redis module问题之想实现Redis命令,如何解决
c++开发redis module问题之想实现Redis命令,如何解决
|
4月前
|
NoSQL Java 编译器
c++开发redis module问题之保证Redis在fork时没有处于inflight状态的命令,如何解决
c++开发redis module问题之保证Redis在fork时没有处于inflight状态的命令,如何解决
|
4月前
|
NoSQL 编译器 Redis
c++开发redis module问题之如果Redis加载了多个C++编写的模块,并且它们都重载了operator new,会有什么影响
c++开发redis module问题之如果Redis加载了多个C++编写的模块,并且它们都重载了operator new,会有什么影响
|
4月前
|
NoSQL Redis C++
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难