Redis从入门到精通(二十一)Redis最佳实践(二)mset、pipeline、慢查询优化、内存划分

文章目录

    • 前言
    • 7.2 批处理优化
      • 7.2.1 命令执行流程
      • 7.2.2 mset
      • 7.2.3 Pipeline
      • 7.2.4 集群下的批处理
        • 7.2.4.1 问题与解决方案
        • 7.2.4.2 基于Spring的串行化执行
    • 7.3 服务器端优化
      • 7.3.1 持久化配置
      • 7.3.2 慢查询优化
        • 7.3.2.1 什么是慢查询
        • 7.3.2.2 如何查看慢查询
      • 7.3.3 命令及安全配置
      • 7.3.4 内存划分和内存配置
      • 7.3.5 集群or主从?
        • 7.3.5.1 集群完整性问题
        • 7.3.5.2 集群带宽问题
        • 7.3.5.3 其他问题
        • 7.3.5.4 结论

前言

Redis最佳实现系列文章:

Redis从入门到精通(二十)Redis最佳实践(一)优雅的Key结构、拒绝BigKey

7.2 批处理优化

7.2.1 命令执行流程

客户端与Redis服务器交互时,单个命令的执行流程如下:

N条命令的执行流程:

Redis处理指令是很快的,主要花费的时候在于网络传输,于是很容易就想到可以将多条指令批量的传输给Redis:

7.2.2 mset

Redis提供了msethmset这样的命令,可以实现批量插入数据。 例如利用mset一次性批量插入1000条数据:

@Test
public void testMset() {
    long b = System.currentTimeMillis();
    String[] arr = new String[2000];
    for (int i = 0; i < 2000; i++) {
        arr[i] = "test:mset:key_" + i;
        arr[i+1] = "value_" + i;
        i++;
    }
    jedis.mset(arr);
    long e = System.currentTimeMillis();
    System.out.println("time: " + (e - b));
}

控制台打印执行时间:

time: 7

此时Redis中的数据:

7.2.3 Pipeline

mset虽然可以批处理,但是却只能操作部分数据类型,因此如果有对复杂数据类型的批处理需要,建议使用Pipeline,例如:

@Test
public void testPipeline() {
    long b = System.currentTimeMillis();
    // 创建管道
    Pipeline pipeline = jedis.pipelined();
    for (int i = 1; i <= 1000; i++) {
        // 放入命令到管道
        pipeline.set("test:pipeline:key_" + i, "value_" + i);
    }
    pipeline.sync();
    long e = System.currentTimeMillis();
    System.out.println("time: " + (e - b));
}

控制台打印执行时间:

time: 119

此时Redis中的数据:

7.2.4 集群下的批处理

7.2.4.1 问题与解决方案

mset或Pipeline批处理命令在一次请求中一般会携带多条命令,而如果此时Redis是一个集群,那批处理命令的多个Key必须落在一个插槽中,否则就会导致执行失败。

这样的要求其实很难实现,因为在批处理时可能一次要插入很多条数据,这些数据很有可能落在不相同的节点上,这就会导致报错了。

解决这个问题,有4种方案:

7.2.4.2 基于Spring的串行化执行
@Test
public void testMset() {
    // MSET写数据
    Map<String, String> map = new HashMap<>(3);
    map.put("name", "Rose");
    map.put("age", "21");
    map.put("sex", "Female");
    stringRedisTemplate.opsForValue().multiSet(map);
    // MGET取数据
    List<String> strings = stringRedisTemplate.opsForValue().multiGet(Arrays.asList("name", "age", "sex"));
    strings.forEach(System.out::println);
}

运行单元测试结果如下:

Rose
21
Female

此时Redis种的数据:

7.3 服务器端优化

7.3.1 持久化配置

