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

3.Redis高级特性和应用(慢查询、Pipeline、事务、Lua、限流原理)

1. Redis的慢查询

1.1 概念

在数据库系统中,慢查询是指执行时间超过预设阈值的查询操作。Redis也提供了慢查询日志功能,帮助开发和运维人员定位性能瓶颈。慢查询日志记录了执行时间较长的命令,以便进行优化。

1.2 慢查询的执行过程

Redis客户端执行一条命令的过程分为四个步骤:

  1. 发送命令:客户端向Redis服务器发送命令。
  2. 命令排队:命令在服务器中排队等待执行。
  3. 命令执行:Redis执行命令并记录执行时间。
  4. 返回结果:将结果返回给客户端。

需要注意,慢查询只统计步骤3的时间,因此可能存在网络问题或命令排队导致的超时,但这些不会被记录为慢查询。

1.3 生活场景示例

想象一下,你在餐馆点了菜。你下单(发送命令),然后服务员把订单放到厨房(命令排队),接着厨师开始做菜(命令执行),最后服务员把菜端到你面前(返回结果)。如果厨师做菜太慢,导致你等得不耐烦,这就类似于Redis的慢查询。

1.4 慢查询配置

Redis提供了两种方式来配置慢查询:

1.4.1 动态设置

使用命令动态修改慢查询阈值:

CONFIG SET slowlog-log-slower-than 20000
  • 默认阈值是10毫秒(10,000微秒)。
  • 设置为0表示记录所有命令,设置为负值表示不记录任何命令。
1.4.2 配置文件设置

在 redis.conf 配置文件中,可以找到以下配置项:

slowlog-max-len 128
  • slowlog-max-len 用于设置慢查询日志的最大条数,默认是128条。

1.5 慢查询操作命令

  • 获取慢查询日志
SLOWLOG GET [n]
  • 获取慢查询日志长度
SLOWLOG LEN
  • 重置慢查询日志
SLOWLOG RESET

1.6 慢查询建议

  • 增加慢查询日志条数:建议设置为1000条以上,以避免丢失重要日志。
  • 调整阈值:根据Redis的并发量调整慢查询阈值,通常设置为1毫秒或更低,以便及时发现性能问题。

2. Pipeline

2.1 概念

Pipeline(流水线)是一种优化技术,可以将多条命令打包在一起,通过一次网络往返(RTT)发送给Redis服务器,从而减少网络延迟,提高执行效率。

2.2 生活场景示例

想象一下,你在超市购物。如果每次都要排队结账(发送命令),你可能会等得很久。但是如果你把所有商品放在购物车里,一次性结账(使用Pipeline),那么你就可以节省很多时间。

2.3 工作原理

在没有Pipeline的情况下,执行n条命令需要n次RTT,而使用Pipeline后,只需一次RTT即可完成所有命令的发送和接收。

2.4 使用场景

  • 执行大量命令时,使用Pipeline可以显著提高性能,尤其是在高延迟网络环境中。

2.5 注意事项

  • 发送的命令数量不宜过多,以免造成网络阻塞和客户端等待时间增加。
  • Pipeline只能操作一个Redis实例,适合批量操作。

2.6 Java代码示例

以下是使用Java的Jedis库实现Pipeline的代码示例:

java

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;public class RedisPipelineExample {public static void main(String[] args) {// 创建Redis连接Jedis jedis = new Jedis("localhost", 6379);// 使用PipelinePipeline pipeline = jedis.pipelined();for (int i = 0; i < 1000; i++) {pipeline.set("key" + i, String.valueOf(i));  // 批量设置键值对}// 执行所有命令pipeline.sync();// 关闭连接jedis.close();}
}

3. 事务

3.1 概念

事务是一组操作,要么全部成功,要么全部失败。Redis事务通过 MULTI 和 EXEC 命令实现。

3.2 生活场景示例

想象一下,你在银行转账。如果转账成功,账户A减少金额,账户B增加金额;如果转账失败,那么两个账户的金额都不变。这就是一个事务的例子。

3.3 事务的基本操作

  1. 开始事务
MULTI
  1. 添加命令
SADD user:1:friends user:2
  1. 提交事务
EXEC
  1. 回滚事务
DISCARD

3.4 事务的特点

  • 事务中的命令在执行 EXEC 之前不会真正执行,而是缓存起来。
  • Redis只支持基本的语法错误检查,运行时错误不会回滚之前的命令。

3.5 Java代码示例

以下是使用Java的Jedis库实现事务的代码示例:

java

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;public class RedisTransactionExample {public static void main(String[] args) {// 创建Redis连接Jedis jedis = new Jedis("localhost", 6379);// 开始事务Transaction transaction = jedis.multi();// 添加命令transaction.sadd("user:1:friends", "user:2");// 提交事务transaction.exec();// 关闭连接jedis.close();}
}

4. Lua脚本

4.1 概念

Lua是一种轻量级的脚本语言,Redis内置了Lua支持,可以通过Lua脚本实现复杂的操作。

4.2 生活场景示例

想象一下,你在厨房里做菜。你可以把多个步骤(切菜、煮汤、上菜)写成一个食谱(Lua脚本),一次性完成,而不需要每一步都去问别人怎么做。

4.3 Lua脚本的优点

  1. 减少网络开销:多个命令可以放在同一个脚本中运行。
  2. 原子操作:整个脚本作为一个整体执行,中间不会被其他命令插入。
  3. 复用性:脚本可以被多个客户端复用。

4.4 Java代码示例

以下是使用Java的Jedis库执行Lua脚本的代码示例:

java

import redis.clients.jedis.Jedis;public class RedisLuaExample {public static void main(String[] args) {// 创建Redis连接Jedis jedis = new Jedis("localhost", 6379);// Lua脚本示例String luaScript = "return redis.call('GET', KEYS[1])";// 执行Lua脚本String result = (String) jedis.eval(luaScript, 1, "key1");System.out.println("Result from Lua script: " + result);// 关闭连接jedis.close();}
}

5. Redis与限流

5.1 概念

限流是一种控制访问频率的技术,确保系统在高并发情况下保持稳定。它可以防止系统因请求过多而崩溃,同时也能确保各个用户的请求得到公平处理。

5.2 限流原理

限流的原理可以通过以下算法来实现:

  1. 固定窗口算法

    • 将时间划分为固定大小的窗口(例如每分钟)。
    • 在每个窗口内,允许一定数量的请求。
    • 如果请求数超过限制,则拒绝后续请求。

    例子:假设每分钟允许10个请求,如果在第一分钟内接收到了10个请求,那么在接下来的请求将被拒绝,直到下一个窗口开始。

    优点:简单易实现,适合于请求量相对平稳的场景。

    应用场景:适用于API调用、用户登录等场景。

  2. 滑动窗口算法

    • 类似于固定窗口,但时间窗口是动态的,允许在滑动窗口内的请求数。
    • 这样可以更平滑地控制请求,而不容易在窗口边界处出现突发请求。

    优点:可以减少突发请求的情况,适合更复杂的限流需求。

    应用场景:适用于实时性要求较高的系统,如在线支付、抢购等。

  3. 漏桶算法

    • 设想一个漏桶,桶的容量固定,水以固定速率漏出。
    • 请求流入桶中,如果桶满了,则丢弃请求。
    • 这种算法确保了请求的平稳流入。

    优点:可以平滑处理突发流量,适合高并发场景。

    应用场景:适用于流量控制,如视频流、音频流等。

  4. 令牌桶算法

    • 先有一个桶,容量是固定的,用来放令牌。
    • 以固定速率向桶放令牌,如果桶满了就不放令牌。
    • 处理请求时,先从桶拿令牌,拿到令牌才能处理请求,没拿到则被限流。

    优点:允许突发请求,但整体速率受限,适合动态流量。

    应用场景:适用于用户注册、消息发送等场景。

5.3 生活场景示例

  • 固定窗口算法:想象你在一个游乐园,每小时只能进入10个人。如果这个小时已经有10个人进入,那么其他人就需要等到下一个小时才能进入。

  • 滑动窗口算法:你在游乐园,每分钟只能进入2个人。如果这一分钟有2个人进入,下一分钟仍然可以接受2个人,但如果在这段时间内有更多的人,就需要等到下一个时间段。

  • 漏桶算法:想象一个水桶,水流入桶中,但桶底有个洞,水以固定速度流出。如果水流入速度过快,桶满了,水就会溢出。

  • 令牌桶算法:你有一个固定容量的桶,每秒可以放入一个令牌。每当你想处理请求时,必须先从桶中拿到令牌。如果没有令牌,就必须等待。

5.4 使用Redis和Lua实现限流

通过Redis的原子操作和Lua脚本,可以实现高效的限流控制,避免系统过载。

5.5 Java代码示例

以下是使用Java的Jedis库和Lua脚本实现四种限流算法的代码示例:

5.5.1 固定窗口算法

java

import redis.clients.jedis.Jedis;public class FixedWindowRateLimiter {public static void main(String[] args) {Jedis jedis = new Jedis("localhost", 6379);String key = "fixed_window_key";int limit = 5;  // 每分钟允许的请求数int window = 60; // 时间窗口,单位为秒// 获取当前请求数String currentCount = jedis.get(key);if (currentCount == null) {jedis.setex(key, window, "1"); // 设置初始请求数System.out.println("请求被允许");} else {int count = Integer.parseInt(currentCount);if (count < limit) {jedis.incr(key); // 增加请求数System.out.println("请求被允许");} else {System.out.println("请求被拒绝,超出限流");}}jedis.close();}
}
5.5.2 滑动窗口算法

java

import redis.clients.jedis.Jedis;public class SlidingWindowRateLimiter {public static void main(String[] args) {Jedis jedis = new Jedis("localhost", 6379);String key = "sliding_window_key";int limit = 5;  // 允许的请求数int window = 60; // 时间窗口,单位为秒long currentTime = System.currentTimeMillis() / 1000;long windowStart = currentTime - window;// 清理过期请求jedis.zremrangeByScore(key, 0, windowStart);// 获取当前请求数long count = jedis.zcard(key);if (count < limit) {jedis.zadd(key, currentTime, String.valueOf(currentTime)); // 记录当前请求System.out.println("请求被允许");} else {System.out.println("请求被拒绝,超出限流");}jedis.close();}
}
5.5.3 漏桶算法

java

import redis.clients.jedis.Jedis;public class LeakyBucketRateLimiter {public static void main(String[] args) {Jedis jedis = new Jedis("localhost", 6379);String key = "leaky_bucket_key";int capacity = 10;  // 桶的容量int leakRate = 1;   // 漏出速率,单位为每秒// 获取当前水位String currentWater = jedis.get(key);if (currentWater == null) {currentWater = "0";jedis.set(key, currentWater);}// 计算当前水位int water = Integer.parseInt(currentWater);water = Math.max(0, water - leakRate); // 漏水jedis.set(key, String.valueOf(water)); // 更新水位// 判断是否可以加入请求if (water < capacity) {water++;jedis.set(key, String.valueOf(water)); // 加入请求System.out.println("请求被允许");} else {System.out.println("请求被拒绝,超出限流");}jedis.close();}
}
5.5.4 令牌桶算法

java

import redis.clients.jedis.Jedis;public class TokenBucketRateLimiter {public static void main(String[] args) {Jedis jedis = new Jedis("localhost", 6379);String key = "token_bucket_key";int capacity = 10;  // 桶的容量int refillRate = 1; // 令牌放入速率,单位为每秒// 获取当前令牌数String currentTokens = jedis.get(key);if (currentTokens == null) {currentTokens = "0";jedis.set(key, currentTokens);}int tokens = Integer.parseInt(currentTokens);tokens = Math.min(capacity, tokens + refillRate); // 令牌放入jedis.set(key, String.valueOf(tokens)); // 更新令牌数// 判断是否可以处理请求if (tokens > 0) {tokens--;jedis.set(key, String.valueOf(tokens)); // 消耗令牌System.out.println("请求被允许");} else {System.out.println("请求被拒绝,超出限流");}jedis.close();}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 笔记 12 : 彭老师课本第 6 章, PWM ,代码实践
  • 位图 —— 哈希思想的产物
  • 网站开发:XTML+CSS - 网页文档结构
  • 【代码随想录训练营第42期 Day46打卡 - 回文问题 - LeetCode 647. 回文子串 516.最长回文子序列
  • 革命性架构:如何用命令模式彻底革新手游后端设计
  • mysql 修改用户密码
  • C++:类和对象(二)
  • 顶级 SSD 硬盘数据恢复工具探讨:最佳 SSD 硬盘数据有哪些
  • web渗透:XXE漏洞
  • python(9) : docker方式运行python程序(自启动,守护)
  • Flutter中组件动态可见的实现
  • 智慧校园”的系统设计数据库
  • 28. 双耳配对 - 配置
  • linux系统中USB模块鼠标驱动实现
  • 计算机毕业设计 基于SpringBoot框架的网上蛋糕销售系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
  • SegmentFault for Android 3.0 发布
  • #Java异常处理
  • 2017前端实习生面试总结
  •  D - 粉碎叛乱F - 其他起义
  • HTML5新特性总结
  • IDEA常用插件整理
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • java 多线程基础, 我觉得还是有必要看看的
  • javascript从右向左截取指定位数字符的3种方法
  • Kibana配置logstash,报表一体化
  • Python socket服务器端、客户端传送信息
  • 创建一个Struts2项目maven 方式
  • 给初学者:JavaScript 中数组操作注意点
  • 利用DataURL技术在网页上显示图片
  • 排序算法之--选择排序
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 用quicker-worker.js轻松跑一个大数据遍历
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​决定德拉瓦州地区版图的关键历史事件
  • #define 用法
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • (23)Linux的软硬连接
  • (24)(24.1) FPV和仿真的机载OSD(三)
  • (Repost) Getting Genode with TrustZone on the i.MX
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (六)Flink 窗口计算
  • (五)activiti-modeler 编辑器初步优化
  • (转)Linux下编译安装log4cxx
  • (转)linux下的时间函数使用
  • (转)大道至简,职场上做人做事做管理
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • ***汇编语言 实验16 编写包含多个功能子程序的中断例程
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .NET 漏洞分析 | 某ERP系统存在SQL注入
  • .NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(二)...
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • .NET中的Exception处理(C#)
  • .NET中统一的存储过程调用方法(收藏)
  • @antv/x6 利用interacting方法来设置禁止结点移动的方法实现。
  • @Autowired多个相同类型bean装配问题