百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

Redis实战经验大总结

wptr33 2024-12-31 15:03 34 浏览

1. key名设计

(1)【建议】: 可读性和可管理性

命令规范:以英文冒号分隔key,前缀概念的范围的返回从大到小,从不变到可变,从变化幅度小到变化幅度大。业务名:key用途:变量

例如:yoga:user:1,表示 yoga:user:{userID},即瑜伽子系统ID=1的用户信息

(2)【建议】:简洁性

保证语义的前提下,控制key的长度,不超64个字符。
当key较多时,内存占用也不容忽视,例如:

user:friends:messages:{mid} 简化为 u:fr:msg:{mid}

(3)【强制】:不要包含特殊字符

反例:包含空格、换行、单双引号以及其他转义字符

Redis 的 Key 一定要规范,这样在遇到问题时,能够进行方便的定位。Redis 属于无 scheme 的 KV 数据库,所以,我们靠约定来建立其 scheme 语义。其好处:

1、能够根据某类 key 进行数据清理

2、能够根据某类 key 进行数据更新

3、能够方面了解到某类 key 的归属方和应用场景

4、为统一化、平台化做准备,减少技术变更

2. value设计

(1)【强制】:拒绝bigkey

字符串类型:它的big体现在单个value值很大,一般认为超过10KB就是bigkey

非字符串类型:哈希、列表、集合、有序集合,它们的big体现在元素个数太多,元素个数不要超过5000

bigkey的危害

1、Redis集群的内存空间不均匀 由于Redis单线程的特性

2、操作bigkey的通常比较耗时,也就意味着阻塞Redis可能性越大

3、bigkey也就意味着每次获取要产生的网络流量较大,容易打满带宽

4、过期删除的时候会阻塞Redis

以下是压测结果,可直观看出bigkey对性能的影响:

(2)【推荐】:选择适合的数据类型

例如:实体类型(要合理控制和使用数据结构内存编码优化配置,例如ziplist,但也要注意节省内存和性能之间的平衡)

反例:

set user:1:name tom
set user:1:age 19
set user:1:favor football

正例:

hmset user:1 name tom age 19 favor football

(3)【强制】:控制key的生命周期,redis不是垃圾桶。

如果应用将Redis定位为缓存Cache使用,对于存放的Key一定要设置超时时间!因为若不设置,这些Key会一直占用内存不释放,造成极大的浪费,而且随着时间的推移会导致内存占用越来越大,直到达到服务器内存上限!另外Key的超时长短要根据业务综合评估,而不是越长越好!(某些业务要求key长期有效。可以在每次写入时,都设置超时时间,让超时时间顺延。)

Redis命令使用规范

1.【强制】严禁不设置范围的批量操作

  • 例如hgetall、lrange、smembers、zrange、sinter等并非不能使用,但是需要明确N的值,有遍历的需求可以使用hscan、sscan、zscan代替。
  • zrange、 zrangebyscore等多个操作 zset 的函数,严禁使用 zrange myzset 0 -1 等这种不设置范围的操作。请指定范围,如 zrange myzset 0 100,如不确定长度,可使用 zcard 判断长度。
  • hgetall会取出相关 hash 的所有数据,如果数据条数过大,同样会引起阻塞,请确保业务可控。如不确定长度,可使用 hlen 先判断长度。
  • 严禁使用 sunion, sinter, sdiff等一些聚合操作。

2.【强制】禁用 select 函数

select函数用来切换 database,对于使用方来说,这是很容易发生问题的地方,cluster 模式也不支持多个 database,且没有任何收益,dba已通过配置禁用。

3.【强制】禁用命令

禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。dba已通过配置禁用这些命令。

4.【强制】不推荐使用事务

Redis的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot上。

优化建议

1. 缩短键值对的存储长度

键值对的长度是和性能成反比的,比如我们来做一组写入数据的性能测试,执行结果如下:

不同key大小性能测试
从以上数据可以看出,在 key 不变的情况下,value 值越大操作效率越慢,因为 Redis 对于同一种数据类型会使用不同的内部编码进行存储,比如字符串的内部编码就有三种:int(整数编码)、raw(优化内存分配的字符串编码)、embstr(动态字符串编码),这是因为 Redis 的作者是想通过不同编码实现效率和空间的平衡,然而数据量越大使用的内部编码就越复杂,而越是复杂的内部编码存储的性能就越低。

2. 冷热数据分离

不要将所有数据全部都放到Redis中,建议根据业务只将高频热数据存储到Redis中【QPS大于5000】,重要性级别较低的但却需求容量较大的场景可申请完全兼容Redis操作的Pika,对于低频冷数据可以使用MySQL/ElasticSearch等基于磁盘的存储方式。

3. 业务数据分离

不要将不相关的数据业务都放到一个 Redis中。一方面避免业务相互影响,另一方面避免单实例膨胀,并能在故障时降低影响面,快速恢复。

4. 大文本数据要压缩

对于大文本【超过500 byte】写入到Redis时,一定要压缩后存储!大文本数据存入Redis,除了带来极大的内存占用外,在访问量高时,很容易就会将网卡流量占满,进而造成整个服务器上的所有服务不可用,并引发雪崩效应,造成各个系统瘫痪。

5. 使用连接池

使用带有连接池的客户端,可以有效控制连接,同时提高效率

6. 缓存 Key 设置失效时间的建议

如果在大型系统中有大量缓存在同一时间同时过期,那么会导致 Redis 循环多次持续扫描删除过期字典,直到过期字典中过期键值被删除的比较稀疏为止,而在整个执行过程会导致 Redis 的读写出现明显的卡顿,卡顿的另一种原因是内存管理器需要频繁回收内存页,因此也会消耗一定的 CPU。

