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

Redis只用来做缓存?来认识一下它其他强大的能力吧。

当今互联网应用中,随着业务的发展,数据量越来越大,查询效率越来越高,对于时序数据的存储、查询和分析需求也越来越强烈,这时候 Redis 就成为了首选的方案之一。

Redis 提供了多种数据结构,如字符串、哈希表、列表、集合、有序集合等,每种数据结构都具备不同的特性,可以满足不同的业务需求。其中,有序集合的 score 可以存储时间戳,非常适合用于存储时序数据,例如监控指标、日志、统计数据、报表等。下面举几个时序数据场景例子:

  1. 监控指标:

假设我们有一个服务,名为 my_service,需要监控它的请求响应时间。我们可以使用 Redis 有序集合来存储数据,每个请求的响应时间作为 value,请求的时间戳作为 score。示例如下:

> ZADD requests:my_service 1613115560 350
(integer) 1
> ZADD requests:my_service 1613115570 450
(integer) 1
> ZADD requests:my_service 1613115580 550
(integer) 1
复制代码

这些命令向名为 requests:my_service 的有序集合中添加了 3 条数据,分别是 2021 年 2 月 12 日 10:19:20 的请求响应时间为 350ms,10:19:30 的请求响应时间为 450ms,10:19:40 的请求响应时间为 550ms。

接下来,我们来看一下如何使用 Redis 命令查询这些监控指标的数据。下面的命令会返回 requests:my_service 有序集合内所有数据:

> ZRANGE requests:my_service 0 -1 WITHSCORES
1) "350"
2) "1613115560"
3) "450"
4) "1613115570"
5) "550"
6) "1613115580"
复制代码

命令执行结果表示,数据按照 score 排序,其中 score 是时间戳(单位为秒),value 是请求响应时间(单位为毫秒)。同时,使用 ZRANGEBYSCORE 命令可以获取一段时间范围内的监控数据,例如:

> ZRANGEBYSCORE requests:my_service 1613115570 1613115580 WITHSCORES
1) "450"
2) "1613115570"
3) "550"
4) "1613115580"
复制代码

这条命令返回了 requests:my_service 有序集合中在时间戳 1613115570 到 1613115580 之间的所有数据。

  1. 日志:

假设我们要存储的日志是一条指定格式的字符串,包含时间戳和日志内容。使用 Redis 列表存储日志数据,每次写入新日志时可以使用 Redis 列表的 rpush 命令将数据写入列表的尾部。示例如下:

> RPUSH logs:my_logs 2021-02-12 10:30:00 INFO message 1
(integer) 1
> RPUSH logs:my_logs 2021-02-12 10:30:01 ERROR message 2
(integer) 2
> RPUSH logs:my_logs 2021-02-12 10:30:02 WARN message 3
(integer) 3
复制代码

这些命令向名为 logs:my_logs 的列表尾部添加 3 条数据,分别是 2021 年 2 月 12 日 10:30:00 的 INFO 级别消息,10:30:01 的 ERROR 级别消息和 10:30:02 的 WARN 级别消息。

接下来,我们来看一下如何使用 Redis 命令查询这些日志数据。下面的命令会返回 logs:my_logs 列表内所有数据:

> LRANGE logs:my_logs 0 -1
1) "2021-02-12 10:30:00 INFO message 1"
2) "2021-02-12 10:30:01 ERROR message 2"
3) "2021-02-12 10:30:02 WARN message 3"
复制代码

命令执行结果表示,数据按照插入顺序排序,从列表头部开始遍历。使用 ZRANGEBYSCORE 命令可以获取一段时间范围内的日志数据,例如:

> ZRANGEBYSCORE logs:my_logs 1613115570 1613115580
1) "2021-02-12 10:30:01 ERROR message 2"
复制代码

这条命令返回了 logs:my_logs 列表中在时间戳 1613115570 到 1613115580 之间的日志数据,但因为日志数据并没有具体的 time stamp 做 score,所以这个例子只是演示这个命令的用法,实际上应该使用有序集合去查询时间区间内的日志数据。

  1. 统计数据:

