redis开发与运维

1. 初识redis

    redis的8个特性:速度快、基于键值对的数据结构服务器、功能丰富、简单稳定、客户端语言多、持久化、主从复制、支持高可用和分布式。
    redis不是万金油,有些场景不符合redis
    开发运维结合以及阅读源码
    生产环境中使用配置文件启动redis
    Redis3.0是重要的里程碑, 发布了Redis官方的分布式实现Redis Cluster。

2. API的理解和使用

    Redis提供5种数据结构, 每种数据结构都有多种内部编码实现。
    纯内存存储、 IO多路复用技术、 单线程架构是造就Redis高性能的三个因素。
    由于Redis的单线程架构, 所以需要每个命令能被快速执行完, 否则会存在阻塞Redis的可能, 理解Redis单线程命令处理机制是开发和运维Redis的核心之一。
    批量操作(例如mget、 mset、 hmset等) 能够有效提高命令执行的效率, 但要注意每次批量操作的个数和字节数。
    了解每个命令的时间复杂度在开发中至关重要, 例如在使用keys、 hgetall、 smembers、 zrange等时间复杂度较高的命令时,需要考虑数据规模对于Redis的影响。
    persist命令可以删除任意类型键的过期时间, 但是set命令也会删除字符串类型键的过期时间, 这在开发时容易被忽视。
    move、 dump+restore、 migrate是Redis发展过程中三种迁移键的方式, 其中 move命令基本废弃, migrate命令用原子性的方式实现了dump+restore, 并且支持批量操作, 是Redis Cluster实现水平扩容的重要工具。
    scan命令可以解决keys命令可能带来的阻塞问题, 同时Redis还提供了hscan、 sscan、 zscan渐进式地遍历hash、 set、 zset。

3. 小功能大用处

    慢查询中的两个重要参数slowlog-log-slower-than和slowlog-max-len。
    慢查询不包含命令网络传输和排队时间。
    有必要将慢查询定期存放。
    redis-cli一些重要的选项, 例如--latency、 –-bigkeys、 -i和-r组合。
    redis-benchmark的使用方法和重要参数。
    Pipeline可以有效减少RTT次数, 但每次Pipeline的命令数量不能无节制。
    Redis可以使用Lua脚本创造出原子、 高效、 自定义命令组合。
    Redis执行Lua脚本有两种方法: eval和evalsha。
    Bitmaps可以用来做独立用户统计, 有效节省内存。
    Bitmaps中setbit一个大的偏移量, 由于申请大量内存会导致阻塞。
    HyperLogLog虽然在统计独立总量时存在一定的误差, 但是节省的内存量十分惊人。
    Redis的发布订阅机制相比许多专业的消息队列系统功能较弱, 不具备堆积和回溯消息的能力, 但胜在足够简单。
    Redis3.2提供了GEO功能, 用来实现基于地理位置信息的应用, 但底层实现是zset。

4. 客户端

    RESP(Redis Serialization Protocol Redis) 保证客户端与服务端的正常通信, 是各种编程语言开发客户端的基础。
    要选择社区活跃客户端, 在实际项目中使用稳定版本的客户端。
    区分Jedis直连和连接池的区别, 在生产环境中, 应该使用连接池。
    Jedis.close() 在直连下是关闭连接, 在连接池则是归还连接。
    Jedis客户端没有内置序列化, 需要自己选用。
    客户端输入缓冲区不能配置, 强制限制在1G之内, 但是不会受到maxmemory限制。
    客户端输出缓冲区支持普通客户端、 发布订阅客户端、 复制客户端配置, 同样会受到maxmemory限制。
    Redis的timeout配置可以自动关闭闲置客户端, tcp-keepalive参数可以周期性检查关闭无效TCP连接
    monitor命令虽然好用, 但是在大并发下存在输出缓冲区暴涨的可能性。
    info clients帮助开发和运维人员找到客户端可能存在的问题。
    理解Redis通信原理和建立完善的监控系统对快速定位解决客户端常见问题非常有帮助。

