Redis学习

第12章 Redis开发运维的陷阱

2020-03-22  本文已影响0人  岁月如歌2020
[图片上传中...(image.png-caa867-1584891059523-0)]
image.png

12.1 Linux配置优化

12.1.1 内存分配控制

含义
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

12.1.2 swappiness

策略
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)

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

# 查看
cat /proc/sys/net/core/somaxconn

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

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

12.2.1 缓存与存储

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

需要恢复

12.2.2 借助AOF机制恢复

12.2.3 RDB有什么变化

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

12.2.4 从节点有什么变化

与主节点一致。

12.2.5 快速恢复数据

  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. 最佳实践

12.3.2 伪装危险命令

  1. 引入rename-command
keys: 键值多时易阻塞
flushall/flushdb: 容易误删数据
save: 键值多时易阻塞
debug: debug reload时会重启Redis
config: 应交给管理员
shutdown: 关闭Redis
rename-command flushall afsdafadfad
  1. rename-command的副作用
  1. 最佳实践

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 最佳实践思路

12.5 寻找热点key

12.5.1 客户端

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

12.5.2 代理端

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);

12.5.4 机器

  1. 简介

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

  1. 现有工具

ELK体系下的packetbeat插件

12.5.5 对比分析

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

12.6 本章小结

  1. Linux相关优化:
  1. 理解Redis的持久化有助于解决flush操作之后的数据快速恢复问题
  2. Redis安全建议:
  1. bigKey的危害不容忽视: 数据倾斜、超时阻塞、网络拥塞,可能是Redis生产环境的一颗定时炸弹,删除bigKey时通常使用渐进式遍历的方式,防止出现Redis阻塞的情况
  2. 通过客户端、代理、monitor、机器抓包四种方式找到热点key, 这几种方式各具优势,具体使用哪种要根据当前场景来决定。
上一篇下一篇

猜你喜欢

热点阅读