假设我们要存储的统计数据是一些具体业务相关的计数器,例如每分钟用户访问量。我们可以使用 Redis 有序集合来存储统计数据,key 是计数器名称,score 是时间戳,value 是具体的计数值(例如访问次数)。示例如下:

> ZADD visits 1613167800 100
(integer) 1
> ZADD visits 1613167860 120
(integer) 1
> ZADD visits 1613167920 150
(integer) 1
复制代码

这些命令向名为 visits 的有序集合中添加了 3 条数据,分别是 2021 年 2 月 12 日 23:30:00 的访问次数为 100,23:31:00 的访问次数为 120,23:32:00 的访问次数为 150。

接下来,我们来看一下如何使用 Redis 命令查询这些统计数据。下面的命令会返回 visits 有序集合内所有数据:

> ZRANGE visits 0 -1 WITHSCORES
1) "100"
2) "1613167800"
3) "120"
4) "1613167860"
5) "150"
6) "1613167920"
复制代码

命令执行结果表示,数据按照 score 排序,其中 score 是时间戳(单位为秒),value 是访问次数。使用 ZRANGEBYSCORE 命令可以获取一段时间范围内的统计数据,例如:

> ZRANGEBYSCORE visits 1613167860 1613167920 WITHSCORES
1) "120"
2) "1613167860"
3) "150"
4) "1613167920"
复制代码

这条命令返回了 visits 有序集合中在时间戳 1613167860 到 1613167920 之间的所有数据。

使用 Redis 有序集合中的另一个常见场景是计算 TopN,例如找出访问次数最多的前 10 个计数器,可以使用命令 ZREVRANGE visits 0 9 WITHSCORES,它返回 visits 有序集合中前 10 个元素,按照 value 从大到小排列,并且返回每个元素的 score。

需求实践:

这是一个实时监控系统,主要用于记录和统计服务发生的错误情况,以便在错误数量超过预设阈值时发出警告信息。

系统每秒钟生成随机错误数据,并将它们存储到 Redis 数据库中。每隔 10 秒钟,系统会从 Redis 数据库中聚合最近一分钟内的错误数据,并按照服务名和错误类型进行统计计算。如果某个服务的错误数量超过预设阈值,系统会输出一条警告信息提示用户。

整个系统的目标是帮助用户及时了解每个服务的错误情况,以便及时采取相应的措施,保障服务的稳定性和可靠性。

代码示例:

模拟接口服务异常数据

package com.example.demo.redis;import redis.clients.jedis.Jedis;
import java.util.*;public class DataGenerator {// 定义服务列表private static final List<String> SERVICES = Arrays.asList("service1", "service2", "service3");// 定义错误列表public static final List<String> ERRORS = Arrays.asList("invalid_param", "timeout", "unknown_error");/*** 生成数据** @param total 数据总数* @param jedis Redis 客户端连接*/public static void generateData(int total, Jedis jedis) {Random rand = new Random(); // 初始化随机数生成器long currentTimestamp = System.currentTimeMillis() / 1000; // 获取当前时间戳,精确到秒long startTimestamp = currentTimestamp - 60; // 计算起始时间戳,为当前时间戳减去 60 秒for (int i = 0; i < total; i++) { // 循环 total 次,生成 total 条数据String service = SERVICES.get(rand.nextInt(SERVICES.size())); // 随机选择一个服务String error = ERRORS.get(rand.nextInt(ERRORS.size())); // 随机选择一个错误long timestamp = startTimestamp + rand.nextInt(60); // 生成一个随机时间戳,精确到秒,范围为起始时间戳到当前时间戳int count = 1;String item = String.format("%s:%s:%d:%d", service, error, timestamp, count);jedis.zadd("error_data", timestamp, item); // 将错误数据存储到 Redis 数据库中}}
}复制代码

聚合异常数据,达到阈值告警