Redis的持久化虽然可以保证数据安全,但也会带来很多额外的开销,因此持久化一般要遵循下列建议:

  • 用来做缓存的Redis实例尽量不要开启持久化功能

  • 建议关闭RDB持久化功能,使用AOF持久化

  • 利用脚本定期在slave节点做RDB,实现数据备份

  • 设置合理的rewrite阈值,避免频繁的bgrewrite

  • 配置no-appendfsync-on-rewrite = yes禁止在rewrite期间做AOF,避免因AOF引起的阻塞

  • 部署有关建议:

    • Redis实例的物理机要预留足够内存,应对fork和rewrite
    • 单个Redis实例内存上限不要太大,例如4G或8G
    • 不要与CPU密集型应用部署在一起
    • 不要与高硬盘负载应用一起部署。例如:数据库、消息队列。

7.3.2 慢查询优化

7.3.2.1 什么是慢查询

并不是说很慢的查询才是慢查询,而是在Redis执行时,耗时超过某个阈值的命令,称为慢查询。

慢查询的危害:由于Redis是单线程的,所以当客户端发出指令后,它们都会进入到Rdis底层的queue来执行,如果此时有一些慢查询的数据,就会导致大量请求阻塞,从而引起报错。

  • 慢查询的阈值可以通过 slowlog-log-slower-than 配置指定,单位是微秒。默认是10000,建议1000。
127.0.0.1:6379> CONFIG GET slowlog-log-slower-than
1) "slowlog-log-slower-than"
2) "10000"
  • 慢查询会被放入慢查询日志中,日志的长度有上限,可以通过 slowlog-max-len 配置指定,本质是一个队列。默认是128,建议1000。
127.0.0.1:6379> CONFIG GET slowlog-max-len
1) "slowlog-max-len"
2) "128"
  • 要修改这两个配置可以使用 config set 命令:
127.0.0.1:6379> CONFIG set slowlog-log-slower-than 1000
OK
127.0.0.1:6379> CONFIG set slowlog-max-len 1000
OK
7.3.2.2 如何查看慢查询

查看慢查询日志列表可以使用以下名:

  • slowlog len:查询慢查询日志长度
  • slowlog get [n]:读取n条慢查询日志
  • slowlog reset:清空慢查询列表

7.3.3 命令及安全配置

Redis默认情况下,会绑定在0.0.0.0:6379,这样将会使Redis服务暴露到公网上,如果Redis没有开启身份认证,则可以导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据

攻击者在未授权访问Redis的情况下,还可以利用Redis的相关方法,在Redis服务器上写入公钥,进而可以使用对应私钥直接登录目标服务器。

更详细的漏洞描述和重现方式见:https://cloud.tencent.com/developer/article/1039000

漏洞出现的核心的原因有以下几点:

  • Redis未设置密码
  • 利用了Redis的config set命令动态修改Redis配置
  • 使用了root账号权限启动Redis

为了避免这样的漏洞,可以参照以下建议:

  • Redis一定要设置密码
  • 禁止使用下面命令:keys、flushall、flushdb、config set等命令,可以利用rename-command禁用。
  • bind:限制网卡,禁止外网网卡访问
  • 开启防火墙
  • 不要使用root账户启动Redis
  • 尽量不使用默认的端口

7.3.4 内存划分和内存配置

当Redis内存不足时,可能导致Key频繁被删除、响应时间变长、QPS不稳定等问题。Redis的内存占用一般包括三个方面:

  • 1)数据内存:Redis最主要的部分,存储Redis的键值信息,主要问题是BigKey问题、内存碎片问题。

    • 碎片问题:Redis底层分配有自己的分配策略。例如当前Key只需要10个字节,此时分配8字节肯定不够,那么底层就会分配16个字节,多出来的6个字节就不能被使用,也就时产生了碎片。
  • 2)进程内存:Redis主进程本身运⾏需要占⽤的内存,如代码、常量池等等;这部分内存⼤约⼏兆,在⼤多数⽣产环境中与Redis数据占⽤的内存相⽐可以忽略。

  • 3)缓冲区内存:一般包括客户端缓冲区、AOF缓冲区、复制缓冲区等。客户端缓冲区又包括输入缓冲区和输出缓冲区两种。这部分内存占用波动较大,不当使用BigKey,可能导致内存溢出。

