一. 问题场景

Redis 作为当前最流行的内存型 NoSQL 数据库,被许多公司所使用,作为分布式缓存。我们在实际使用中一般都会为 key 带上指定的前缀或者其他定义的格式。当由于我们程序出现bug,造成 redis 里面的存储的值,与我们预期的不一致时,我们可以通过查询指定格式的 key,来定位到我们具体的出现问题的key,从而方便我们解决问题。

二. 解决办法

1.Keys 命令

Keys 命令用于查找所有符合给定模式 pattern 的 key 。要求 Redis 版本大于 1.0.0。keys在查询大数量key时,会长时间阻塞Redis,由于Redis是单线程的,这就是一个突出的问题,需要注意。

2.Scan 命令

Scan 命令相对于 Keys 命令来说,优点就是不会阻塞服务器。要求 Redis 版本大于 2.8。

三. 代码实现

这里采用的Redis驱动是 StackExchange.Redis。

在 StackExchange.Redis 里封装 Redis 命令时分为了两种,一种是针对于集群的命令,一种是针对于单个Redis服务器的命令,Keys 和 Scan 命令便是后者,我们在使用的时候必须在单独的服务器上执行。

Keys 和 Scan 命令都支持模糊查询,这里介绍三种匹配符:

  1. * 表示可以匹配 多个 任意字符
  2. ? 表示可以匹配 单个 任意字符
  3. [] 表示可以匹配 指定范围 内的字符

因为我们的key可能分布在集群内多个Redis服务器上,所以我们需要在每台服务器上都执行命令。我们可以通过 ConnectionMultiplexer.GetEndPoints() 方法来获取所有的终结点信息。

在 StackExchange.Redis 对于 keys 和 scan 命令统一封装为了 IServer.Keys()方法,它会自动根据Redis服务器版本来决定使用keys命令还是scan命令。

为了方便测试,我在 Redis 里面准备了四个以 test 为前缀的key,放在序号为1的db里面:

1.遍历所有前缀为 test 的key 代码如下:

static async Task Main(string[] args){ //创建连接 var conn = await ConnectionMultiplexer.ConnectAsync("192.168.10.110"); //获取db var db = conn.GetDatabase(1); //遍历集群内服务器 foreach (var endPoint in conn.GetEndPoints()) { //获取指定服务器 var server = conn.GetServer(endPoint); //在指定服务器上使用 keys 或者 scan 命令来遍历key foreach (var key in server.Keys(1,"test.*")) { //获取key对于的值 var val = db.StringGet(key); Console.WriteLine($"key: {key}, value: {val}"); } }}

执行结果:

2.[]的用法

假设我要遍历 key为 test.1-test.3 的数据,可以这样写:

static async Task Main(string[] args){ //创建连接 var conn = await ConnectionMultiplexer.ConnectAsync("192.168.10.110"); //获取db var db = conn.GetDatabase(1); //遍历集群内服务器 foreach (var endPoint in conn.GetEndPoints()) { //获取指定服务器 var server = conn.GetServer(endPoint); //在指定服务器上使用 keys 或者 scan 命令来遍历key foreach (var key in server.Keys(1,"test.[1-3]")) { //获取key对于的值 var val = db.StringGet(key); Console.WriteLine($"key: {key}, value: {val}"); } }}

执行结果:

假设我要遍历 key为 test.1和test.4 的数据,可以这样写:

static async Task Main(string[] args){ //创建连接 var conn = await ConnectionMultiplexer.ConnectAsync("192.168.10.110"); //获取db var db = conn.GetDatabase(1); //遍历集群内服务器 foreach (var endPoint in conn.GetEndPoints()) { //获取指定服务器 var server = conn.GetServer(endPoint); //在指定服务器上使用 keys 或者 scan 命令来遍历key foreach (var key in server.Keys(1,"test.[1,4]")) { //获取key对于的值 var val = db.StringGet(key); Console.WriteLine($"key: {key}, value: {val}"); } }}

执行结果:

好了,关于 Redis 查询指定格式的 key 的方法就介绍到这里了

一. 问题场景Redis 作为当前最流行的内存型 NoSQL 数据库,被许多公司所使用,作为分布式缓存。我们在实际使用中一般都会为 key 带上指定的前缀或者其他定义的格式。当由于我们程序出现bug,造成 redis 里面的存储的值,与我们预期的不一致时,我们可以通过查询指定格式的 key,来定位到我们具体的出现问题的key,从而方便我们解决问题。二. 解决办法1.Keys 命令Keys 命令用于... .net core 出来有一时间了,这段时间也一直在做技术准备,目前想做一个单点登录(SSO)系统,在这之前用 .net 时我用习惯了machine Key ,也顺手在 .net core 中尝试了一上,结果发现不好使了,也不起作用,于是开始了网上学习。 实现 方法   功夫不负有心人,网上高人还是多,在github.com上面ISSUES中也有人在讨论此问题,于是找到代码尝试,结果 实现 了。   直接上代码,我们需要先封装一个XmlRepository, Key 格式 如下: <?xml version=1.0 encoding=utf-8?> < key id=cbb8a41a-9c
查找符合某个条件比如 前缀 为cart_的 key ,这里我预先插入了一万条数据,在正式开始之前先说一下 key s 指令的匹配规则: key s pattern里面有3个通配符 分别是 *,?,[] *:通配多个任意字符 ?:通配单个字符 []:通配数组内的某个字符 这些通配都可以组合使用,比如我插入了四个键 List key s = new ArrayList<>(); //初始 key s List list = this. redis Template.opsForValue().multiGet( key s); 2、利用PipeLine final List key s = new ArrayListList list = this. redis Template.executePipel
redis -cli -p 26379 -a 123456 -n 0 key s g.at.ga.* > a.txt 2. 拼出取value的 命令 sed 's/^/get &/g' a.txt > b.txt 3. 取value cat b.txt | redis -cli -p...... //模糊匹配 redis key Set<String> key s = string Redis Template. key s("*" + Redis Key Utils.getAllCacheCircleUser Key (userId.toString()) + "*"); 2. 根据 key 批量 获取 hash value * 批量 获取 hash Key value * @param key s * @return 一、 获取 方式 redis 命令 key s(*) 可以 获取 所有的 key 。但是此种方式当数据量大的时候,会产生阻塞的情况。 redis key 还可以通过scan 命令 获取 key 。scan采用渐进式遍历的方式来解决 key s 命令 可能带来的阻塞问题 与SCAN 命令 相关的 命令 :  与SCAN 命令 相关的 命令 还有 SSCAN 命令 、 HSCAN 命令 和 ZSCAN 命令 ,都是用于增量地迭代(incrementally iterate)一集元素(a collection of elements
redis 用scan代替 key s 众所周知,当 redis key 数量越大, key s 命令 执行越慢,而且最重要的会阻塞服务器,对单线程的 redis 来说,简直是灾难,且在生产环境, key s 命令 一般是被禁止的。scan可用来替换 key s请求。 # scan用法 SCAN cursor [MATCH pattern] [COUNT count] scan是一个增量迭代式的 命令 ,这意味着每次调用这个 命令 都会返回一个游标cursor,该游标用于下次 查询 查询 开始时,cursor值为0;当 查询 结束时,cursor的值也
redis 作为我们接口开发中的首选缓存,当从 redis 中每次 获取 一个 key 的value时,接口响应时间上一般是没啥问题的,但是当需要 获取 多个 key 的value时,一般需要使用mget等 批量 获取 的方法。但是当value是以压缩 格式 写入到 redis 中的时候,还可以直接套用原来的方法吗?最近在一个接口的开发过程中遇到了这个问题,特此记录下解决方法。 先复习下 redis 、jedis和 redis Template之间的关系: Redis 是用ANSI C写的一个基于内存的 Key -Value数据库,而Jedis是R
redis 队列的 批量 获取 一直以来让我很困惑,今天又遇到了同样的问题,经过几番波折,终于找到了一个方法。分享一下 只需要 redis 自带的两个方法(lrange, ltrim) lrange可以 获取 队列中某一段的数据,例如 获取 队列中1-10的数据,lrange key 1 10 ltrim  可以保留所选区间的所有值,也就是可以 删除 所选区间之外的所有值, 例如 ltrim key 5 10 就会...
```java import org.springframework.data. redis . core . Redis Template; import org.springframework.stereotype.Service; import java.util.List; @Service public class MovieRankService { private final Redis Template<String, Integer> redis Template; private static final String REDIS _ KEY = "MOVIE_RANK"; public MovieRankService( Redis Template<String, Integer> redis Template) { this. redis Template = redis Template; public void addMovie(Integer movieId) { redis Template.opsForZSet().incrementS core ( REDIS _ KEY , movieId, 1); public List<Integer> getTopMovies(int n) { return redis Template.opsForZSet().reverseRange( REDIS _ KEY , 0, n - 1); 在这个示例中,我们使用了 Redis 的有序集合数据结构来 实现 排行榜功能。排行榜中每个电影对应的分数即为它的热度值,每次添加电影时我们通过incrementS core 方法自增1分数值。使用reverseRange方法可以 获取 到前n个分数最高的电影id,这里我们直接返回了id列表。 如果需要更加复杂的排行榜或者拓展,可以根据实际场景进行调整和扩展。