package com.example.demo.redis;import redis.clients.jedis.Jedis;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class DataAggregator {private static final String REDIS_HOST = "localhost"; // Redis 主机名private static final int REDIS_PORT = 6379; // Redis 端口号private static final int THRESHOLD = 100; // 预设阈值,当错误数量超过该阈值时触发警告public static void main(String[] args) {ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); // 创建一个只有一个线程的定时任务执行程序Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT); // 创建 Redis 客户端连接scheduler.scheduleAtFixedRate(() -> {// 并发情况下,线程会阻塞synchronized (jedis) {DataGenerator.generateData(20, jedis); // 生成随机错误数据,并将其存储到 Redis 数据库中}}, 0, 1, TimeUnit.SECONDS); // 定时任务间隔为 1 秒钟scheduler.scheduleAtFixedRate(() -> { // 定时任务逻辑synchronized (jedis) {long currentTimestamp = System.currentTimeMillis() / 1000; // 获取当前时间戳,精确到秒long startTimestamp = currentTimestamp - 60; // 计算起始时间戳,为当前时间戳减去 60 秒Set<String> data = jedis.zrangeByScore("error_data", startTimestamp, currentTimestamp); // 使用 zrange 命令获取指定时间范围内的数据Map<String, Map<String, Integer>> countMap = new HashMap<>(); // 用于记录聚合后的服务和错误数量信息for (String item : data) { // 遍历所有错误数据String[] parts = item.split(":"); // 以冒号为分隔符,将错误数据分割为部分String service = parts[0]; // 获取服务名String error = parts[1]; // 获取错误类型long timestamp = Long.parseLong(parts[2]); // 获取时间戳int count = Integer.parseInt(parts[3]); // 获取错误数量if (timestamp < startTimestamp) { // 如果时间戳早于起始时间戳,则跳过该数据continue;}Map<String, Integer> serviceCountMap = countMap.computeIfAbsent(service, k -> new HashMap<>()); // 获取指定服务的错误数量信息serviceCountMap.put(error, serviceCountMap.getOrDefault(error, 0) + count); // 更新指定服务和错误类型的错误数量信息}List<String> alerts = new ArrayList<>(); // 用于存储警告信息for (String service : countMap.keySet()) { // 遍历服务名列表Map<String, Integer> serviceCountMap = countMap.get(service); // 获取服务和错误数量信息int totalErrors = 0;for (String error : serviceCountMap.keySet()) { // 遍历错误列表int count = serviceCountMap.get(error); // 获取错误数量totalErrors += count;}if (totalErrors > THRESHOLD) { // 如果错误数量超过预设阈值alerts.add(service + " has too many errors: " + serviceCountMap.keySet() + ", count: " + totalErrors); // 将该服务名添加到警告信息列表中}}if (!alerts.isEmpty()) { // 如果警告信息列表不为空System.out.println(String.join("\n", alerts)); // 打印警告信息}}}, 0, 10, TimeUnit.SECONDS); // 定时任务间隔为 10 秒// 关闭 Redis 连接jedis.close();}
}复制代码

以上代码可正常运行,有疑问可以交流~~

相关文章:

Redis只用来做缓存?来认识一下它其他强大的能力吧。

当今互联网应用中&#xff0c;随着业务的发展&#xff0c;数据量越来越大&#xff0c;查询效率越来越高&#xff0c;对于时序数据的存储、查询和分析需求也越来越强烈&#xff0c;这时候 Redis 就成为了首选的方案之一。 Redis 提供了多种数据结构&#xff0c;如字符串、哈希表…...

【ES】数据同步集群

【ES】数据同步&集群3.数据同步3.1.思路分析3.1.1.同步调用3.1.2.异步通知3.1.3.监听binlog3.1.4.选择3.2.实现数据同步3.2.1.思路3.2.2.导入demo3.2.3.声明交换机、队列1&#xff09;引入依赖2&#xff09;声明队列交换机名称3&#xff09;声明队列交换机3.2.4.发送MQ消息…...

37岁男子不愿熬夜,回乡养鸡每天准时下班,青山绿水中养鸡,直播间里卖鸡蛋...

37岁男子不愿熬夜&#xff0c;回乡养鸡每天准时下班&#xff0c;青山绿水中养鸡&#xff0c;直播间里卖鸡蛋。今天和大家分享一个创业案例&#xff0c;他叫胡铭浩&#xff0c;来自安徽省旌德县&#xff0c;今年37岁&#xff0c;曾做过车床操作工&#xff0c;开过婚纱摄影店&…...

深度学习和人工智能之间是什么样的关系?

