一、基础知识
1.1 数据库
在 Redis 里,数据库简单的使用一个数字编号来进行辨认,默认数据库的数字编号是 0。如果你想切换到一个不同的数据库,你可以使用 select 命令来实现。在命令行界面里键入 select 1,Redis 应该会回复一条 OK 的信息,然后命令行界面里的提示符会变成类似 redis 127.0.0.1:6379[1]> 这样。如果你想切换回默认数据库,只要在命令行界面键入 select 0 即可
1.2 命令、关键字和值
Redis 不仅仅是一种简单的关键字 - 值型存储,从其核心概念来看,Redis 的 5 种数据结构中的每一个都至少有一个关键字和一个值
关键字(Keys)是用来标识数据块,值(Values)是关联于关键字的实际值,可以是字符串、整数、序列化对象(使用 JSON、XML 或其他格式)
Redis 命令的基本构成,如:set users:leto “{name: leto, planet: dune, likes: [spice]}”
关键字和值的是 Redis 的基本概念,而 get 和 set 命令是对此最简单的使用
1.3 Redis 查询
对于 Redis 而言,关键字就是一切,而值是没有任何意义。Redis 不允许通过值来进行查询
1.4 存储器和持久化
Redis 是一种持久化的存储器内存储(in-memory persistent store)默认情况下,Redis 会根据已变更的关键字数量来进行判断,然后在磁盘里创建数据库的快照(snapshot)。你可以对此进行设置,如果 X 个关键字已变更,那么每隔 Y 秒存储数据库一次。默认情况下,如果 1000 个或更多的关键字已变更,Redis 会每隔 60 秒存储数据库;而如果 9 个或更少的关键字已变更,Redis 会每隔 15 分钟存储数据库
至于存储器,Redis 会将所有数据都保留在存储器中。显而易见,运行 Redis 具有不低的成本:因为 RAM 仍然是最昂贵的服务器硬件部件
1.5 小结
关键字(Keys)是用于标识一段数据的一个字符串
值(Values)是一段任意的字节序列,Redis 不会关注它们实质上是什么
Redis 展示了(也实现了)5 种专门的数据结构
上面的几点使得 Redis 快速而且容易使用,但要知道 Redis 并不适用于所有的应用场景
二、Redis 的数据结构
关于 key
key 不要太长,尽量不要超过 1024 字节,这不仅消耗内存,而且会降低查找的效率
key 也不要太短,太短的话,key 的可读性会降低
在一个项目中,key 最好使用统一的命名模式,例如 user:10000:passwd
2.1 字符串 strings
127.0.0.1:6379> set mynum “2”
OK
127.0.0.1:6379> get mynum
“2”
127.0.0.1:6379> incr mynum
(integer) 3
127.0.0.1:6379> get mynum
“3”
由于 INCR 等指令本身就具有原子操作的特性,所以我们完全可以利用 redis 的 INCR、INCRBY、DECR、DECRBY 等指令来实现原子计数的效果,假如,在某种场景下有 3 个客户端同时读取了 mynum 的值(值为 2),然后对其同时进行了加 1 的操作,那么,最后 mynum 的值一定是 5。不少网站都利用 redis 的这个特性来实现业务上的统计计数需求。
2.2 列表 lists
lists 的常用操作包括 LPUSH、RPUSH、LRANGE 等。我们可以用 LPUSH 在 lists 的左侧插入一个新元素,用 RPUSH 在 lists 的右侧插入一个新元素,用 LRANGE 命令从 lists 中指定一个范围来提取元素。
// 新建一个 list 叫做 mylist,并在列表头部插入元素 ”1″
127.0.0.1:6379> lpush mylist “1”
// 返回当前 mylist 中的元素个数
(integer) 1
// 在 mylist 右侧插入元素 ”2″
127.0.0.1:6379> rpush mylist “2”
(integer) 2
// 在 mylist 左侧插入元素 ”0″
127.0.0.1:6379> lpush mylist “0”
(integer) 3
// 列出 mylist 中从编号 0 到编号 1 的元素
127.0.0.1:6379> lrange mylist 0 1
1) “0”
2) “1”
// 列出 mylist 中从编号 0 到倒数第一个元素
127.0.0.1:6379> lrange mylist 0 -1
1) “0”
2) “1”
3) “2”
lists 的应用相当广泛,随便举几个例子:
我们可以利用 lists 来实现一个消息队列,而且可以确保先后顺序,不必像 MySQL 那样还需要通过 ORDER BY 来进行排序。
利用 LRANGE 还可以很方便的实现分页的功能。
在博客系统中,每片博文的评论也可以存入一个单独的 list 中。
2.3 集合 sets
redis 的集合,是一种无序的集合,集合中的元素没有先后顺序。集合相关的操作也很丰富,如添加新元素、删除已有元素、取交集、取并集、取差集等.
// 向集合 myset 中加入一个新元素 ”one”
127.0.0.1:6379> sadd myset “one”
(integer) 1
127.0.0.1:6379> sadd myset “two”
(integer) 1
// 列出集合 myset 中的所有元素
127.0.0.1:6379> smembers myset
1) “one”
2) “two”
// 判断元素 1 是否在集合 myset 中,返回 1 表示存在
127.0.0.1:6379> sismember myset “one”
(integer) 1
// 判断元素 3 是否在集合 myset 中,返回 0 表示不存在
127.0.0.1:6379> sismember myset “three”
(integer) 0
// 新建一个新的集合 yourset
127.0.0.1:6379> sadd yourset “1”
(integer) 1
127.0.0.1:6379> sadd yourset “2”
(integer) 1
127.0.0.1:6379> smembers yourset
1) “1”
2) “2”
// 对两个集合求并集
127.0.0.1:6379> sunion myset yourset
1) “1”
2) “one”
3) “2”
4) “two”
对于集合的使用,也有一些常见的方式,比如,QQ 有一个社交功能叫做“好友标签”。
2.4 有序集合 sorted sets
redis 还提供了有序集合(sorted sets)。有序集合中的每个元素都关联一个序号(score),这便是排序的依据。很多时候,我们都将 redis 中的有序集合叫做 zsets,这是因为在 redis 中,有序集合相关的操作指令都是以 z 开头的,比如 zrange、zadd、zrevrange、zrangebyscore 等等
// 新增一个有序集合 myzset,并加入一个元素 baidu.com,给它赋予的序号是 1:
127.0.0.1:6379> zadd myzset 1 baidu.com
(integer) 1
// 向 myzset 中新增一个元素 360.com,赋予它的序号是 3
127.0.0.1:6379> zadd myzset 3 360.com
(integer) 1
// 向 myzset 中新增一个元素 google.com,赋予它的序号是 2
127.0.0.1:6379> zadd myzset 2 google.com
(integer) 1
// 列出 myzset 的所有元素,同时列出其序号,可以看出 myzset 已经是有序的了。
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) “baidu.com”
2) “1”
3) “google.com”
4) “2”
5) “360.com”
6) “3”
// 只列出 myzset 的元素
127.0.0.1:6379> zrange myzset 0 -1
1) “baidu.com”
2) “google.com”
3) “360.com”
2.5 哈希 hashes
hashes 存的是字符串和字符串值之间的映射,比如一个用户要存储其全名、姓氏、年龄等等,就很适合使用哈希
// 建立哈希,并赋值
127.0.0.1:6379> HMSET user username antirez password P1pp0 age 34
OK
// 列出哈希的内容
127.0.0.1:6379> HGETALL user
1) “username”
2) “antirez”
3) “password”
4) “P1pp0”
5) “age”
6) “34”
// 更改哈希中的某一个值
127.0.0.1:6379> HSET user password 12345
(integer) 0
// 再次列出哈希的内容
127.0.0.1:6379> HGETALL user
1) “username”
2) “antirez”
3) “password”
4) “12345”
5) “age”
6) “34”
三、Redis 持久化 -RDB 和 AOF
持久化不属于入门范围,找了几篇比较好的文章,有兴趣欢迎阅读
redis 持久化 RDB 和 AOF
[Redis 持久化 RDB 和 AOF 相比较]
[redis 系列:RDB 持久化与 AOF 持久化]
四、redis.conf 文件配置项
redis.conf 配置项说明如下:
Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程 daemonize no
当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定 pidfile /var/run/redis.pid
指定 Redis 监听端口,默认端口为 6379,这里有个故事,因为 6379 在手机按键上 MERZ 对应的号码,而 MERZ 取自意大利歌女 Alessia Merz 的名字 port 6379
绑定的主机地址 bind 127.0.0.1
当客户端闲置多长时间后关闭连接,如果指定为 0,表示关闭该功能 timeout 30
指定日志记录级别,Redis 总共支持四个级别:debug、verbose、notice、warning,默认为 verboseloglevel verbose
日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/nulllogfile stdout
设置数据库的数量,默认数据库为 0,可以使用 SELECT <dbid> 命令在连接上指定数据库 iddatabases 16
指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 save <seconds> <changes> Redis 默认配置文件中提供了三个条件:`save 900 1 save 300 10 save 60 10000` 分别表示 900 秒(15 分钟)内有 1 个更改,300 秒(5 分钟)内有 10 个更改以及 60 秒内有 10000 个更改。
指定存储至本地数据库时是否压缩数据,默认为 yes,Redis 采用 LZF 压缩,如果为了节省 CPU 时间,可以关闭该选项,但会导致数据库文件变的巨大 rdbcompression yes
指定本地数据库文件名,默认值为 dump.rdbdbfilename dump.rdb
指定本地数据库存放目录
`dir ./`
设置当本机为 slav 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步
`slaveof <masterip> <masterport>`
当 master 服务设置了密码保护时,slav 服务连接 master 的密码
`masterauth <master-password>`
设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭
`requirepass foobared`
设置同一时间最大客户端连接数,默认无限制,Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息 maxclients 128
指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 Key,当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis 新的 vm 机制,会把 Key 存放内存,Value 会存放在 swap 区
`maxmemory <bytes>`
指定是否在每次更新操作后进行日志记录,Redis 在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis 本身同步数据文件是按上面 save 条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为 noappendonly no
指定更新日志文件名,默认为 appendonly.aofappendfilename appendonly.aof
指定更新日志条件,共有 3 个可选值:
no:表示等操作系统进行数据缓存同步到磁盘(快)always:表示每次更新操作后手动调用 fsync() 将数据写到磁盘(慢,安全)everysec:表示每秒同步一次(折衷,默认值)appendfsync everysec
指定是否启用虚拟内存机制,默认值为 no,简单的介绍一下,VM 机制将数据分页存放,由 Redis 将访问量较少的页即冷数据 swap 到磁盘上,访问多的页面由磁盘自动换出到内存中 vm-enabled no
虚拟内存文件路径,默认值为 /tmp/redis.swap,不可多个 Redis 实例共享 vm-swap-file /tmp/redis.swap
将所有大于 vm-max-memory 的数据存入虚拟内存, 无论 vm-max-memory 设置多小, 所有索引数据都是内存存储的 (Redis 的索引数据 就是 keys), 也就是说, 当 vm-max-memory 设置为 0 的时候, 其实是所有 value 都存在于磁盘。默认值为 0vm-max-memory 0
Redis swap 文件分成了很多的 page,一个对象可以保存在多个 page 上面,但一个 page 上不能被多个对象共享,vm-page-size 是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page 大小最好设置为 32 或者 64bytes;如果存储很大大对象,则可以使用更大的 page,如果不 确定,就使用默认值 vm-page-size 32
设置 swap 文件中的 page 数量,由于页表(一种表示页面空闲或使用的 bitmap)是在放在内存中的,,在磁盘上每 8 个 pages 将消耗 1byte 的内存。vm-pages 134217728
设置访问 swap 文件的线程数, 最好不要超过机器的核数, 如果设置为 0, 那么所有对 swap 文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为 4vm-max-threads 4
设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启 glueoutputbuf yes
指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法 `hash-max-zipmap-entries 64 hash-max-zipmap-value 512`
指定是否激活重置哈希,默认为开启 activerehashing yes
指定包含其它的配置文件,可以在同一主机上多个 Redis 实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 include /path/to/local.conf
什么是守护进程?守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离于终端是为了避免进程被任何终端所产生的信息所打断,其在执行过程中的信息也不在任何终端上显示。由于在 linux 中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会自动关闭。
五、事务处理
MULTI、EXEC、DISCARD、WATCH 指令构成了 redis 事务处理的基础
MULTI 用来组装一个事务;
EXEC 用来执行一个事务;
DISCARD 用来取消一个事务;
WATCH 用来监视一些 key,一旦这些 key 在事务执行之前被改变,则取消事务的执行。