Redis提供了一些命令,用于查询Redis目前的内存分配状态:

  • info memory:查看内存分配状态

  • memory usage key:查看某个key的内存
127.0.0.1:6379> memory usage test:pipeline:key_195
(integer) 80

内存缓冲区常见的有三种:

  • 复制缓冲区:主从复制的repl_backlog_buf,如果太小可能导致频繁的全量复制,影响性能。可以通过repl-backlog-size配置来设置,默认1mb。
  • AOF缓冲区:AOF执行rewrite之前的缓冲区。无法设置容量上限。
  • 客户端缓冲区:分为输入缓冲区和输出缓冲区,输入缓冲区最大1G且不能设置,输出缓冲区可以设置。

一般复制缓冲区和AOF缓冲区不会有问题,可能有问题的是客户端缓冲区。

客户端缓冲区指的就是客户端向Redis发送命令时,用来缓存命令的一个输入端缓冲区,以及Redis向客户端返回数据的输出缓存区。输入缓冲区最大1G且不能设置,一般不会有问题,如果超过了这个空间,Redis会直接断开,因为此时此刻就代表着Redis处理不过来了。

因此输入端缓冲区并不需要担心,要担心的时输出端缓冲区。 客户端缓冲区的配置如下:

如上图所示,client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>配置的几个参数含义如下:

  • <class>:客户端类型,包括normal(普通客户端)、replica(主从复制客户端)、pubsub(PubSub客户端)
  • <hard limit>:缓冲区上限,超过hard limit后断开客户端
  • <soft limit> <soft seconds>:持续时间限制,当内存大小达到soft limit,并持续soft seconds秒后,断开客户端

7.3.5 集群or主从?

集群虽然具备高可用特性,能实现自动故障恢复,但是如果使用不当,也会存在一些问题:

7.3.5.1 集群完整性问题

在Redis的默认配置中,如果发现任意一个插槽不可用,则整个集群都会停止对外服务。

在实际开发中,最重要的是可用性,即使有slot不能使用,Redis集群也应该可以对外提供服务。为此,需要把如下配置修改成no:

# 默认为yes
cluster-require-full-coverage no
7.3.5.2 集群带宽问题

集群节点之间会不断的互相Ping来确定集群中其它节点的状态。每次Ping携带的信息至少包括:插槽信息、集群状态信息等。

集群中节点越多,集群状态信息数据量也越大,10个节点的相关信息可能达到1kb,此时每次集群互通需要的带宽会非常高,这样会导致集群中大量的带宽都会被Ping信息所占用。

解决方案主要有:

  • 避免大集群,集群节点数不要太多,最好少于1000,如果业务庞大,则建立多个集群。
  • 避免在单个物理机中运行太多Redis实例。
  • 配置合适的cluster-node-timeout值。
7.3.5.3 其他问题
  • 数据倾斜问题
  • 客户端性能问题
  • 命令的集群兼容性问题
  • lua和事务问题
7.3.5.4 结论

单体Redis(主从Redis)已经能达到万级别的QPS,并且也具备很强的高可用特性。如果主从能满足业务需求的情况下,所以如果不是在万不得已的情况下,尽量不搭建Redis集群。

本节完。本节所涉及的代码和资源可从git仓库下载:https://gitee.com/weidag/redis_learning.git

更多内容请查阅分类专栏:Redis从入门到精通

感兴趣的读者还可以查阅我的另外几个专栏:

  • SpringBoot源码解读与原理分析(已完结)
  • MyBatis3源码深度解析(已完结)
  • 再探Java为面试赋能(持续更新中…)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/564223.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

智慧安防边缘计算硬件AI智能分析网关V4算法启停的操作步骤

