目录
什么是Redis
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API
key的类型:是字符串 value的类型
Redis的数据类型
常用的:string字符串类型、list列表类型、set集合类型、sortedset(zset)有序集合类型、hash类型。
不常用的:bitmap位图类型、geo地理位置类型。 Redis5.0新增一种:stream类型
注意:Redis中命令是忽略大小写(set SET),key是不忽略大小写的 (NAME name)
key值的设计建议: 见名知义
1. 用:分割 2. 把表名转换为key前缀, 比如: user: 3. 第二段放置主键值 4. 第三段放置列名
例如:username 的 key: user:9:username
Redis 优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
Redis的使用场景
- 热点数据的缓存
- 限时业务的运用
- redis中可以使用expire命令设置一个键的生存时间,到时间后redis会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景。
- 计数器相关问题
- redis由于incrby命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成
- 具体业务还体现在比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等
- 分布式锁
- 利用redis的setnx命令进行,setnx:"set if not exists"就是如果不存在则成功设置缓存同时返回1,否则返回0
- 在分布式锁的场景中,主要用在比如秒杀系统等
- 延时操作
- 例如在订单生成后我们占用了库存,10分钟后去检验用户是否真正购买,如果没有购买将该单据设置无效,同时还原库存。
- 我们在订单生产时,设置一个key,同时设置10分钟后过期, 我们在后台实现一个监听器,监听key的实效,监听到key失效时将后续逻辑加上。
- 排行榜相关问题
- 关系型数据库在排行榜方面查询速度普遍偏慢,所以可以借助redis的SortedSet进行热点数据的排序
- 等等等多种场景
Redis测试工具
redis-benchmark是一个压力测试工具!官方自带的性能测试工具!
参考文档:https://www.runoob.com/redis/redis-tutorial.htm
Redis 数据类型
它支持多种类型的数据结构,
常用:如字符串(String),散列(Hash),列表(List),集合(Set),有序集合(Sorted Set或者是ZSet)
不常用:范围查询,Bitmaps,Hyperloglogs 和地理空间(Geospatial)索引半径查询。
Redis 字符串命令(String)
一个键最大的存储容量为512Mb
String类型是二进制安全的,意思是 redis 的 string 可以包含任何数据。如数字,字符串,jpg图片或者序列化的对象。
常用命令:
1 | SET key value 设置指定 key 的值 |
2 | GET key 获取指定 key 的值。 |
3 | INCR key 将 key 中储存的数字值增一 |
4 | DECR key 将 key 中储存的数字值减一 |
5 | SETNX key value set if not exist 如果不存在该key时设置值 已存在该key 设置失败 返回 0 不存在该key 设置成功 返回1 |
6 | APPEND key value 如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾。 如果key之前不存在 则 设置该key并赋值 |
应用场景:
- 缓存 经典使用场景,把常用信息,字符串,图片或者视频等信息放到redis中,redis作为缓存层,mysql做持久化层,降低mysql的读写压力。
- 计数器 redis是单线程模型,一个命令执行完才会执行下一个,同时数据可以一步落地到其他的数据源。
- session 常见方案spring session + redis实现session共享,
Redis 列表(List)
Redis用双向链表实现List ,按照插入顺序排序,因此无论是操作头或尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了
按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边);底层的数据结构为双向链表
常用命令:
1 | LPUSH key value1 [value2] 将一个或多个值插入到列表头部 left push 在左边加入值 |
2 | RPUSH key value1 [value2] 在列表中添加一个或多个值 right push 在右边加入值 |
3 | LRANGE key start stop 获取列表指定范围内的元素, -1表示最后一位,例如 查看list1的全部元素 LRANGE list1 0 -1 lrange key start stop 查看元素 |
4 | LPOP key 移出并获取列表的第一个元素 移除左边的值 |
5 | RPOP key 移除列表的最后一个元素,返回值为移除的元素。 移除右边的值 |
6 | LINDEX key index 通过索引获取列表中的元素 |
应用场景:
- 使用List结构,我们可以轻松地实现最新消息排队功能(比如新浪微博的TimeLine)。
- List的另一个应用就是消息队列,可以利用List的 PUSH 操作,将任务存放在List中,然后工作线程再用 POP 操作将任务取出进行执行
- 使用列表的技巧
- lpush+lpop=Stack(栈)
- lpush+rpop=Queue(队列)
- lpush+ltrim=Capped Collection(有限集合)
- lpush+brpop=Message Queue(消息队列)
Redis 集合(Set)
特征 不存在重复的元素 底层的数据结构为 hash 表 所以添加,删除,查找的复杂度都是 O(1)。
常用命令:
1 | SADD key member1 [member2] 向集合添加一个或多个成员 ,例如 sadd set01 1 1 1 2 2 2 3 3 3 3 4 4 4 输出插入成功个数 4 不能包含重复元素 |
2 | SMEMBERS key 返回集合中的所有成员, 例如: smembers set01 输出 1 2 3 4 |
3 | SISMEMBER key member 判断 member 元素是否是集合 key 的成员 例如 s is member set01 4 输出 1 (存在输出1) 不存在输出 0 |
4 | SCARD key 获取集合的成员数 ,例如 scard set01 输出 3 返回该key对应value的个数 |
实战场景
- 标签 tag),给用户添加标签,或者用户给消息添加标签,这样有同一标签或者类似标签的可以给推荐关注的事或者关注的人。
- 点赞,或点踩,收藏等 可以放到set中实现
Redis 哈希(Hash)
Redis hash 是一个 string 类型的 field(字段) 和 value(值) 的映射表,hash 特别适合用于存储对象。 注意:value 是一个键值对
1 | HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。 |
2 | HGET key field 获取存储在哈希表中指定字段的值。 |
3 | HDEL key field1 [field2] 删除一个或多个哈希表字段 |
4 | HMGET key field1 [field2] 获取所有给定字段的值 |
5 | HGETALL key 获取在哈希表中指定 key 的所有字段和值 |
实战场景
- 缓存 更直观,相比string更节省空间的维护缓存信息,如用户信息,视频信息等。
Redis Zset有序集合
Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的, 但分数(score)却可以重复。有序集合是通过两种数据结构实现:
-
压缩列表(ziplist)
zip list是为了提高存储效率而设计的一种特殊编码的双向链表。
它可以存储字符串或者整数,存储整数时是采用整数的二进制而不是字符串形式存储。它能在O(1)的时间复杂度下完成list两端的push和pop操作。
但是因为每次操作都需要重新分配ziplist的内存,所以实际复杂度和ziplist的内存使用量相关
-
跳跃表(zSkiplist)
跳跃表的性能可以保证在查找,删除,添加等操作的时候在对数期望时间内完成,
这个性能是可以和平衡树来相比较的,而且在实现方面比平衡树要优雅,这是采用跳跃表的主要原因。跳跃表的复杂度是O(log(n))。
常用命令
1 | ZADD | 将一个带有给定分值的成员添加到有序集合里面 | ZADD zset-key 178 member1 |
2 | ZRANGE | 根据元素在有序集合中所处的位置,从有序集合中获取多个元素 | ZRANGE zset-key 0-1 withccores |
3 | ZREM | 如果给定元素成员存在于有序集合中,那么就移除这个元素 | ZREM zset-key member1 |
实战场景
- 排行榜 有序集合经典使用场景:例如小说视频等网站需要对用户上传的小说视频做排行榜,榜单可以按照用户关注数,更新时间,字数等打分,做排行。
Redis HyperLogLog
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。
这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
什么是基数?
举个例子,A = {1, 2, 3, 4, 5}, B = {3, 5, 6, 7, 9};那么基数(不重复的元素)= 1, 2, 4, 6, 7, 9;。 基数估计就是在误差可接受的范围内,快速计算基数。
1 | PFADD key element [element ...] 添加指定元素到 HyperLogLog 中。 |
2 | PFCOUNT key [key ...] 返回给定 HyperLogLog 的基数估算值。 |
3 | PFMERGE destkey sourcekey [sourcekey ...] 将多个 HyperLogLog 合并为一个 HyperLogLog |
HyperLogLogs 基数统计用来解决什么问题?
这个结构可以非常省内存的去统计各种计数,比如注册 IP 数、每日访问 IP 数、页面实时UV、在线用户数,共同好友数等。
Redis Bitmap (位存储)
Bitmap 即位图数据结构,都是操作二进制位来进行记录,只有0 和 1 两个状态。
比如:统计用户信息,活跃,不活跃! 登录,未登录! 打卡,不打卡! 两个状态的,都可以使用 Bitmaps!
如果存储一年的打卡状态需要多少内存呢? 365 天 = 365 bit 1字节 = 8bit 46 个字节左右!
Redis geo (地理位置)
Redis 的 Geo 在 Redis 3.2 版本就推出了! 这个功能可以推算地理位置的信息: 两地之间的距离, 方圆几里的人
更推荐使用ES实现地理位置
基础知识
1 | config get databasesconfig | 通过配置文件查看默认数据库个数 输出16 |
2 | dbsize | 查看数据库大小 (数据库中存在多少个key) |
3 | select 数据库 index | 切换数据库 默认为0号 |
4 | flushall | 清空所以数据库 |
5 | flushdb | 清空当前库 |
key 常用的命令
1 | DEL key 删除 key |
2 | EXISTS key 检查给定 key 是否存在 |
3 | EXPIRE key seconds 为给定 key 设置过期时间,以秒计 |
4 | PEXPIRE key milliseconds 设置 key 的过期时间以毫秒计 |
5 | KEYS pattern 查找所有符合给定模式( pattern)的 key keys * 查询当前库中所有的键 |
6 | MOVE key db 将当前数据库的 key 移动到给定的数据库 db 当中 比如 假设k1目前存在默认库0号 执行: move k1 2 将k1转移到 数据库2号 |
7 | PERSIST key 移除 key 的过期时间,key 将持久保持。persist -1 表示永不过期 |
8 | PTTL key 以毫秒为单位返回 key 的剩余的过期时间 |
9 | TTL key 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live) -1 表示永不过期 -2 表示已过期 |
10 | TYPE key 返回 key 所储存的值的类型 |
11 | EXPIREAT key timestamp EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。 |
12 | RANDOM KEY 从当前数据库中随机返回一个 key |
13 | RENAME key newkey 修改 key 的名称 |
14 | RENAMENX key newkey 仅当 newkey 不存在时,将 key 改名为 newkey |
15 | SCAN cursor [MATCH pattern] [COUNT count] 迭代数据库中的数据库键 |
16 | PEXPIREAT key milliseconds-timestamp 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计 |
17 | DUMP key 序列化给定 key ,并返回被序列化的值 |
更多命令请参考:Commands | Redis
Redis 的配置文件解析
Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf
你可以通过 CONFIG 命令查看或设置配置项。 Redis 配置 | 菜鸟教程
1 | config get 配置项名称 | 查看或设置配置项 例如: CONFIG GET loglevel //获取日志输出等级 输出 notice 使用 * 号获取所有配置项: |
2 | config set 配置项名称 | 修改 redis.conf 文件 指定项配置。 |
redis.conf常用配置说明如下:
序号 | 配置项 | 说明 |
1 | daemonize no | Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程, 设置为yes ,即可后台运行 |
2 | bind 127.0.0.1 | 绑定的主机地址 ,设置后只能指定ip链接服务器。 默认绑定: bind 127.0.0.1 |
3 | protected-mode yes | 是否开启保护模式,默认开启。要是配置里没有指定bind和密码。开启该参数后,redis只会本地进行访问,拒绝外部访问。要是开启了密码和bind,可以开启。否则最好关闭,设置为no |
4 | requirepass foobared | requirepass配置可以让用户使用AUTH命令来认证密码,才能使用其他命令。 设置成一个空的值,可以禁止一个命令 默认注释掉 关闭 |
5 | pidfile /var/run/redis.pid | 当 Redis 以守护进程方式运行时,Redis 默认会把 pid( Process ID!进程ID) 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定pid 写入的文件名称 |
6 | port 6379 | 指定 Redis 监听端口,默认端口为 6379 |
7 | tcp-backlog 511 | 设置tcp的backlog,backlog其实是一个连接队列,backlog队列总和=未完成三次握手队列 + 已经完成三次握手队列。 在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。注意Linux内核会将这个值减小到/proc/sys/net/core/somaxconn的值, 所以需要确认增大somaxconn和tcp_max_syn_backlog两个值 来达到想要的效果 默认设置的值为511 |
8 | timeout 300 | 此参数为设置客户端空闲超过timeout,服务端会断开连接,为0则服务端不会主动断开连接,不能小于0 默认设置值为300 时间单位为秒 |
9 | loglevel notice | 指定了服务端日志的级别。级别包括:debug (很多信息,方便开发、测试),verbose(许多有用的信息,但是没有debug级别信息多), notice(适当的日志级别,适合生产环境),warn (只有非常重要的信息) |
10 | logfile stdout | 日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null 。 指定了记录日志的文件。空字符串的话,日志会打印到标准输出设备。后台运行的redis标准输出是/dev/null 例如: logfile /usr/local/redis/var/redis.log |
11 | syslog-enabled no | 是否打开记录syslog功能 补充:是否将日志信息输出到syslog中 |
12 | syslog-ident redis | 指定syslog里的日志标识 |
13 | syslog-facility local0 | 指定syslog设备,值可以是USER或LOCAL0-LOCAL7 默认值为LOCAL0 |
14 | databases 16 | 设置数据库的数量,默认数据库为0,可以使用SELECT命令在连接上指定数据库id |
15 | always-show-logo yes | 启动时是否展示日志信息 |
16 | maxclients 128 | 设置同一时间最大客户端连接数,默认无限制,Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。 当客户端连接数到达限制时,Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息。 |
17 | maxmemory | 指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 Key, 当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis 新的 vm 机制,会把 Key 存放内存,Value 会存放在 swap 区 |
18 | maxmemory-policy noeviction(重点) | 内存容量超过maxmemory后的处理策略。 lru last recently use 最近最少使用 ttl time to live volatile 最近即将过期 (1)volatile-lru:使用LRU算法移除key volatitle 只对设置了过期时间的键 (2)allkeys-lru:使用LRU算法移除key allkeys 所有的key值 (3)volatile-random:在过期集合中移除随机的key, volatitle 只对设置了过期时间的键 (4)allkeys-random:移除随机的key allkeys 所有的key值 (5)volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key (6)noeviction:不进行移除。针对写操作,只是返回错误信息 生产禁用 |
19 | maxmemory-samples 5 | 设置样本数量,LRU算法和最小TTL算法都并非是精确的算法,而是估算值,所以你可以设置样本的大小, redis默认会检查这么多个key并选择其中LRU的那个 |
20 | include /path/to/local.conf | 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 类似于jsp技术在中的《include》 标签 可以将指定的文件包含进当前文件中 |
13 | slaveof | 设置当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步 |
14 | masterauth | 当 master 服务设置了密码保护时,slav 服务连接 master 的密码 |
15 | requirepass foobared | 设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH 命令提供密码,默认关闭 |
21 | vm-enabled no | 指定是否启用虚拟内存机制,默认值为 no,简单的介绍一下,VM 机制将数据分页存放,由 Redis 将访问量较少的页即冷数据 swap 到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析 Redis 的 VM 机制) |
22 | vm-swap-file /tmp/redis.swap | 虚拟内存文件路径,默认值为 /tmp/redis.swap,不可多个 Redis 实例共享 |
23 | vm-max-memory 0 | 将所有大于 vm-max-memory 的数据存入虚拟内存,无论 vm-max-memory 设置多小,所有索引数据都是内存存储的(Redis 的索引数据 就是 keys),也就是说,当 vm-max-memory 设置为 0 的时候,其实是所有 value 都存在于磁盘。默认值为 0 |
24 | vm-page-size 32 | Redis swap 文件分成了很多的 page,一个对象可以保存在多个 page 上面,但一个 page 上不能被多个对象共享,vm-page-size 是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page 大小最好设置为 32 或者 64bytes;如果存储很大大对象,则可以使用更大的 page,如果不确定,就使用默认值 |
25 | vm-pages 134217728 | 设置 swap 文件中的 page 数量,由于页表(一种表示页面空闲或使用的 bitmap)是在放在内存中的,,在磁盘上每 8 个 pages 将消耗 1byte 的内存。 |
26 | vm-max-threads 4 | 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4 |
27 | glueoutputbuf yes | 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启 |
28 | hash-max-zipmap-entries 64hash-max-zipmap-value 512 | 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法 |
29 | activerehashing yes | 指定是否激活重置哈希,默认为开启(后面在介绍 Redis 的哈希算法时具体介绍) |
30 | 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 |