Redis学习笔记

概述

Redis是一个非关系型数据库,以键值对的方式来存储数据。
数据通过存储在内存中来获得高的读写性能,同时也可以存储到硬盘以实现持久化,既适合用作缓存,也适合用作数据存储。
非关系型数据库的本质,就是切掉一部分关系型数据库拥有的功能,而专注于高效的实现某些功能。
如在本笔记中发现错误,欢迎指正。

参考书籍

《Redis实战》,人民邮电出版社。

数据类型与命令

Redis可以存储键与5种不同数据结构类型之间的映射。
每种类型的指令均由该类型的首字母开头,然后用操作对应的英文单词表达。

STRING

可以是字符串、整数或者浮点数。

  • 整数的取值范围和系统的长整数的取值范围相同。
  • 浮点数的取值范围和精度与IEEE754标准的双精度浮点数相同。
数操作命令

对数类型进行增减的命令。
INCR、DECR、INCRBY、DECRBY、INCRBYFLOAT。

  • 对一个不存在或者保存了空串的键进行了操作,会将该键的的值当做0来处理。
  • 如果尝试对无法解释为整数或者浮点数的字符串操作,会返回错误。
子串和二进制位命令

对字符串类型进行字符或者位级别操作的指令。
APPEND、GETRANGE、SETRANGE、GETBIT、SETBIT、BITCOUNT、BITOP。

  • 在使用SET*对字符串进行写入的时候,如果字符串长度不满足要求,会自动使用空自己(null)来将字符串扩展至所需的长度再执行。
  • 在使用GETRANGE读取字符串时,超出字符串末尾的数据会被视为空串。
  • 在使用GETBIT读取二进制串时,超过字符串末尾的数据会被视为0。

LIST

一个链表,链表每个节点都包含了一个字符串。

常用列表命令

推入、弹出、索引等命令。
RPUSH、LPUSH、RPOP、LPOP、LINDEX、LRANGE、LTRIM。

阻塞命令

阻塞命令可以阻塞执行命令的客户端,直到其他客户端给列表添加元素为止,常用于消息传递和任务队列。
BLPOP、BRPOP、BPOPLPUSH、BRPOPLPUSH。

SET

包含字符串的无序收集器,包含的每个字符串都是独一无二的。

常用集合命令

添加、删除、查询等命令。
SADD、SREM、SISMEMBER、SCARD、SMEMBERS、SRANDMEMBER、SPOP、SMOVE。

多集合操作命令

用于作集合的交集、差集、并集等命令。
SDIFF、SDIFFSTORE、SINTER、SINTERSTORE、SUNION、SUNIONSTORE。

HASH

包含键值对的无序散列表。

  • 与字符串一样,对一个不存在的键进行自增时,会将值当做0来处理。
常用散列命令

添加、删除、查询等命令。
HMGET、HMSET、HDEL、HLEN。

高级散列命令

批量操作命令,以及一些字符串操作类似的散列命令。
HEXISTS、HKEYS、HVALS、HGETALL、HINCRBY、HINCRBYFLOAT。

ZEST

字符串成员与浮点数分值之间的有序映射,元素的排列顺序由分值的大小决定。当分值相同时,会按照字符串进行排序。

常用有序集合命令

添加、删除、查询、统计等命令。
ZADD、ZREM、ZCARD、ZINCRBY、ZCOUNT、ZRANK、ZSCORE、ZRANGE。

范围操作命令

逆序、子集、交集、并集等命令。
ZREVRANK、ZREVRANGE、ZRANGEBYSCORE、ZREVRANGEBYSCORE、ZREMRANGEBYRANK、ZREMRAMGEBYSCORE、ZINTERSTORE、ZUNIONSTORE。

  • 交集和并集运算需要对分数使用聚合函数,默认函数是sum,此外还有min、max等。
  • 普通集合的分值默认当做1来处理。

发布与订阅

订阅者负责订阅频道,发送者负责向频道发送二进制字符串消息。
Redis的发布订阅模式有两个缺点:

  • 读取消息的速度如果赶不上发送消息的速度,会被自动断开连接。
  • 遇到网络断线时期间的消息都会丢失。
常用命令

订阅与发布的命令。
SUBSCRIBE、UNSUBSCRIBE、PUBLISH、PSUBSCRIBE、PUNSUBSCRIBE。

其他通用指令

SORT

可以设置升降序,字符、数字、或者其他权重排序。

过期时间

设置、查看、取消键的过期时间,但是对于列表、集合、散列和有序集合,只能为整个键设置过期时间。
PERSIST、TTL、EXPIRE、EXPIREAT、PTTL、PEXPIRE、PEXPIREAT。