深度学习与人工智能概念的潜在联系&#xff0c;我们依然借助维恩图来说明&#xff0c;如图4.1所示。 1、人工智能 “人工智能”这个概念新鲜时髦但又含混模糊&#xff0c;同时包罗万象。尽管如此,我们仍尝试对 人工智能进行定义:用一台机器处理来自其周围环境的信息,然后将这些…...

实战打靶集锦-016-lampiao

提示&#xff1a;本文记录了博主打靶过程中一次曲折的提权经历 文章1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查4.1 80端口探查4.2 1898端口探查4.3 EXP搜索4.3.1 exploit/unix/webapp/drupal_coder_exec4.3.2 exploit/unix/webapp/drupal_drupalgeddon25. 提权5.1 系统信息…...

《Web前端应用开发》考试试卷(模拟题)

一、产品搜索页面 打开“考试文件夹”中的input.html&#xff0c;完成以下步骤&#xff1a; 注意&#xff1a;本题仅能在input.html的&#xff08;1&#xff09;为产品名称所在的div添加样式属性&#xff0c;使得产品名称保持在文本框的左边&#xff1b; &#xff08;2&#xf…...

【react全家桶学习】react简介

react是什么&#xff1f; react是用于构建用户界面的JS库&#xff0c;是一个将数据渲染为HTML视图的开源JS库 谁开发的&#xff1f; 由Facebook开发&#xff0c;且开源 为什么要学&#xff1f; 原生JavaScript操作DOM繁琐、效率低 ( DOM-API操作 UI)使用JavaScript直接操作…...

此战成硕,我成功上岸西南交通大学了~~~

友友们&#xff0c;好久不见&#xff0c;很长时间没有更一个正式点的文章了&#xff01; 是因为我在去年年底忙着准备初试&#xff0c;今年年初在准备复试&#xff0c;直到3月底拟录取后&#xff0c;终于可以写下这篇上岸贴&#xff0c;和大家分享一下考研至上岸的一个过程 文章…...

光耦继电器工作原理及优点概述

光耦继电器是一种电子元器件&#xff0c;也是固态继电器的一种&#xff0c;其主要作用是隔离输入与输出电路&#xff0c;用于保护或者控制电路的正常工作。 光耦继电器工作原理是利用光电转换器将外界信号转化为光信号&#xff0c;通过光纤传输到另一端&#xff0c;再由另一端的…...

【Mysql】mysql8.0.26解压包部署方式

版本背景&#xff1a; 操作系统&#xff1a;centos7.3 mysql版本&#xff1a;mysql-8.0.26-linux-glibc2.12-x86_64.tar 一、前期准备 1、检测操作系统自带安装的mysql和mariadb服务&#xff0c;如存在&#xff0c;需卸载 rpm -qa | grep mysql rpm -qa | grep mariadb 卸载…...

进销存管理系统能为企业带来哪些实际效益?

随着互联网的不断发展&#xff0c;如今的商业世界已经越来越向数字化转型。拥有一套完整的数字化的进销存管理能够极大地提升公司货物进出库存情况的效率和准确性&#xff0c;避免过程中出现不必要的错误和漏洞&#xff0c;从而帮助企业更加稳健地自我发展。那么&#xff0c;一…...

图片怎么转换成pdf格式?这几个方法帮你一键转换

现今电子书籍越来越受到欢迎&#xff0c;其中PDF格式也成为了一种常用的电子书籍格式。无论是工作还是学习&#xff0c;我们都可能会遇到需要将图片转换成PDF格式的情况&#xff0c;例如保存一些资料证明、公文公告、学习资料等。在这篇文章中&#xff0c;我们将为大家介绍三种…...

数据结构exp1_2学生成绩排序

目录 数据结构exp1_2学生成绩排序 程序设计 程序分析 数据结构exp1_2学生成绩排序 【问题描述】 对某班学生成绩排序。从键盘依次输入某班学生的姓名和成绩(一个班级人数最多不超过50人)并保存,然后分别按学生成绩由高到低顺序输出学生姓名和成绩,成绩相同时,则按输…...

在DongshanPI-D1开箱使用分享与折腾记录实现MPU6050数据读取

