第12章 Redis开发运维的陷阱

[图片上传中...(image.png-caa867-1584891059523-0)]

image.png

12.1 Linux配置优化

12.1.1 内存分配控制

  • overcommit_memory
含义
0 内核将检查是否有足够的可用内存(物理内存+swap),如果有,则内存申请通过;否则申请失败,并把错误返回给应用进程
1 内核允许超量使用内存直到用完为止
2 内核决不过量的使用内存,即系统整个内存地址空间不能超过swap+50%的RAM值,50%是overcommit_ratio的默认值,可修改
  • 获取和设置
cat /proc/sys/vm/overcommit_memory

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

  • 最佳实践
    • Redis设置maxmemory保证机器有20%-30%的闲置内存
    • 集中化管理AOF重写和RDB的bgsave
    • 设置vm.overcommit_memory=1防止极端情况下fork失败

12.1.2 swappiness

  • swappiness的值越大,表明系统使用swap的概率越大
  • 重要值说明
策略
0 Linux3.5以及以上:宁愿用OOM killer也不用swap; 否则反之
1 Linux3.5以及以上:宁愿用swap也不用OOM killer
60 默认值
100 操作系统会主动地使用swap
  • 设置
# 临时生效
echo {bestvalue} > /proc/sys/vm/swappiness

# 永久生效
echo swappiness={bestvalue} >> /etc/sysctl.conf

# 查看swap的总体情况
free -m

# 实时查看swap的使用, 看si(swap in)和so(swap out)列
vmstat 1

# 查看指定进程的swap使用, 假设进程号为986
redis-cli -h ip -p port info server | grep process_id
cat /proc/986/smaps
  • 最佳实践

对于高可用的Redis集群来说,单个Redis节点死掉比阻塞更好,所以应设置swappiness=0(当Linux>=3.5)

12.1.3 THP(Transparent Huge Pages)

  • 开启后会加快fork速度, 但fork操作之后,每个内存页从4KB变为2MB,会增加写期间父进程内存消耗,由于每次写命令引起的复制内存页单位放大了512倍,写操作也会变慢,建议禁用
  • 禁用方法
echo never > /sys/kernel/mm/transparent_hugepage/enabled

12.1.4 OOM killer

  • 简介

OOM killer会在可用内存不足时选择性地杀掉用户进程, 杀掉进程的选择依据进程权重来进行,权重越高被杀掉的概率越高

  • 设置进程权重
# 设置单个Redis进程权重
echo {value} > /proc/${process_id}/oom_adj

# 设置批量Redis进程权重
for redis_pid in $(pgrep -f "redis-server")
do
    echo -17 > /proc/${redis_pid}/oom_adj
done
  • 最佳实践

同THP设置一样的思路,对于Redis集群来说, 宁可让Redis节点被杀掉,也不愿意Redis节点阻塞,所以一般不要依赖此项配置

12.1.5 使用NTP(Network Time Protocol)

  • 简介

用来帮Redis集群节点间统一系统时钟, 一般每天/小时同步一次

0 * * * * /usr/sbin/ntpupdate ntp.xx.com > /dev/null 2>&1

12.1.6 ulimit

  • 简介

系统当前用户进程的资源数(包含文件描述符合网络连接)

  • 查看和设置
# 查看系统当前用户进程的资源数, 找open files参数
ulimit -a

# 设置当前用户进程的资源数,Redis建议open files设置成至少10032
ulimit -Sn {max-open-files}

12.1.7 TCP backlog

  • Redis默认511,Redis的TCP backlog不能超过Linux系统的TCP backlog
  • 设置Linux的TCP backlog方法
# 查看
cat /proc/sys/net/core/somaxconn

# 设置
echo 511 > /proc/sys/net/core/somaxconn

12.2 flushall/flushdb误操作快速恢复方法

12.2.1 缓存与存储

  • 缓存

误操作删除数据,一般不用恢复,遇到并发量较大的情况,为了降低后端直接负载,才需要手动恢复

  • 存储

需要恢复

