开始之前,我们一起学习一下,社区其他小伙伴的文章:《Linux系统之iotop命令的基本使用》
文章名:《Linux系统之iotop命令的基本使用》 作者:江湖有缘
评价:
iotop是Linux下的实时磁盘I/O监控工具,类似于top,但专注于显示进程的磁盘读写情况。需root权限运行,通过命令行参数可定制显示内容和行为,有助于诊断磁盘I/O瓶颈。结合其他监控工具,提供全面的系统性能视图
我们简单回顾一下Redis性能的相关概念。
可以参考以下几篇文章:
深刻理解Redis集群(下):Redis 哨兵(Sentinel)模式
(1)启动程序后填写 Redis 服务器信息进行连接:
(2)连接后便可以对键和键值进行增删改查操作:
(3)Medis 还支持直接执行终端命令:
要开启Redis的慢查询日志功能,你需要修改Redis的配置文件(通常是redis.conf
),并进行以下配置:
修改redis.conf文件:
slowlog-log-slower-than
参数来设置命令执行时间的阈值(单位为微秒)。例如,设置为10000微秒(即10毫秒):slowlog-log-slower-than 10000
slowlog-max-len
参数来设置慢查询日志的最大条目数。例如,设置为128条:slowlog-max-len 128
maxmemory 21mb
maxmemory-policy allkeys-lru
在Redis的redis.conf文件里,maxmemory-policy
配置项用于设置当达到最大内存限制时,Redis如何选择要移除的数据。以下是各个淘汰策略的详细说明:
在redis.conf
文件中,你可以设置如下配置:
maxmemory-policy allkeys-lru
这表示当Redis达到最大内存限制时,将使用近似LRU算法淘汰任意键。
noeviction
,即不淘汰任何数据,当内存不足时返回错误。通过合理配置maxmemory-policy
,可以确保Redis在高负载情况下仍能稳定运行,并根据应用需求优化内存使用。
package com.bryant.controller.redis;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Random;
@RestController
@RequestMapping("/redis/performance")
public class PerformanceController {
@Resource(name = "userRedisTemplate")
private RedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient;
private static final int _1MB = 1024 * 1024;
private static final int _100MB = 1024 * 1024 * 100;
@PostMapping("/write2Cache")
public void write(
@RequestParam(value = "id", defaultValue = "0") int id,
@RequestParam(value = "isBigObject", defaultValue = "false") boolean isBigObject) {
for (int i = id; i < 100; i++) {
byte[] _1M = new byte[_100MB];
BigObject bigObject = new BigObject(_1M);
String key = "1M:" + i;
if (isBigObject) {
redisTemplate.opsForValue().set(key, bigObject);
} else {
redisTemplate.opsForValue().set(key, bigObject.toString());
}
}
}
@GetMapping("/readFromCache")
public void read() {
for (int i = 0; i < 100; i++) {
redisTemplate.opsForValue().get("1M:" + i);
}
}
}
class BigObject implements Serializable {
private static final long serialVersionUID = 589939600983368050L;
private byte[] a;
public BigObject(byte[] a) {
this.a = a;
}
public byte[] getA() {
return a;
}
public void setA(byte[] a) {
this.a = a;
}
}
(1)keys指令扫描容易引发性能问题
阻塞操作:
KEYS
命令是一个阻塞操作,它会阻塞 Redis 服务器直到命令执行完毕。这意味着在 KEYS
命令执行期间,Redis 无法处理其他客户端的请求,导致服务不可用时间复杂度:
KEYS
命令的时间复杂度是 O(N),其中 N 是数据库中的 key 数量。如果数据库中有大量的 key,KEYS
命令的执行时间会非常长。内存消耗:
KEYS
命令会将所有的 key 加载到内存中,这可能导致内存消耗过大,甚至引发内存溢出问题。(2)scan指令使用不当,也容易引发性能问题
SCAN
命令的基本语法如下:
SCAN cursor [MATCH pattern] [COUNT count]
cursor
:游标的初始值为 0,表示开始遍历。每次调用 SCAN
命令后,会返回一个新的游标值,用于下一次迭代。MATCH pattern
:可选参数,用于指定匹配的模式,类似于 KEYS
命令中的模式匹配功能。COUNT count
:可选参数,用于指定每次迭代返回的 key 的数量。这个值只是一个建议,实际返回的数量可能会有所不同。scan 命令 时间复杂度为 O(n)
理论上这个O(n) 很多的是靠 count来进行指定.
并且理论上一个键值对的消耗时间为 1 微秒左右.
虽然他可以在 count 值的微秒数之内返回,
但是如果要遍历所有的键值对, 并且多个client同时遍历
那么时间损耗是非常恐怖的.
又因为redis是单线程io复用的模型. 所以他会导致其他的核心业务卡断.
如果非必要建议不要使用scan命令, 在高并发,大量key的场景下性能表现并不好.
(3)对keys扫描优化
当使用到keys和scan,其本质就是对缓存的key进行遍历+操作(删除等),我们可以从下面几个方面入手:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。