TSINGSEE青犀视频智能分析网关V4内置了近40种AI算法模型&#xff0c;支持对接入的视频图像进行人、车、物、行为等实时检测分析&#xff0c;上报识别结果&#xff0c;并能进行语音告警播放。硬件管理平台支持RTSP、GB28181协议、以及厂家私有协议接入&#xff0c;可兼容市面上常…

MySQL 基础语法(2)

文章目录 创建表查看表修改表表数据插入 本文为表结构相关的基础语言库相关的基础语句 创建表 CREATE TABLE table_name ( field1 datatype comment xxx, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎;CREATE TABLE&#xff1…

算法竞赛相关问题总结记录

前言 日常在校生或者是工作之余的同学或多或少都会参加一些竞赛,参加竞赛一方面可以锻炼自己的理解与实践能力&#xff0c;也能够增加自己的生活费&#xff0c;竞赛中的一些方案也可以后续作为自己论文的base,甚至是横向课题的框架。在算法竞赛中算法的差别个人感觉差距都不大&…

创建一个空的maven项目,整合SpringBoot和Redis

创建一个空的maven项目&#xff0c;整合SpringBoot和Redis 创建空的maven项目 在最新版的idea中创建maven项目的时候会让选择模板 如下图&#xff1a; 我们选择quickstart快速开始模板&#xff0c;quickstart快速开始模板创建的maven项目里面什么都不带&#xff0c;只有一个…

便携式手提万兆网络协议测试仪

便携式手提万兆网络协议测试仪 平台简介 便携式手提万兆网络协议测试仪&#xff0c;以FPGA万兆卡和X86主板为基础&#xff0c;构建便携式的手提设备。 FPGA万兆卡是以Kintex-7XC7K325T PCIeX4的双路万兆光纤网络卡&#xff0c;支持万兆网络数据的收发和网络协议的定制设计。 …

微服务之.SpringCloud AlibabaSentinel实现熔断与限流

一、概述 1.1介绍 Sentinel是阿里巴巴开源的一款服务保护框架&#xff0c;目前已经加入SpringCloudAlibaba中。官方网站&#xff1a; 官网https://sentinelguard.io/zh-cn/ 从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开…

计算机服务器中了locked勒索病毒怎么办,locked勒索病毒解密工具流程步骤

随着网络技术的不断应用与发展&#xff0c;越来越多的企业离不开网络&#xff0c;网络大大提升了企业的办公效率水平&#xff0c;也为企业的带来快速发展&#xff0c;对于企业来说&#xff0c;网络数据安全成为了大家关心的主要话题。近日&#xff0c;云天数据恢复中心接到多家…

注意libaudioProcess.so和libdevice.a是不一样的,一个是动态链接,一个是静态

libaudioProcess.so是动态链接&#xff0c;修改需要改根文件系统&#xff0c;需要bsp重新配置 libdevice.a是静态链接&#xff0c;直接替换就行 动态链接文件修改 然后执行fw_update.sh

JAVA学习笔记29(集合)

1.集合 ​ *集合分为&#xff1a;单列集合、双列集合 ​ *Collection 接口有两个重要子接口 List Set&#xff0c;实现子类为单列集合 ​ *Map接口实现子类为双列集合&#xff0c;存放的King–Value ​ *集合体系图 1.1 Collection接口 1.接口实现类特点 1.collection实现…

射频识别技术助力产品分拣:提升效率与准确性

射频识别技术助力产品分拣&#xff1a;提升效率与准确性 RFID技术在产品分拣中具有重要的应用&#xff0c;它利用射频信号进行非接触式的自动识别&#xff0c;能够高效、准确地完成产品分拣工作。 在产品分拣中&#xff0c;RFID技术的主要应用方式是在产品上粘贴RFID电子标签&…

阿里云mysql8.0 this is incompatible withsql mode=only full group by

阿里云RDS中mysql5.6升级为8.0后&#xff0c;出现如下问题&#xff1a; ### Error querying database. Cause:java.sql.SQLSyntaxErrorException: Expression #1 of SELECT listis not in GROUP BY clause and contains nonaggregatedcolumn temp.product_id which is not fun…

电商平台数据有哪些(淘宝1688京东API)?如何进行电商平台数据分析?(内附测试方式)

电商平台数据是一个庞大且复杂的体系&#xff0c;涵盖了多个维度和类型。在淘宝、1688、京东等电商平台中&#xff0c;数据主要分为以下几个类别&#xff1a; 用户数据&#xff1a;包括用户属性&#xff08;如年龄、性别、地域、职业等&#xff09;、用户行为&#xff08;如浏…

本地环境测试

1. 在 Anaconda Navigator 中&#xff0c;打开 Jupyter Notebook &#xff0c;在网页中&#xff0c;点击进入本地环境搭建中创 建的工作目录&#xff0c;点击右上角的 New- 》 Folder &#xff0c;将新出现的 Untitled Folder 选中&#xff0c;并使用左上角 的 Rename 按钮重…

CSS基础常用属性之字体属性(如果想知道CSS的字体属性知识点,那么只看这一篇就足够了!)

前言&#xff1a;在我们学习CSS的时候&#xff0c;主要学习选择器和常用的属性&#xff0c;而这篇文章讲解的就是最基础的属性之一——文字属性。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 废话不多说&#xff0c;让我们直…

STP学习的第一篇

1.STP的基本概念&#xff1a;根桥 &#xff08;1&#xff09;STP的主要作用之一是在整个交换网络中计算出一棵无环的“树”&#xff08;STP树&#xff09;。 &#xff08;2&#xff09;根桥是一个STP交换网络中的“树根”。 &#xff08;3&#xff09;STP开始工作后&#xf…

Hack The Box-Runner

总体思路 子域名扫描->CVE-2023-42793利用->获取敏感信息->user->端口转发->CVE-2024-21626利用->root 信息收集&端口利用 nmap -sSVC 10.10.11.13目标开放22、80、8000端口&#xff0c;这里先将runner.htb加入到hosts文件后&#xff0c;访问之 查看源…

一文读懂链游!探索链游的前世今生,区块链与游戏结合的新兴趋势

区块链技术的崛起给游戏行业带来了前所未有的变革&#xff0c;而链游&#xff08;Blockchain Games&#xff09;正是这一变革的产物。本文将带您一览链游的前世今生&#xff0c;探索区块链与游戏结合的新兴趋势。 1. 链游的起源 链游&#xff0c;顾名思义&#xff0c;是指利用…

DAPP的商业模型创新: 探索可持续盈利路径

去中心化应用&#xff08;Decentralized Applications&#xff0c;DAPPs&#xff09;作为区块链技术的重要应用之一&#xff0c;在近年来蓬勃发展。然而&#xff0c;随着市场竞争的加剧和用户需求的不断变化&#xff0c;DAPP开发者们面临着寻找可持续盈利路径的挑战。本文将探讨…

STM32学习和实践笔记(16):STM32的中断一般配置步骤

STM32的中断配置步骤&#xff0c;通常都需经过这几步&#xff1a; &#xff08;1&#xff09;使能外设某个中断 方法就是调用这个外设的中断使能库函数来使能或者说打开它。 &#xff08;2&#xff09;设置中断优先级分组&#xff0c; 方法就是使用库函数 NVIC_PriorityGro…

Linux下kafka单机版搭建

1.zookeeper的安装 这里使用3.6.4版本 前提&#xff1a;服务器已经安装了jdk&#xff0c;zookeeper运行需要jdk环境 1.1创建放zookeeper的目录 #创建目录 mkdir -p /usr/local/zookeeper#赋予权限 chmod 777 /usr/local/zookeeper1.2安装包的下载 #这里推荐去官网下载 https:…