12.2.2 借助AOF机制恢复

  • 前提条件
    • AOF重写尚未发生
  • 紧急措施(为了阻止AOF重写发生)
    • 调大auto_aof_rewrite_percentage和auto_aof_rewrite_min_size, 阻止AOF重写的发生
    • 拒绝手动bgrewriteaof
    • 去掉AOF日志中的flushall/flushdb相关操作指令
    • 用redis-check-aof工具检验AOF文件的合法性

12.2.3 RDB有什么变化

  • 前提条件
    • 没有开启RDB的自动策略, 比如
    save 900 1
    save 300 10
    save 60 10000
    
    • 没有手动执行过save, bgsave
  • 紧急措施
    • 删除RDB中flushall/flushdb相关操作指令
  • 后续影响

RDB文件的数据可能有一定延迟,这是跟RDB的同步频率有关的。

12.2.4 从节点有什么变化

与主节点一致。

12.2.5 快速恢复数据

  • AOF数据源误删数据恢复步骤演练:
  1. 防止AOF重写
config set auto_aof_rewrite_percentage 1000
config set auto_aof_rewrite_min_size 100,000,000,000
  1. 去掉主从AOF文件中的flush相关内容
*1
$8
flushall
  1. 重启Redis主节点服务器, 恢复数据
  • 最佳实践

提前准备好恢复数据的shell脚本, 故障不等人!!!

12.3 安全的Redis如何设计

12.3.1 密码机制

  1. 简单的密码机制
# 服务端
redis-server --requirepass hello_redis_devops

# 客户端使用-a
redis-cli -a hello_redis_devops

# 客户端使用auth
redis-cli
auth hello_redis_devops
  1. 最佳实践
  • 密码足够复杂(64个字节以上)
  • 主从结构,从节点配置要加上masterauth配置, 对应主节点的密码
  • auth明文并不十分可靠,需要其他方案的配合

12.3.2 伪装危险命令

  1. 引入rename-command
  • Redis危险命令:
keys: 键值多时易阻塞
flushall/flushdb: 容易误删数据
save: 键值多时易阻塞
debug: debug reload时会重启Redis
config: 应交给管理员
shutdown: 关闭Redis
  • 重命名危险指令
rename-command flushall afsdafadfad
  1. rename-command的副作用
  • 管理员需要修改客户端代码, 例如jedis.flushall()操作内部使用了flushall命令, 改名后代码也要修改
  • 不支持config set
  • 若AOF和RDB包含了rename-command前的指令,Redis将无法启动
  • Redis源码中有些命令是写死的,rename-command后可能导致Redis无法工作
  1. 最佳实践
  • 对于一些危险的指令,不管内网还是外网,一律使用rename-command配置
  • 第一次配置Redis的时候一次性设置好rename-command,以后不再修改
  • 保持主从一致

12.3.3 防火墙

比如Linux系统只允许80端口对外

12.3.4 bind

  1. 简介

bind指定了Redis和哪块网卡绑定

  1. 举例
内网地址: 10.10.xx.192
外网地址: 220.181.xx.123
回环地址: 127.0.0.1

当前Redis配置了bind 10.10.xx.192, 那么Redis访问如果通过
redis-cli -h 220.181.xx.123 -p 6379
redis-cli -h 127.0.0.1 -p 6379
就无法正常访问Redis了

12.3.5 定期备份数据

最后一招,有备份数据才是王者

12.3.6 不使用默认端口

Redis默认端口6379, 容易被别有用心的人恶意攻击

12.3.7 使用非root用户启动

root权限太大, Redis一旦失陷, 整台机器失陷

12.4 处理bigkey的方案与最佳实践

12.4.1 bigkey的危害

  1. 内存分布不均衡
  2. 超时阻塞
  3. 网络拥塞

12.4.2 如何发现

  1. redis-cli --bigkeys
  2. scan + debug object key

12.4.3 如何删除

分批删除, 不要一次性删除