持久化

Redis提供两种不同形式的持久化方法,这两种方法可以不使用、单独使用或者同时使用:

  • 快照,可以将存在于某一时刻的所有数据都写入硬盘。
    • 发送BGSAVE命令,redis会用fork创建一个子进程负责将快照写入硬盘。如果系统剩余的内存很少,该命令可能导致系统长时间停顿。
    • 发送SAVE命令,redis将开始创建快照并不再接收任何命令,直到快照创建完毕。因为不用和子进程争抢资源,所以该命令创建快照的速度会比BGSAVE更快。
    • 通过SHUTDOWN命令接收关闭服务器请求时,会执行SAVE命令,执行完毕后再关闭服务器。
    • 服务崩溃会导致最后一次快照之后的数据丢失。
    • 从服务器连接到主服务器并发送SYNC命令时,如果主服务器没有在执行BGSAVE命令,则会执行该命令。
  • 只追加文件,在执行写命令时将被执行的写命令复制到硬盘里面。
    • appendfsync选项用于设置同步频率:
      • no:操作系统决定,几乎不对redis性能带来影响,系统崩溃会丢失不定量数据,如果硬盘写入速度不够快导致缓冲区被填满,会阻塞redis写入。
    • everysec:每秒一次,对redis性能影响较小。
    • always:每次写命令执行,受硬盘性能限制,会严重降低redis性能,并减少固态硬盘的寿命。
  • 发送BGREWRITEAOF命令可以移除AOF文件中的冗余命令来重写AOF文件以减少文件体积,该命令的工作原理和BGSAVE十分相似。

复制

与关系型数据库类似,通过主从复制,客户端每次向主服务器
写入时,都会同步到从服务器,读请求可以向任意的从服务器发送。
Redis不支持主主复制。

配置

  • 为从服务器设置slaveof host port配置,redis在启动时首先会载入当前可用的任何快照或者AOF文件,然后连接主服务器。
  • 使用SLAVEOF命令,redis会立即尝试连接主服务器。
  • 从服务器默认是不允许写入的,但某些查询可能需要进行一些临时写入,此时需要将从服务器的salve-read-only配置选项从默认的yes改成no。

复制过程

  • 从服务器发送SYNC命令连接主服务器。
  • 主服务器执行BGSAVE。
  • 主服务器发送快照文件并使用缓冲区记录这段期间的写命令,从服务器丢弃所有旧数据并载入主服务器的快照文件。
  • 主服务器发送缓冲区的命令。
  • 主服务器同步发送写命令。

对于主从链复制,如果从服务器X拥有从服务器Y,那么当X执行对快照文件的解释时,会断开与Y的连接,导致Y需要重新连接和同步。

故障处理

验证快照文件或者AOF文件

redis提供了两个命令行程序来检查快照文件和AOF文件的状态并在需要的情况下进行恢复:

  • redis-check-aof:redis会扫描aof文件,当发现第一个出错命令时,会删除出错的命令以及位于出错命令后的所有命令。
  • redis-check-dump

更换redis服务器

更换主服务器

因为从服务器是无法执行写命令的,所以可以通过快照的方式发送数据,整个过程不会出现数据的不一致性。

  • 从服务器执行SAVE命令生成快照。
  • 将快照文件发送给新的主服务器,让主服务器从快照启动。
  • 将从服务器连接上新的主服务器。
升级从服务器

修改配置文件让从服务器升级成为主服务器。

事务

与关系型数据库的差异

redis的事务和传统的关系型数据库不同。

  • 关系型数据库事务以BEGIN命令开始,然后执行各个相互一致的读写操作,最后用户可以选择COMMIT确认修改或者ROLLBACK放弃修改。
  • redis事务以MULTI命令开始,然后传入多个命令,最后以EXEC结束,但是在EXEC命令被调用前不会执行任何实际操作,所以用户没法根据读取到的数据来决定。

命令

redis事务由五个命令组成:

  • MULTI:事务开始的命令。
  • EXEC:事务结束的命令。
  • WATCH:对键进行监视,在用户执行EXEC之前,如果有其他客户对被监视的键进行了修改,那么事务将失败并返回错误。
  • UNWATCH:在WATCH命令之后、MULTI命令之前对连接进行重置。
  • DISCARD:在MULTI命令执行之后、EXEC命令执行之前对连接进行重置,该指令会取消WATCH命令,并且清空已入队的命令。

客户端流水线

  • 客户端往往会用队列缓存指令,直到输入EXEC命令后再一次性将事务发送给服务器,以减少通信数量,提高速度。
  • 非事务型操作也可以使用流水线的方法来提高速度。

锁分类

