当前位置: 首页 > news >正文

《Redis开发与运维》笔记

本笔记来源于《Redis开发与运维》(付磊 张益军著)

初识Redis

单线程面向快速执行场景的内纯数据库

特性

  1. 数据结构:string字符串(位图bitmaps,hyperloglog),hash哈希表,list列表,set集合,zset有序集合
  2. 单线程模型
  3. 持久化方式:RDB,AOF
  4. 主从复制

数据结构 & API

object encoding testObject:查看testObject内部编码

zipXxx:是更加紧凑的数据结构,集合元素总数少(默认512,有序集合zset是128)且所有元素不大时(64 bytes)采用,否则用其他大容量结构

lpush + lpop = stack
lpush + rpop = queue
lpush + ltrim = 有限集合
lpush + brpop = 消息队列 # brpop阻塞方法

ttl : time to live # 过期时间s
pttl # 过期时间 ms
persist # 持久化,会消除过期时间
set # string set会移除过期时间
复制代码

不支持二级数据结构内部元素过期功能

命令作用域原子性支持多个键使用建议
moveRedis实例内部弃用
dump + restoreRedis实例之间非原子,不用
migrateRedis实例之间原子,建议使用

单线程架构

命令到达服务端后,按队列依次单线程执行

epoll I/O多路复用提升IO性能

redis快的原因:

  1. 纯内存访问
  2. I/O多路复用:epoll
  3. 单线程避免线程竞争

keys全量遍历键可能导致redis阻塞,可以在从节点上执行,或者使用渐进式的scan代替(可能漏掉期间进行的更新)

附加功能

慢查询分析

慢查询只统计执行命令的时间,并不统计网络通信和命令排队的时间

slowlog-log-slower-than : 0记录所有命令,<0不记录,>0记录超过该阈值的命令(微妙μs),默认10000,并发量100
slowlog-max-len : 按列表储存,日志最大数量
复制代码

redis shell

--bigkeys : 使用scan命令对键采样,找到内存占用较大的键值
--latency/latency-history/dist : 检测网络延迟
--stat:实时获取统计信息
复制代码

pipeline

将一组redis命令组装,通过一次RTT(Round Trip Time往返时间)传输给Redis,再将执行结构一次性按序返回

pipeline非原子操作

事务与Lua

事务

watch key # 此代码后到事务执行前,key没有被其他客户端修改过才执行事务
multi
cmd...
exec

discard #停止事务
复制代码

命令写错了,不执行事务 运行时错误,已执行的不回滚,redis不支持事务回滚

Lua

Lua脚本为原子执行

eval:执行lua脚本 eval 脚本内容 key个数 key列表 参数列表
evalsha:服务器复用脚本 evalsha 脚本SHA1值 key个数 key列表 参数列表
script kill:杀掉正在执行的Lua脚本

bitmaps

bitmaps本质上是字符串,不是一种数据结构

HyperLogLog

HyperLogLog本质上是字符串,不是一种数据结构

可以利用极小的内存空间完成独立总数的统计

近似估计,有失误率,用精度换取空间

Redis阻塞

  1. 定位异常节点

    可以修改客户端connection类,专门捕获连接,发送命令和协议读取事件的异常,打印出对应的ip port,定位阻塞节点

  2. 排查内在原因

    API或数据结构使用不合理 CPU饱和 与持久化相关的阻塞

redis内存

哨兵 sentinel

客户端在初始化时是连接sentinel集合获取master节点信息

sentinel节点之间可以共享数据

sentinel可以同时监控多个主节点

  1. 每个sentinel会对数据节点和其他sentinel节点进行监控,发现节点不可达时,对节点做下线标识
  2. 被下线标识的是master节点,则sentinel会和其他sentinel节点协商,当大部分sentinel节点认为master节点不可达,就选举出一个sentinel节点完成故障自动转移

leader sentinel选举(Raft算法):任何一个sentinel确认主节点主观下线后,立即向其他所有sentinel节点发送投票命令(设置发送方sentinel为leader),其他节点未同意的才能同意请求,否则拒绝,当至少有max(quorum,sentinels/2+1)个sentinel节点同意成立,否则进行下一次选举

类似zookeeper leader选举,本质上都是多数投票,未选出结果就多轮投票

