美文网首页
redis常见问题

redis常见问题

作者: hirolin | 来源:发表于2018-07-15 23:23 被阅读0次

1.redis数据结构

redis数据结构

redis五种数据结构
String
Hash 优点由于Hash结构会在单个Hash元素在不足一定数量时进行压缩存储,所以可以大量节约内存(HashMap)。
List 链表
Set 集合,一堆不重复值的组合,求交集并集(HashSet创建了HashMap,HashMap中keySet来遍历set集合)。
Sorted Set 有序集合,增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列。

2.key太多,使用keys可能会导致线程阻塞(通过slowlog get [num] 查询慢查询操作)

当redis中key的数量过多时,由于redis是单线程的。keys指令会导致线程阻塞,线上涉及redis的服务会停止,直到指令执行完服务才正常。故在生产环境慎用keys!!!!!

keys activity*
 1)  "activity-10"
 2)  "activity-6"
 3)  "activity-7"
 4)  "activity-8"
 5)  "activity-4"
 6)  "activity-1"
 7)  "activity-11"
 8)  "activity-9"
 9)  "activity-5"
 10)  "activity-2"
 11)  "activity-13"
 12)  "activity-3"
 13)  "activity-14"
 14)  "activity-12"

如果有这样的场景需要模糊查询keys的数量可以使用scan。scan指令可以无阻塞的提取出指定模式的key列表(对应的其他数据结构有对应的SSCAN 命令、 HSCAN 命令和 ZSCAN 命令,第一个参数总是一个数据库键)。

SCAN 命令的回复是一个包含两个元素的数组, 第一个数组元素是用于进行下一次迭代的新游标, 而第二个数组元素则是一个数组, 这个数组中包含了所有被迭代的元素。

scan 0 match activity* count 100
 1)  "0"
 2)    1)   "activity-10"
  2)   "activity-6"
  3)   "activity-7"
  4)   "activity-8"
  5)   "activity-13"
  6)   "activity-14"
  7)   "activity-12"
  8)   "activity-4"
  9)   "activity-1"
  10)   "activity-5"
  11)   "activity-2"
  12)   "activity-3"
  13)   "activity-11"
  14)   "activity-9"

可以根据返回的新游标进行遍历,当下标为0时,说明迭代结束。

scan 0 match activity* count 10
 1)  "14"
 2)    1)   "activity-10"
  2)   "activity-6"
  3)   "activity-7"
  4)   "activity-8"
  5)   "activity-13"
  6)   "activity-14"
  7)   "activity-12"
  8)   "activity-4"
  9)   "activity-1"
  10)   "activity-5"
  11)   "activity-2"

scan 14 match activity* count 10
 1)  "0"
 2)    1)   "activity-3"
  2)   "activity-11"
  3)   "activity-9"

3.setnx 注意事项

setnx是redis设置锁常用的方式,但有几个事项需要注意以下:

1.SetNX 不具备设置过期时间的功能,所以需借助 Expire 来设置。

local:0>setnx "activity_test" 1
"1"
local:0>expire "activity_test" 10
"1"

2.setnx成功,expire失败。可以通过multi/exec实现原子性,但是多个请求若没有加判断,setnx失败,但是expire会成功,那么会一直刷新expire时间。使用set参数的方式实现就可以解决这些问题。

local:0>set "activity_test" "test" nx ex 10
"OK"
local:0>get "activity_test"
"test"

4. multi or pipeline ?

multi 事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行, 。
pipeline 将所有命令打包一次性发送。一次性批量执行所有命令,成功后再一次性返回所有处理结果,无法保证一致性。

local:0>multi
"OK"
local:0>set "activity_test_01" 1
"QUEUED"
local:0>set "activity_test_02" 2
"QUEUED"
local:0>exec
 1)  "OK"
 2)  "OK"

可以看到multi情况下,每个步骤客户端都收到服务端“QUEUED”的返回,redis服务端会把事务中命令保存到服务端内存中。
需要注意两点:
1.multi指令在执行时,配合watch能实现对key的监控,如果该key在执行过程中被修改,则该事务整个都会被取消;
2.如果只有multi,事务中有某条/某些命令执行失败了, 事务队列中的其他命令仍然会继续执行,Redis不会停止执行事务中的命令。

$redis->multi(Redis::PIPELINE);
$redis->sAdd($key1 , 1);//1
$redis->sAdd($key1 , 2);//2
$redis->exec();