public void delBigHash(String bigKey) {
    Jedis jedis = new Jedis("127.0.0.1", 6379);
    String cursor = "0";
    while (true) {
        ScanResult<Map.Entry<String, String>> scanResult = jedis.hscan(bigKey, cursor, new ScanParams().count(100));
        cursor = scanResult.getStringCursor();
        List<Entry<String, String>> list = scanResult.getResult();
        if (list == null || list.size() == 0) {
            continue;
        }
        String[] fields = getFieldsFrom(list);
        jedis.hdel(bigKey, fields);
        if (cursor.equals("0")) {
            break;
        }
    }
    jedis.del(bigKey);
}

12.4.4 最佳实践思路

  • 合理的bigKey检测机制
  • 开发阶段注意防止bigKey的出现

12.5 寻找热点key

12.5.1 客户端

客户端本地计数探知热点key

12.5.2 代理端

  • 示意图


    image.png
  • 开源实现

    • Twemproxy
    • Codis

12.5.3 Redis服务端

  • 伪代码
List<String> keyList = redis.monitor(100000);
AtomicLongMap<String> ATOMIC_LONG_MAP = AtomicLongMap.create();
for (String key : keyList) {
    ATOMIC_LONG_MAP.incrementAndGet(key);
}
statHotKey(ATOMIC_LONG_MAP);
  • 开源实现
    • Facebook的redis-faina

12.5.4 机器

  1. 简介

对机器上所有Redis端口的TCP数据包抓包分析

  1. 现有工具

ELK体系下的packetbeat插件

12.5.5 对比分析

方案 优点 缺点
客户端 实现简单 1. 内存泄露隐患 2. 维护成本高 3. 只能统计单个客户端
代理 实现最方便 增加代理端的开发部署成本
服务端 实现简单 1. monitor本身的成本和危害性,只能短时间使用 2. 只能统计单个Redis节点
机器 对于客户端和服务端无侵入和影响 需要专业的运维团队开发,增加了机器部署成本

12.6 本章小结

  1. Linux相关优化:
  • vm.overcommit_memory建议为1
  • Linux>3.5, vm.swappiness建议为1,否则建议为0
  • THP建议关闭掉
  • 可以为Redis进程设置oom_adj, 减少Redis被OOM killer杀掉的概率,但不要过度依赖此特性
  • 建议对Redis所有节点所在机器使用NTP服务
  • 设置合理的ulimit保证网络连接正常
  • 设置合理的tcp-backlog参数
  1. 理解Redis的持久化有助于解决flush操作之后的数据快速恢复问题
  2. Redis安全建议:
  • 根据具体网络环境决定是否设置Redis密码
  • rename-command可以伪装命令,但是要注意成本
  • 合理的防火墙是防止攻击的利器
  • bind可以将Redis的访问绑定到指定网卡上
  • 定期备份数据应该作为习惯性操作
  • 可以适当错开Redis默认端口启动
  • 使用非root用户启动Redis
  1. bigKey的危害不容忽视: 数据倾斜、超时阻塞、网络拥塞,可能是Redis生产环境的一颗定时炸弹,删除bigKey时通常使用渐进式遍历的方式,防止出现Redis阻塞的情况
  2. 通过客户端、代理、monitor、机器抓包四种方式找到热点key, 这几种方式各具优势,具体使用哪种要根据当前场景来决定。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • Redis 提供了多种不同级别的持久化方式: 了解 RDB 持久化和 AOF 持久化之间的异同是非常重要的, 以下...
    笑Skr人啊阅读 460评论 0 1
  • 因前两天服务器挂掉了,导致项目使用的redis数据库异常,丢失了部分数据,为了能够更好的使用Redis,结合网上的...
    呦_小宋啊阅读 2,251评论 2 9
  • 一、Redis高可用概述 在介绍Redis高可用之前,先说明一下在Redis的语境中高可用的含义。 我们知道,在w...
    空语阅读 1,593评论 0 2
  • 转载 Redis 是一个开源( BSD 许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件. ...
    大先生居然都有人用了阅读 1,129评论 0 0
  • 今天下午的最后一节课是展长班,李老师带我们去观察那棵老杨树,那个花坛里面花朵簇簇,花坛的正中心就是那棵老杨树。我很...
    李晨旭1阅读 438评论 1 4