# sentinel.conf
# sentinel节点配置了master节点信息,会从master节点获取其他slave节点信息
# 2: 1)至少2(quorum)个sentinel认为主节点不可达,才可以判定不可达
#    2)至少有max(2,sentinels/2+1)个节点参与选举,才能选出leader sentinel
sentinel monitor master-1 10.211.55.10 6381 2
# 每个sentinel ping其余所有sentinel节点和数据节点,超时5000ms则判定节点失效
sentinel down-after-milliseconds master-1 5000
# 故障转移超时时间18s
sentinel failover-timeout master-1 18000
# 添加主节点密码,防止无法监控
sentinel auth-pass master-1 test123
# 每次故障转移,限制每次2个slave节点向新master节点发起复制,减少对master机器影响
sentinel parallel-syncs master-1 2
复制代码

tips

  1. sentinel节点不应该部署到同一个机器上
  2. 奇数个sentinel节点

集群

槽是redis集群管理数据的基本单位

集群模式下只有处理槽的主节点才负责读写请求和集群槽等关键信息维护.而从节点只进行主节点数据和状态信息复制

Tips

redis实现分布式锁

前提:redis单线程执行

string的setnx和setxx命令:setnx键必须不存在才能设置成功,setxx键必须存在才能设置成功

public class RedisTool {
    private static final String LOCK_SUCCESS = "OK";
    //setnx如果已有key存在,则函数不会调用成功
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;
    /**
     * 加锁
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
        //requestId:让加锁和解锁是同一个客户端
        //设置过期时间,即使客户端崩溃也可解锁,防止死锁
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
    /**
     * 释放分布式锁
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
        //Lua脚本:获取锁对应的value值,检查是否与requestId相等,如果相等则删除锁(解锁)
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        //eval()方法可以确保原子性
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}
复制代码

参考链接

  1. Redis 分布式锁的正确实现方式

相关文章:

  • Result Maps collection already contains value forxxx
  • Windows下安装最新版的MongoDB
  • 微信互联网:如何让别人找到你的小程序?
  • Unity重置Animator到初始状态和重复播放同一个Animation
  • 一种轻量级的C4C业务数据同步到S/4HANA的方式:Odata通知
  • 发送HTTP_GET请求 表头application/json
  • 网络文件共享-SAMBA
  • 如何辨别程序员的水平?
  • jQuery清空标签内容--防止内存泄露
  • 对“工厂方法”,突然茅塞顿开
  • 算法第三章上机实践报告
  • 2018-2019-1 20165320 《信息安全系统设计基础》第六周学习总结
  • ajax实现异步上传多图并且预览
  • Redis学习之管道机制
  • fiddler安装及抓包分析
  • 时间复杂度分析经典问题——最大子序列和
  • [译]前端离线指南(上)
  • Java 11 发布计划来了,已确定 3个 新特性!!
  • SpringCloud集成分布式事务LCN (一)
  • swift基础之_对象 实例方法 对象方法。
  • vuex 学习笔记 01
  • 第十八天-企业应用架构模式-基本模式
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 什么软件可以剪辑音乐?
  • 使用 QuickBI 搭建酷炫可视化分析
  • 使用agvtool更改app version/build
  • 使用Gradle第一次构建Java程序
  • 微信开源mars源码分析1—上层samples分析
  • 我是如何设计 Upload 上传组件的
  • 优化 Vue 项目编译文件大小
  • nb
  • 容器镜像
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • #include<初见C语言之指针(5)>
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (ros//EnvironmentVariables)ros环境变量
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (十六)一篇文章学会Java的常用API
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • .Net MVC4 上传大文件,并保存表单
  • .NET6实现破解Modbus poll点表配置文件
  • .NET基础篇——反射的奥妙
  • .NET框架设计—常被忽视的C#设计技巧
  • .NET运行机制
  • 。Net下Windows服务程序开发疑惑
  • @ 代码随想录算法训练营第8周(C语言)|Day57(动态规划)
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • [ MSF使用实例 ] 利用永恒之蓝(MS17-010)漏洞导致windows靶机蓝屏并获取靶机权限
  • [acwing周赛复盘] 第 94 场周赛20230311
  • [AIR] NativeExtension在IOS下的开发实例 --- IOS项目的创建 (一)
  • [BZOJ 3531][Sdoi2014]旅行(树链剖分+线段树)