在共享数据库中,通过加锁可以让当前客户端对数据进行排他性访问。一般步骤为先获取锁,然后执行操作,最后释放锁。

  • 常见的关系型数据库在加锁时就不允许其他客户端修改了,这种锁称为“悲观锁”。
  • Redis使用WATCH命令来对数据进行加锁,WATCH只会在数据被其他客户端抢先修改了的情况下才通知执行了这个命令的客户端,而不会阻止其他客户端对数据进行修改,这种加锁方式称为“乐观锁”。
    • 因为在失败后会进行重试,所以这种锁在重负载的情况下可能会出现性能问题。

悲观锁实现

  • SETNX指令,只会在键不存在的情况下为键设置值,用于获取锁。
  • 锁占有者通过为键设置超时时间,来避免自身崩溃后一直持有锁。
  • 竞争者通过检查并为没有超时时间的锁设置超时时间,来避免锁占有者在设置超时时间之前就崩溃。
  • 锁占有者通过取消键的值来释放锁。

信号量

通过redis命令有多种方式来实现信号量功能,属于redis应用场景,本篇不多介绍。

性能优化

短结构

  • Redis为列表、集合、散列和有序集合提供了一组配置选项,可以让Redis以更节约空间的压缩列表存储长度较短的结构,即短结构。
    • 列表、散列、有序集合的配置选项由*-max-ziplist-entries和-max-ziplist-value组成,entries表示包含最大元素的数量,value表示每个节点的最大体积字节数。
    • 集合的配置选项为set-max-intset-entries,但要求成员必须能够被解释为可表示的整数,这种存储方式被称为整数集合。
    • 当选项设置的任意限制条件被突破的时候,redis会将编码转换为其他结构。
  • 压缩列表会以序列化的方式存储数据,这些序列化数据每次被读取的时候都要进行解码,每次被写入的时候也要进行局部的重新编码,并且可能需要对内存里面的数据进行移动。
    • 所以短结构本质上是拿时间换空间,当结构很长时,对时间性能的影响就会变得很大。

分片结构

  • 一个通用的技巧,对数据计算哈希值后分片存储,既可以对键进行分片也可以对键的值进行分片。分片后的数据进行读写以及运算操作都需要进行相应的调整。
  • 可以和短结构组合使用,让每个分片都能够被表示为短结构。
  • 不同的分片可以存储在不同的数据库中从而对数据库的写性能进行扩展。

位图表示

  • 一个通用的技巧,对数据进行连续编码,然后以位图的方式来存储。
  • 可以和分片与短结构组合使用,将长位图进行分片。

Lua脚本编程

Redis从2.6版本开始引入使用Lua编程语言进行的服务器端脚本编程功能。

  • SCRIPT LOAD命令接受一个字符串格式的Lua脚本为参数,然后把脚本存储起来并返回SHA1的校验和。
  • EVALSHA命令接受脚本的SHA1校验和以及脚本所需的全部参数来执行脚本。
  • Redis也把EVAL和EVALSHA看作是单个命令来处理,都是原子操作。所以通过Lua脚本可以更加简单的实现事务操作的效果。

注意事项

  • Lua里面的某些数据类型是不允许进行传出的,因为脚本在返回不同类型的数据时可能会产生含糊不清的结果,所以应该尽量显式的返回字符串,然后手动的进行分析操作。
  • 使用SCRIPT KILL命令可以终止正在运行的脚本,但是已经对结构进行了修改的Lua脚本将无法被中断,只能使用SHUTDOWN NOSAVE命令杀死服务器,让服务器从最近的一次快照重新启动。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,829评论 1 331
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,603评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,846评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,600评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,780评论 3 272
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,695评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,136评论 2 293
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,862评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,453评论 0 229
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,942评论 2 233
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,347评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,790评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,293评论 3 221
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,839评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,448评论 0 181
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,564评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,623评论 2 249

推荐阅读更多精彩内容

  • Redis简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。Redis ...
    drfung阅读 933评论 0 10
  • REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写...
    yoyo鹿鸣阅读 262评论 0 1
  • 聊聊redis持久化 – 两种方式 redis提供了两种持久化的方式,分别是RDB(Redis DataBase)...
    lijun_m阅读 227评论 0 1
  • 最近,添置了不少物品,买了一些可有可无的东西,也买了新手机。买中大件物品不再像以前一样考虑许久。一来是经济上比之前...
    IT学思想阅读 1,582评论 0 5
  • 今天和老薛一起去的车站 买的票是过路车 居然只经过城东 如果坐公车的话还要一个半小时 老妈拜托了她朋友来接我 本...
    打好boss好睡觉阅读 130评论 0 0