为了避免这种卡顿现象的产生,我们需要预防大量的缓存在同一时刻一起过期,就简单的解决方案就是在过期时间的基础上添加一个指定范围的随机数。

7. 限制Redis 分片大小

乐信标准,Redis都有分片,最少一个分片,单分片的大小是4G ,为何不建议一直往上加内存?

  • 单台服务器内存资源有限,不利于扩展
  • 单个分片内存过大,服务器出故障时,影响面大
  • Redis持久化时,虽然操作是异步化,但会有fork进程的操作,这一步是由主进程来完成的,分片内存越大,页表就越大,fork执行时间就越长,就会给主线程带来阻塞风险
  • 不利于平台标准化,后期迁移困难
  • Redis是单进程模型,只能利用一个CPU核心,多分片有利于提高Redis集群能力,充分利用多核性能。

8. 认真对待最大内存淘汰策略

根据自身业务类型选择好最大内存淘汰策略,可保证有用数据不被删除,也可避免Redis实例出现OOM,让Redis持续高效。

  • noeviction:不淘汰任何数据,当内存不足时,新增操作会报错,Redis 默认内存淘汰策略
  • allkeys-lru:淘汰整个键值中最久未使用的键值
  • allkeys-random:随机淘汰任意键值
  • volatile-lru:淘汰所有设置了过期时间的键值中最久未使用的键值(乐信默认)
  • volatile-random:随机淘汰设置了过期时间的任意键值
  • volatile-ttl:优先淘汰更早过期的键值

在 Redis 4.0 版本中又新增了 2 种淘汰策略:

  • volatile-lfu:淘汰所有设置了过期时间的键值中,最少使用的键值
  • allkeys-lfu:淘汰整个键值中最少使用的键值

相关推荐

一篇文章带你了解PHP的学习使用(php的教程)

ThinkPHP5实战...

在memcached管理php的session(memcached libevent)

PHP的session(会话管理)一般是以文件形式进行,而在多个Web服务器之间进行session管理时memecached会比文件管理方式更加方便。在这里介绍如何使用memcached管理PHP的s...

php传值和传引用的区别(php 传值和传引用)

php传值:在函数范围内,改变变量值得大小,都不会影响到函数外边的变量值。PHP传引用:在函数范围内,对值的任何改变,在函数外部也有所体现,因为传引用传的是内存地址。传值:和copy是一样的。【打个比...

PHP 常量详解教程(php常量和变量)

常量类似变量,但是常量一旦被定义就无法更改或撤销定义。PHP常量常量是单个值的标识符(名称)。在脚本中无法改变该值。有效的常量名以字符或下划线开头(常量名称前面没有$符号)。注释:与变量不同,常...

php自学零基础入门小知识(php新手入门教程)

我们就把PHP入门当成一个苹果吧!一口一口的吃掉他!不啰嗦了!开始了1、嵌入方法:类似ASP的<%,PHP可以是<?php或者是<?,结束符号是?>,当然您也可以自己指定。2、...

PHP 语法详解(php语法大全)

PHP脚本在服务器上执行,然后向浏览器发送回纯HTML结果。基础PHP语法PHP脚本可放置于文档中的任何位置。PHP脚本以<?php开头,以?>结尾:<?php...

PHP笔记(一)PHP基础知识(php必背知识点)

创建PHP程序PHP代码框架<?php>2.文件命名规则...

PHP 8新特性之Attributes(注解),你掌握了吗?

PHP8的Alpha版本,过几天就要发布了,其中包含了不少的新特性,当然我自己认为最重要的还是JIT,这个我从2013年开始参与,中间挫折无数,失败无数后,终于要发布的东东。不过,今天呢,我不打算谈J...

PHP基本语法之标记与注释(php注释规范)

1、标记由于PHP是嵌入式脚本语言,它在实际开发中经常会与HTML内容混在一起,所以为了区分HTML与PHP代码,需要使用标记对PHP代码进行标识。如:<html>...

php注解(PHP注解 性能)

目标了解和使用php注解,如果你已经掌握其他一种具有注解的语言,例如:java、python等,你在本文中只需要了解点语法就行。示例php8以前的版本,注解写在注释里,如果你掌握其他语言的注解,你是不...

数据丢失?别慌!MySQL备份恢复攻略

想象一下,某个晴朗的午后,你正享受着咖啡,突然接到紧急电话:你的网站或APP彻底挂了!系统崩溃,界面全白。虽然心头一紧,但你或许还能安慰自己:系统崩溃只是暂停服务,数据还在,修复修复就好了。然而,如果...

MySQL 日志:undo log、redo log、binlog

今天来和大家分享MySQL的三个日志文件,可以说MySQL的多数特性都是围绕日志文件实现,而其中最重要的有以下三种:...

MySQL三大日志:binlog、redolog、undolog全解析

binlog概述在MySQL数据库中,binlog可是个相当重要的存在,它的全称为binarylog,也就是二进制日志。它就像是数据库的“记忆本”,记录了所有的DDL(数据定义语言)和...

1、MySQL数据库介绍(mysql数据库简单介绍)

1.1数据库的核心定义数据库的本质数据库乃存储数据对象之容器,涵盖如下关键组件:表(Table)...

MySQL 日志双雄:实时监控与历史归档实战优化

MySQL日志双雄:实时监控+历史归档实战用这招让你家日志系统再也不卡不爆炸MySQL十亿级日志处理:从洪峰到归档全攻略手把手教你用MySQL搞定ELK级日志监控在微服务架构大行其道的今天,日志系统早...