前言 上一篇文章使用RT-Smart的IIC驱动OLED屏幕&#xff0c;进行基本的字符串显示,在使用过程中对RT-Smart有了一定熟悉&#xff0c;准备使用SPI驱动ST7789&#xff0c;但SPI接口没有引出&#xff0c;本次使用手上已有的传感器MPU6050进行使用。 过程 本次直接开始添加离线包…...

Nature子刊 定制饮食去除半胱氨酸和蛋氨酸可诱导细胞自毁进而治疗脑瘤?

恶性胶质瘤是成人最常见的脑部肿瘤。恶性胶质瘤的致死率为100%&#xff0c;无法治愈&#xff0c;是一种极度的恶性肿瘤。如此糟糕的预后促使研究者及神经外科医生不断学习研究肿瘤生物学&#xff0c;期望创造更好的疗法。神经外科助理教授Dominique Higgins博士从事肿瘤生物学的…...

抛弃 TCP 和 QUIC 的 HTTP

下班路上发了一则朋友圈&#xff1a; 周四听了斯坦福老教授 John Ousterhout 关于 Homa 的分享&#xff0c;基本重复了此前那篇 It’s Time To Rep… 的格调&#xff0c;花了一多半时间喷 TCP… Ousterhout 关于 Homa 和 TCP 之间的论争和论证&#xff0c;诸多反复回执&…...

未来公寓智能化设计平台项目(下)

创业场景通过在社区入口附近建设共享办公室,带动海慧园和众汽佳苑创业氛围,也让社区出了居住以外有其它功能,并且结合教育、邻里模块让社区更有活力。住户可通过app查看共享空间的使用情况,以及可以远程控制各种设备。 顺应未来生活与就业、创业融合新趋势,构建“大众创新…...

常见分布式消息队列综合对比

本文将从&#xff0c;Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ 17 个方面综合对比作为消息队列使用时的差异。 1. 资料文档 Kafka&#xff1a;中&#xff0c;有 kafka 作者自己写的书&#xff0c;网上资料也有一些。 rabbitmq&#xff1a;多&#xff0c;有一些不错的书…...

怎么邀请主流媒体到现场报道

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好 主流媒体通常是指央媒&#xff0c;报纸杂志&#xff0c;电视台&#xff0c;地方重点媒体等&#xff0c;采访形式包括现场取材报道&#xff0c;媒体专访&#xff0c;群访等。通常主流媒体对选题要求较严格&#xff0c;因此在…...

2023年最强手机远程控制横测:ToDesk、向日葵、Airdroid三款APP免Root版本

前言 随着远程办公和远程协作的日益普及&#xff0c;跨设备、系统互通的远程控制软件已经成为职场人士不可或缺的工具之一。在国内&#xff0c;向日葵和ToDesk是最著名的远程控制软件&#xff1b;而在国外&#xff0c;则有微软远程桌面、AirDroid、TeamViewer、AnyDesk、Parse…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

python爬虫——气象数据爬取

一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用&#xff1a; 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests&#xff1a;发送 …...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

elementUI点击浏览table所选行数据查看文档

项目场景&#xff1a; table按照要求特定的数据变成按钮可以点击 解决方案&#xff1a; <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

ArcPy扩展模块的使用(3)

管理工程项目 arcpy.mp模块允许用户管理布局、地图、报表、文件夹连接、视图等工程项目。例如&#xff0c;可以更新、修复或替换图层数据源&#xff0c;修改图层的符号系统&#xff0c;甚至自动在线执行共享要托管在组织中的工程项。 以下代码展示了如何更新图层的数据源&…...

spring boot使用HttpServletResponse实现sse后端流式输出消息

1.以前只是看过SSE的相关文章&#xff0c;没有具体实践&#xff0c;这次接入AI大模型使用到了流式输出&#xff0c;涉及到给前端流式返回&#xff0c;所以记录一下。 2.resp要设置为text/event-stream resp.setContentType("text/event-stream"); resp.setCharacter…...

智警杯备赛--excel模块

数据透视与图表制作 创建步骤 创建 1.在Excel的插入或者数据标签页下找到数据透视表的按钮 2.将数据放进“请选择单元格区域“中&#xff0c;点击确定 这是最终结果&#xff0c;但是由于环境启不了&#xff0c;这里用的是自己的excel&#xff0c;真实的环境中的excel根据实训…...