5. 持久化

    Redis提供了两种持久化方式: RDB和AOF。
    RDB使用一次性生成内存快照的方式, 产生的文件紧凑压缩比更高, 因此读取RDB恢复速度更快。 由于每次生成RDB开销较大, 无法做到实时持久化, 一般用于数据冷备和复制传输。
    save命令会阻塞主线程不建议使用, bgsave命令通过fork操作创建子进程生成RDB避免阻塞。
    AOF通过追加写命令到文件实现持久化, 通过appendfsync参数可以控制实时/秒级持久化。 因为需要不断追加写命令, 所以AOF文件体积逐渐变大, 需要定期执行重写操作来降低文件体积。
    AOF重写可以通过auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数控制自动触发, 也可以使用bgrewriteaof命令手动触发。
    子进程执行期间使用copy-on-write机制与父进程共享内存, 避免内存消耗翻倍。 AOF重写期间还需要维护重写缓冲区, 保存新的写入命令避免数据丢失。
    持久化阻塞主线程场景有: fork阻塞和AOF追加阻塞。 fork阻塞时间跟内存量和系统有关, AOF追加阻塞说明硬盘资源紧张。
    单机下部署多个实例时, 为了防止出现多个子进程执行重写操作, 建议做隔离控制, 避免CPU和IO资源竞争。

6. 复制

    Redis通过复制功能实现主节点的多个副本。 从节点可灵活地通过slaveof命令建立或断开复制流程。
    复制支持树状结构, 从节点可以复制另一个从节点, 实现一层层向下的复制流。 Redis2.8之后复制的流程分为: 全量复制和部分复制。 全量复制需要同步全部主节点的数据集, 大量消耗机器和网络资源。 而部分复制有效减少因网络异常等原因造成的不必要全量复制情况。 通过配置合理的复制积压缓冲区尽量避免全量复制。
    主从节点之间维护心跳和偏移量检查机制, 保证主从节点通信正常和数据一致
    Redis为了保证高性能复制过程是异步的, 写命令处理完后直接返回给客户端, 不等待从节点复制完成。 因此从节点数据集会有延迟情况。
    当使用从节点用于读写分离时会存在数据延迟、 过期数据、 从节点可用性等问题, 需要根据自身业务提前作出规避。
     在运维过程中, 主节点存在多个从节点或者一台机器上部署大量主节点的情况下, 会有复制风暴的风险。

7. redis的噩梦:阻塞

    客户端最先感知阻塞等Redis超时行为, 加入日志监控报警工具可快速定位阻塞问题, 同时需要对Redis进程和机器做全面监控。
    阻塞的内在原因: 确认主线程是否存在阻塞, 检查慢查询等信息, 发现不合理使用API或数据结构的情况, 如keys、 sort、 hgetall等。 关注CPU使用率防止单核跑满。 当硬盘IO资源紧张时, AOF追加也会阻塞主线程。
    阻塞的外在原因: 从CPU竞争、 内存交换、 网络问题等方面入手排查是否因为系统层面问题引起阻塞。

8. 理解内存

     Redis实际内存消耗主要包括: 键值对象、 缓冲区内存、 内存碎片。
    通过调整maxmemory控制Redis最大可用内存。 当内存使用超出时, 根据maxmemory-policy控制内存回收策略。
    内存是相对宝贵的资源, 通过合理的优化可以有效地降低内存的使用量, 内存优化的思路包括:
        精简键值对大小, 键值字面量精简, 使用高效二进制序列化工具。
        使用对象共享池优化小整数对象。
        数据优先使用整数, 比字符串类型更节省空间。
        优化字符串使用, 避免预分配造成的内存浪费
        使用ziplist压缩编码优化hash、 list等结构, 注重效率和空间的平衡。
        使用intset编码优化整数集合。
        使用ziplist编码的hash结构降低小对象链规模。

9. 哨兵

    Redis Sentinel是Redis的高可用实现方案: 故障发现、 故障自动转移、 配置中心、 客户端通知。
    Redis Sentinel从Redis2.8版本开始才正式生产可用, 之前版本生产不可用。
    尽可能在不同物理机上部署Redis Sentinel所有节点。
    Redis Sentinel中的Sentinel节点个数应该为大于等于3且最好为奇数。
    Redis Sentinel中的数据节点与普通数据节点没有区别。
    客户端初始化时连接的是Sentinel节点集合, 不再是具体的Redis节点, 但Sentinel只是配置中心不是代理。
    Redis Sentinel通过三个定时任务实现了Sentinel节点对于主节点、 从节点、 其余Sentinel节点的监控。
    Redis Sentinel在对节点做失败判定时分为主观下线和客观下线。
    看懂Redis Sentinel故障转移日志对于Redis Sentnel以及问题排查非常有帮助。
    Redis Sentinel实现读写分离高可用可以依赖Sentinel节点的消息通知, 获取Redis数据节点的状态变化。

10. 集群

猜你喜欢

转载自my.oschina.net/u/2615530/blog/1807736