缓存并发问题
参考:https://blog.csdn.net/hijameschen/article/details/109382666
这里的并发指的是多个redis的client同时set key引起的并发问题。比较有效的解决方案就是把redis.set操作放在队列中使其串行化,必须的一个一个执行,具体的代码就不上了,当然加锁也是可以的
1,使用原子性的命令:incr,decr 2,使用锁:setnx设置锁,del释放锁
3,lua脚本
性能优化
参考:https://www.cnblogs.com/moonandstar08/p/7282108.html
1、尽量使用短的key 当然在精简的同时,不要为了key的“见名知意”。对于value有些也可精简,比如性别使用0、1。 2、避免使用keys * keys *, 这个命令是阻塞的,即操作执行期间,其它任何命令在你的实例中都无法执行。当redis中key数据量小时到无所谓,数据量大就很糟糕了。所以我们应该避免去使用这个命令。可以去使用SCAN,来代替。 3、在存到Redis之前先把你的数据压缩下 redis为每种数据类型都提供了两种内部编码方式,在不同的情况下redis会自动调整合适的编码方式。 4、设置key有效期 我们应该尽可能的利用key有效期。比如一些临时数据(短信校验码),过了有效期Redis就会自动为你清除! 5、选择回收策略(maxmemory-policy)
6、尽可能地使用hashes哈希存储
7、想要一次添加多条数据的时候可以使用管道 8、限制redis的内存大小(64位系统不限制内存,32位系统默认最多使用3GB内存)
9、SLOWLOG [get/reset/len]
慢查询分析
参考: https://www.cnblogs.com/williamjie/p/9660427.html
延迟时间
redis-cli --latency -h 127.0.0.1 -p 6379 //Redis的响应延迟时间以毫秒为单位,小于秒的时间都是已1000倍计数
慢日志
#命令
slowlog get 1) 1) (integer) 12849 #日志的唯一标识符 2) (integer) 1495630160 #被记录命令的执行时间点,以 UNIX 时间戳格式表示 3) (integer) 61916 #查询执行时间,以微秒为单位 4) 1) "KEYS" 2) "20170524less*"
slowlog len
slowlog reset
#配置项
config set slowlog-log-slower-than 10000 #超过10毫秒就记录
slowlog-max-len #慢日志最大条数
Pipeline管道
设置数据
$redis = new Redis(); //开启管道模式,代表将操作命令暂时放在管道里 $pipe = $redis->multi(Redis::PIPELINE); //循环遍历数据,执行操作 foreach ($users as $user_id => $username) { //用户名修改次数+1 $pipe->incr('changes:' . $user_id); // 更新用户名 $pipe->set('user:' . $user_id . ':username', $username); } //开始执行管道里所有命令 $pipe->exec();
获取数据
$redis = new Redis(); //开启管道模式 $pipe = $redis->multi(Redis::PIPELINE); //循环遍历数据,执行操作 foreach ($users as $user_id => $username) { // 用户被访问的次数+1 $pipe->incr('accessed:' . $user_id); // 获取用户数据记录 $pipe->get('user:' . $user_id); } // 开始执行管道里所有命令 $users = $pipe->exec(); // 打印数据 print_r($users);
注意,由于管道里每一条命令都会返回数据,所以最终打印的数组,会含有incr操作带来的记录,还有从获取用户操作那里拉下来的redis key值作为了打印数组的索引值。
取消管道
$pipe->discard();
reids6种淘汰策略:
主要配置项:
maxmemory #最大内存,将maxmemory设置为0,则表示不进行内存限制
maxmemory-policy #内存淘汰策略
达到最大内存限制时(maxmemory
), Redis 根据 maxmemory-policy
配置的策略, 来决定具体的行为。
noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。大多数写命令都会导致占用更多的内存(有极少数会例外。 **allkeys-lru:**所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。 **allkeys-random:**所有key通用; 随机删除一部分 key。#最不好的配置 volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。 **volatile-lru:**只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。 volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。
一般来说:
如果分为热数据与冷数据, 推荐使用 allkeys-lru 策略。 也就是, 其中一部分key经常被读写. 如果不确定具体的业务特征, 那么 allkeys-lru 是一个很好的选择。
如果需要循环读写所有的key, 或者各个key的访问频率差不多, 可以使用 allkeys-random 策略, 即读写所有元素的概率差不多。 假如要让 Redis 根据 TTL 来筛选需要删除的key, 请使用 volatile-ttl 策略。
volatile-lru 和 volatile-random 策略主要应用场景是: 既有缓存,又有持久key的实例中。 一般来说, 像这类场景, 应该使用两个单独的 Redis 实例。
值得一提的是, 设置 expire
会消耗额外的内存, 所以使用 allkeys-lru 策略, 可以更高效地利用内存, 因为这样就可以不再设置过期时间了。
Redis做异步队列
1,一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
缺点:在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。
2,**能不能生产一次消费多次呢?**使用pub/sub主题订阅者模式,可以实现1:N的消息队列。