缘起
- 想找一个开源技术点深入下去的,于是找到了redis,比较好的是,他有相应的学习曲线。
- 全书第1遍用了3h19min的样子,20181117开始读的,20181123读完。还会继续阅读第2遍或第3遍,虽然原理性可能不太多,但我还没有很好的消化它,虽然这本书不是每个点都要了解,但还是要读到觉得能放下为止。
- 下一本读《Redis实战》
内容
- 目录 8/224
chap1 简介 11/224
1.1、历史与发展
- 网站实时统计系统LLOOGG,创始人是意大利的Salvatore Sanfilippo。
- 是REmote DIctionary Server(远程字典服务器)的缩写。
1.2、特性
- 1.2.1 存储结构
- 1.2.2 内存存储与持久化
- 数据都在内存中,程序退出后内存中的数据如何保存?
- 1.2.3 功能丰富
- 为每个键设置生存时间(Time To Live)
- 1.2.4 简单稳定
HGET post:1 title // 读取键名为post:1 的散列类型键的title字段的值
chap2 准备 17/224
2.1、安装Redis
- 2.1.1 在POSIX系统中安装
- 官方安装文档
- 2.1.2 在OS X系统中安装
- 2.1.3 在Windows中安装
- 比较麻烦
2.2、启动和停止Redis 11(21/224)
make
后继续执行make install
相应的6个命令会拷贝到/usr/local/bin
目录下。-
2.2.1 启动Redis
- 直接启动
-
redis-server
,默认端口是6379;可以用port
参数指定,即redis-server --port 6380
-
- 通过初始化脚本启动
-
redis/utils/redis_init_script
的脚本文件 - 复制脚本到
/etc/init.d
目录中
-
- 直接启动
-
2.2.2 停止Redis
redis-cli SHUTDOWN
2.3、Redis命令行客户端
- 2.3.1 发送命令
- 参数模式
redis-cli -h 127.0.0.1 -p 6379
redis-cli PING
- 交互模式
-
redis-cli
后,再输入PING
或ECHO hi
无关大小写
-
- 参数模式
- 2.3.2 命令返回值
- 状态回复
- 错误回复
- 整数回复
- 字符串回复
- 多行字符串回复
2.4、配置
-
redis-server /path/to/redis.conf
这个路径我没找到,只是解压目录下有个redis.conf
文件 -
$redis> CONFIG SET
命令在不重新启动Redis的情况下动态修改部分Redis配置
2.5、多数据库
- 默认支付16个数据库
select 0
到select 15
- 这些数据库更像是一种命名空间;一个空Redis实例占用的内存只有1M左右。
chap3 入门 29/224
3.1、热身
- 1、获得符合规则的键名列表
-
KEYS pattern
patern支持glob风格通配符 set bar 1
-
keys *
keys命令需要遍历Redis中的所有键,会影响性能,不建议用。
-
- 2、判断一个键是否存在
exists bar
-
exists no
//返回值是(integer) 0
- 3、删除键
-
del bar
del命令不支付通配符 -
redis-cli keys "user:*" | xargs redis-cli del
来实现删除
-
- 4、获取键值的数据类型
type bar
3.2、字符串类型
- 3.2.1 介绍
- 一个字符串类型键允许存储的数据的最大容量是512MB。
- 3.2.2 命令
- 1、复制与取值
set key hello
get key
- 2、递增数字
INCR num
- 1、复制与取值
- 3.2.3 实践
- 1、文章访问量统计
- 2、生成自增ID
- 3、存储文章数据
- 3.2.4 命令拾遗
- 1、增加指定的整数
INCRBY bar 2
- 2、减少指定的整数
-
DECR bar
只是递减,无法减多少
-
- 3、增加指定浮点数
INCRBYFLOAT bar 2.7
- 4、向尾部追加值
set key hello
-
append key " world!"
// 返回的是总长度
- 5、获取字符串长度
STRLEN key
- 6、位操作 lionel这部分没看
- 1、增加指定的整数
3.3、散列类型
- 3.3.1 介绍
- 一个散列类型键可以包含至多2的32次方-1个字段。
- 3.3.2 命令
- 1、赋值与取值
HSET car price 500
HSET car name BMW
HGET car name
- 需要同时设置多个字段的值时,可以使用
HMSET
命令。 -
HMGET car price name
// 同时获得多个字段的值 -
HGETALL car
// 想获取键中所有字段和这段值都不知道键中有哪些字段时
- 2、判断字段是否存在
HEXISTS car model
- 3、当字段不存在时赋值
-
HSETNX
// 是原子操作,不用担心竞态条件。
-
- 4、增加数字
-
HINCRBY person score 60
// person键不存在,会创建该键并默认score字段在执行命令前的值为“0”。返回值是60 -
HINCRBY person score 1
// 因为存在了,所以返回值是61
-
- 5、删除字段
- 'HDEL'
- 1、赋值与取值
- 3.3.3 实践 lionel也没怎么好好看
- 1、存储文章数据
- 2、存储文章缩略名
- 3.3.4 命令拾遗
- 1、只获取字段名或字段值
HKEYS car
HVALS car
- 2、获取字段数量
HLEN car
- 1、只获取字段名或字段值
3.4、列表类型
- 3.4.1 介绍
- 一个列表(List)类型键可以包含至多2的32次方-1个元素。
- 3.4.2 命令
- 1、向列表两端增加元素
-
LPUSH numbers 1
// 返回列表的长度 1 -
RPUSH numbers 0 -1
// 返回列表的长度 3
-
- 2、从列表两端弹出元素
LPOP numbers
RPOP numbers
- 3、获取列表中元素的个数
HLEN numbers
- 4、获取列表片断
-
LRANGE numbers 0 2
// 获取一个区间的数据
-
- 5、删除列表中指定的值
-
LREM numbers 0 -1
// count=0,删除所有“-1”的元素 -
LREM numbers -1
// count<0,从列表右边开始删除第1个元素;cout>0时,从左边删
-
- 1、向列表两端增加元素
- 3.4.3 实践 lionel没怎么看
- 1、存储文章ID列表
- 2、存储评论列表
- 3.4.4 命令拾遗
- 1、获得/设置指定索引的元素值
LINDEX numbers 0
LSET numbers 1 7
- 2、只保留列表指定片段
LRANGE numbers 0 -1
- 3、向列表中插入元素
LINSERT numbers AFTER 7 3
LINSERT numbers BEFORE 2 1
- 4、将元素从一个列表转到另一个列表
RPOPLPUSH
- 1、获得/设置指定索引的元素值
3.5、集合类型
- 3.5.1 介绍
- 一个集合(set)类型键可以包含至多2的32次方-1个字符串。
- 3.5.2 命令
- 1、增加/删除元素
-
SADD letters a b c
// 返回增加的个数 3 -
SREM letters c d
// 返回删除的个数1,因为d本身就不存 在
-
- 2、获得集合中的所有元素
SEMBERS letters
- 3、判断元素是否在集合中
SISMEMBER letters a
- 4、集合间运算
SDIFF
SINTER
SUNION
- 1、增加/删除元素
- 3.5.3 实践
- 1、存储文章标签
- 2、通过标签搜索文章
- 3.5.4 命令拾遗
- 1、获得集合中元素个数
SCARD letters
- 2、进行集合运算并将结果存储
SINTERSTORE
- 3、随机获得集合中的元素
SRANDMEMBER letters
- 4、从集合中弹出一个元素
SPOP letters
- 1、获得集合中元素个数
3.6、有序集合类型
- 3.6.1 介绍
- 有序集合与链表的异同
- 3.6.2 命令
- 1、增加元素
ZADD scoreboard 89 Tom 67 Peter 100 David
- 2、获得元素的分数
-
ZSCORE scoreboard Tom
69/224 lionel 没怎么读
-
- 1、增加元素
- 3.6.3 实践
- 1、实现按点击量排序
- 2、改进按时间排序
- 3.6.4 命令拾遗
- 1、获得集合中元素的数量
ZCARD scoreboard
- 2、获得指定分数范围内的元素个数
- 3、删除一个或多个元素
- 4、按照排名范围删除元素 lionel也没怎么看呢
- 1、获得集合中元素的数量
chap4 进阶 67(77/224)
4.1、事务
- 4.1.1 概述
-
MULTI
命令告诉Redis,下面的命令属于事务。
-
- 4.1.2 错误处理
- 语法错误 直接不执行,返回错误码
- 运行错误 不支持回滚功能,只能将数据库复原到之前的状态
- 4.1.3 WATCH命令介绍
- WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。
-
UNWATCH
取消监控
4.2、过期时间
- 4.2.1 命令介绍
SET session:29e3d uid1314
-
EXPIRE session:29e3d 900
// 让session:29e3d键在15分钟后被删除。EXPIRE
命令设置一个键的过期时间,到时期后Redis会自动删除它 -
TTL session:29e3d
// session:29e3d键的剩余时间 -
PERSIST session:29e3d
// 取消session:29e3d键的过期时间设置
- 4.2.2 实现访问频率限制之一
- 限制每分钟每个用户最多只能访问100个页面。
- 4.2.3 实现访问频率限制之二
- 4.2.4 实现缓存
- 修改配置文件的maxmemory参数,限制Redis最大可用内存大小,超出限制时Redis会依据maxmemory-policy参数指定的策略来删除不需要的键,直到Redis占用的内存小于指定内存。
4.3、排序
- 4.3.1 有序集合的集合操作
- 4.3.2 SORT命令
- 4.3.3 BY参数
-
SORT sortbylist BY somkey->somefield:*
//*
只能在->
符号前面才有用,否则只会被当作字段名本身
-
- 4.3.4 GET参数
-
SORT tag:ruby:posts BY post:*->time DESC post:*->title
// GET参数不影响排序,作用是使SORT命令的返回结果不再是元素自身的值,而是GET参数中指定的键值。
-
- 4.3.5 STORE参数
-
SORT tag:ruby:posts BY post:*->time DESC GET post:*->title GET post:*->time GET # STORE sort.result
// 保存排序结果,默认是直接返回排序结果的
-
- 4.3.6 性能优化
- SORT的时间复杂度是O(n+mlog(m))
- 使用SORT命令时有几点注意:
- 尽可能减少待排序的数据(N尽可能小)
- 使用LIMIT参数只获取需要的数据(使M尽可能小)
- 如果要排序的数据量较大,尽可能使用STORE参数将结果缓存
4.4、消息通知
- 4.4.1 任务队列
- 4.4.2 使用Redis实现任务队列
- 4.4.3 优先级队列 lionel没好好看,以及4.4到目前
- 4.4.4 “发布/订阅”模式
-
PUBLISH channel.2 hi
// 向channel.2说一声“hi” 发布者 -
SUBSCRIBE chanel.2
// 订阅者
-
- 4.4.5 按照规则订阅
-
PSUBSCRIBE channel.?*
// 订阅指令的规则,支持glob风格通配符
-
4.5、管道
4.6 节省空间
- 4.6.1 精简键名和键值
- 4.6.2 内部编码优化 lionel没好好看
- 0、
- 1、字符串类型
chap5 实践 103(113/224)
5.1、PHP与Redis
- 5.1.1 安装
- 解压后放入项目目录中,引用autoload.php文件
require './dir/autoload.php'
假设在dir目录下,后面会用到。
- 解压后放入项目目录中,引用autoload.php文件
- 5.1.2 使用方法
- 创建一个连接
$redis = new dir\Client();
$redis = new dir\Client(arry('scheme'=>'tcp','host'=>'127.0.0.1','port'=>6379,));
echo $redis->get('foo');
- 创建一个连接
- 5.1.3 简便用法
- 5.1.4 实践:用户注册登录功能
5.2、Ruby与Redis
- 5.2.1 安装
-
gem install redis
安装新版的redis-rb
-
- 5.2.2 使用方法
- 5.2.3
- 5.2.4
5.3、Python与Redis
- 5.3.1 安装
pip install redis
- 5.3.2 使用方法
-
import redis
// 引入redis-py
-
- 5.3.3 简便用法
- 1、HMSET/HGETALL
- 2、事务和管道
- 5.3.4 实践:在线的好友
5.4、Node.js与Redis
- 5.4.1 安装
npm install ioredis
- 5.4.2 使用方法
- 加载ioredis模块
var Redis = require('ioredis');
- 加载ioredis模块
- 5.4.3 简便用法
- 1、HMSET/HGETALL
- 2、事务
- 3、“发布/订阅”模式
- 5.4.4 实践:IP地址查询
chap6 脚本 131(141/224)
6.1、概览
- 6.1.1 脚本介绍
- 允许开发者使用Lua语言编写脚本传到Redis中执行。
- 脚本的好处:
- (1)减少网络开销
- (2)原子操作
- (3)复用
- 6.1.2 实例:访问频率限制
6.2、Lua语言
- 6.2.1 Lua语法
- 数据类型
- 变量
- 注释
- 赋值
- 操作符
- if语句
- 循环语句
- 表类型
- 函数
- 6.2.2 标准库
- String库
- Table库
- Math库
- 6.2.3 其他库
- cjson库
- cmsgpack库
6.3、Redis与Lua
- 6.3.1 在脚本中调用Redis命令
- 6.3.2 从脚本中返回值
- 6.3.3 脚本相关命令
- 1、EVAL命令
- 2、EVALSHA命令
- 6.3.4 应用实例
- 1、同时获取多个散列类型键的键值
- 2、获利并删除有序集合中分数最小的元素
- 3、处理JSON
6.4、深入脚本
- 6.4.1 KEYS与ARGV
- 6.4.2 沙盒与随机数
- 6.4.3 其他脚本相关命令
- 1、将脚本加入缓存:SCRIPT LOAD
- 2、判断脚本是否已经被缓存:SCRIPT EXISTS
- 3、清空脚本缓存:SCRIPT FLUSH
- 4、强制终止当前脚本的执行:SCRIPT KILL
- 6.4.4 原子性和执行时间
chap7 持久化 157(167/224)
7.1、RDB方式
- 0、
- 通过快照(snapshotting)完成的。当符合一定条件的Redis会自动将内存中的所有数据生成一份副本并存储在硬盘上,这个过程即为“快照“。
- 在以下情况对数据进行快照:
- 根据配置规则进行自动快照
- 用户执行SAVE或BGSAVE命令
- 执行FLUSHALL命令
- 执行复制(replication)时
- 7.1.1 根据配置规则进行自动快照
- 7.1.5 快照原理
- 在执行fork时OS会使用写时复制(copy-on-write)策略,即fork函数发生的一刻子进程共享同一内存数据。
- 所以新的RDB文件存储的是执行fork一刻的内存数据。
- 我们通过定时备份RDB文件来实现Redis数据库备份。
7.2、AOF方式
- 7.2.1 开启AOF
-
appendonly yes
**通过手工开启,默认没有开启(AOF append only file)
-
- 7.2.2 AOF的实现
- 7.2.3 同步硬盘数据
- 操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每30秒会执行一次同步操作,以便将硬盘缓存中的内容真正地写入硬盘。
-
appendfsync everysec
// 采用everysec规则
chap8 集群 165(175/224)
8.1、复制
- 8.1.1 配置
$ redis-server --port 6380 --slaveof 127.0.0.1 6379
-
SALVEOF
命令会停止和原来数据库的同步转而和新数据库同步。
- 8.1.2 原理
- 8.1.3 图结构
- 8.1.4 读写分离与一致性
- 一主多从的结构很适合读多写少的场景,主数据库只进行写操作,从数据库负责读操作。
- 8.1.5 从数据库持久化
- 8.1.6 无硬盘复制
- 8.1.7 增量复制
8.2、哨兵
- 8.2.1 什么是哨兵
- 8.2.2 马上上手
- 8.2.3 实现原理
- 一个哨兵节点可以同时监控多个Redis主从系统,只需要提供多个sentinel monitor配置即可。
- 8.2.4 哨兵的部署
- 哨兵以独立进程的方式对一个主从系统进行监控。
8.3、集群
- 8.3.1 配置集群
- 需要将每个数据库节点的cluster-enabled配置选项打开即可。
- 8.3.2 节点的增加
- 8.3.3 插槽的分配
- 8.3.4 获取与插槽对应的节点
- 8.3.5 故障恢复
chap9 管理 193(203/224)
9.1、安全
- 9.1.1 可信的环境
- 9.1.2 数据库密码
- 9.1.3 命名命令
9.2、通信协议
- 9.2.1 简单协议
- 适合在telnet程序中和Redis通信。
- 9.2.2 统一请求协议
9.3、管理工具
- 9.3.1 redis-cli
- 耗时命令日志
redis> SLOWLOG GET
- 命令监控
redis> MONITOR
- 耗时命令日志
- 9.3.2 phpRedisAdmin
- 9.3.3 Rdbtools
附录 203(213/224)
附录A
- A.1 REDIS_CMD_WRITE
- A.2 REDIS_CMD_DENYOOM
- A.3 REDIS_CMD_NOSCRIPT
附录B
附录C CRC16 实现参考
收获
履历
- 20181117从头开始看到3.2.4节(1-37/224),用时1h16min。不太理解的地方
- (1)用命令行配置启动;(2)redis配置; 虽然照着会做,但知识点上没有融汇贯通。
- 20181119从3.2.4看到4.1.2(37-80/224),用时1h02min。差不多我只能坚持看1小时书。
- 中间有几个地方跳过没好好看,后期要补上,主要是单纯的用命令,不知道场景在哪,可能属于基础吧,还是需要熟悉。
- 要确认各个类型的区别,以及知道他们的优缺点。
- 20181120从4.1.2看到5.3.1(80-126/224),用时40min
- 在4.4消息通知方面没怎么看,包括4.6节省空间方面。
- 其它方面的知识呢,差不多都能理解。可以搜搜面试指南来查漏或夯实知识
- 20181121从5.3.1看到7.1.4(126-169/224),用时21min。其实没怎么看,就是过了下结构。
- 毕竟第chap6的Lua和chap5实践,都需要搭建环境去跑的,算是个大概了解吧,估计后期会选用Python进行实践,因为《Redis实战》用的是这个。
- chap7持久化开了个头,因为前期还搜了部分知道,看起来不觉得费劲。
- 20181123从7.1.5看到结束(169-224/224),用时26min。也没有过多学习新知识,就是看个大概。
- 了解了下AOF方式。
- 集群的话,面试环境可能会在复制这部分有些问题要问,自己也有点感触,但哨兵和集群,可能在架构或配置时要用。
- chap9管理的话,只是作了部分的了解。