pipeline客户端将命令写入缓冲,最后再通过exec命令发送给服务端。
需要注意两点:
1.pipeline如果指令数过大可能会造成网络阻塞,并且服务器将被迫回复一个队列答复,占用很多内存。所以,如果在需要发送大量的命令,最好是把他们按照合理数量分批次的处理。至于合适的数量一般在100-1000(搜索出来的,待证实)。
2.pipeline有某条/某些命令执行失败了,其他指令仍然执行。
所以pipeline选择客户端缓冲,multi选择服务端缓冲。multi每个命令都发送给服务端,pipeline一次性发送给服务端。根据业务场景选择合适方式。

5. redis 的hgetall获取的数据是有序的吗?

首先看一个例子:

$key2 = 'activity_h_test_06';
for ($index = 0; $index < 512; $index ++) {
    $redis->hSet($key2, 'key' . $index, $index);
}
var_dump($redis->hGetAll($key2));
var_dump('length : ' . $redis->hLen($key2));

部分结果:
  ["key506"]=>
  string(3) "506"
  ["key507"]=>
  string(3) "507"
  ["key508"]=>
  string(3) "508"
  ["key509"]=>
  string(3) "509"
  ["key510"]=>
  string(3) "510"
  ["key511"]=>
  string(3) "511"
}
string(12) "length : 512"

key2插入了512个hashkey,可以看到返回数据是按照插入顺序返回。
当数量超过512个hashkey呢,看下一个例子:

$key2 = 'activity_h_test_07';
for ($index = 0; $index < 513; $index ++) {
    $redis->hSet($key2, 'key' . $index, $index);
}
var_dump($redis->hGetAll($key2));
var_dump('length : ' . $redis->hLen($key2));

部分结果:
  ["key330"]=>
  string(3) "330"
  ["key349"]=>
  string(3) "349"
  ["key202"]=>
  string(3) "202"
  ["key316"]=>
  string(3) "316"
  ["key117"]=>
  string(3) "117"
  ["key499"]=>
  string(3) "499"
  ["key512"]=>
  string(3) "512"
}
string(12) "length : 513"

可以看到当数量超过512个,返回的数据会编程无序的。为什么会造成这个现象呢,来大致看一下redis的源码:

int hashTypeSet(robj *o, sds field, sds value, int flags) {
    ....
    if (hashTypeLength(o) > server.hash_max_ziplist_entries)
            hashTypeConvert(o, OBJ_ENCODING_HT);
    ....
}

void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {
    .....
    for (i = start; i <= end; i++) {
        if (sdsEncodedObject(argv[i]) &&
            sdslen(argv[i]->ptr) > server.hash_max_ziplist_value)
        {
            hashTypeConvert(o, OBJ_ENCODING_HT);
            break;
        }
        .....
}

#define OBJ_HASH_MAX_ZIPLIST_ENTRIES 512
#define OBJ_HASH_MAX_ZIPLIST_VALUE 64

server.hash_max_ziplist_value
server.hash_max_ziplist_entries 可以通过server配置文件修改

可以看到当hash键值长度小于64字节或数量小于512个时,还是使用ziplist存储,而ziplist是一个经过特殊编码的双向链表,所以能保证有序。当不满足时会转化成hash存储。(ziplist详解
所以当业务场景中需要保证有序时,可以使用redis列表或者有序集合。

相关文章

  • 八、Linux(CentOS7)安装Redis

    安装Redis的操作步骤: 常见问题:1、redis不能远程连接时,可能是防火墙的问题:

  • Spring Cache相关

    SpringCache官方文档 常见问题使用redis作为存储cache,@CacheConfig:cacheNa...

  • mac下安装配置redis

    一准备工作二 安装redis服务器三redis服务器的启动、使用和退出四 配置php使用redis服务五 常见问题...

  • Redis 安装和集群环境搭建

    Redis 的安装部署非常简单,本文将按照 Redis 下载、单节点安装部署、集群环境搭建和常见问题解决几个部分加...

  • Redis 面试常见问题

    Redis常见问题 为什么使用Redis性能和并发(分布式锁还有其他中间件可以代替)性能需要执行耗时特别久,且结果...

  • Redis总结

    一、数据类型 二、使用场景 二、redis缓存使用总结 三、redis缓存常见问题 四、布隆过滤器的方式解决缓存穿透问题

  • redis常见题目

    redis 分布式锁常见问题 注意:redis的单个指令是原子性,但是多个指令就不能保证原子性了。这个时候如果要保...

  • 《Redis实战》

    阅读本书可以让你学到很多小技巧、小窍门以及使用Redis解决某些常见问题的方法。 redis五大数据类型 stri...

  • redis常见问题

    1.redis数据结构 redis五种数据结构StringHash 优点由于Hash结构会在单个Hash元素在不足...

  • Redis——常见问题

    fork操作 一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相...

网友评论

      本文标题:redis常见问题

      本文链接:https://www.haomeiwen.com/subject/zpfppftx.html