Redis教程

OverView

正文。

小贴士:这里将对正文中的某些词汇进行解释。

扩展: 这里是作者建议的内容,和编程方面的延伸。可以跳过阅读。

示例:这里是帮助读者理解而写的示例。

注意 提示读者需要注意的事项。


理论篇

什么是Redis?[1]

REmote DIctionary Server(Redis) 是一个由SalvatoreSanfilippo写的key-value(键值对)存储系统。
Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。[详细见表一]
它通常被称为数据结构服务器,因为值(value)可以是字符串(String), 哈希(Map), 列表(list), 集合(sets) 和有序集合(sorted sets)等类型。

小贴士:[2]Redis中的数据类型
哈希(Map hashmap):散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。
列表(list):列表是一种数据项构成的有限序列,即按照一定的线性顺序,排列而成的数据项的集合。(redis中使用双向链表实现)
集合(sets):和中学时学习的概念是相似的。特点是集合中元素不能重复是唯一的。切内部是无序的
有序集合(sorted sets):也是一种集合,但是内部数据是经过排序的。

示例:  
比如使用json表示:  
哈希表:{key1:value1,key2:value2, ... ,keyn:valuen} 在这里的key和value是一一对应的关系,而且是函数关系。也就是说,key1 ... keyn 都是唯一的。  
列表:['a','a','b','c','e']。注意这里的'a'是可以重复的这个在列表中是允许的,而且这里的顺序是不能变的,一旦顺序变了就不是同一个列表了。  
集合:{v1,v2, ... ,vn}。这里v1到vn都是唯一的。也就是说{a,a}不是一个集合。这里集合的顺序是无关的,于是{a,b}和{b,a}在概念上可以视为一个集合  
有序集合:{1,2,3, ... ,n} 这里1到n当然是不能重复的。其次他中元素是按照某种规则排序的。比如大小等。一旦顺序不一致在其中也不视为同一个有序集合了。

注意 在引用列表中的[2]连接中有更加详细的说明。为了方便阅读可以跳过但是建议在适当是时候阅读它。

特点和优势

特点

  • Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
  • Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

优势

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

小贴士:
publish/subscribe :订阅发布模式。阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象。这个主题对象在自身状态变化时,会通知所有订阅者对象,使它们能够自动更新自己的状态。他是设计模式中的一种。Redis支持了这种模式。
阅读了解更多订阅发布模式[3]订阅发布模式介绍。或者看有关Redis下订阅发布模式的支持[4]。


实践篇

安装Redis

windows[5]

下载地址
Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择。

注意 操作系统位数可以在我的电脑中的右键属性中看到。如果不知道就试试64位。Redis版本要最好和公司生产环境使用的发行版本一直,保证bug与问题可以重现。

压缩包到 C 盘,解压后,将文件夹重新命名为 redis。(当然不安装到c盘也是允许的)
打开一个 cmd 窗口 使用cd命令切换目录到 C:\redis 运行 redis-server.exe redis.windows.conf 。

1
2
3
$ cd c:/redis
$ redis-server.exe redis.windows.conf
## 这里的 redis.windows.conf 是Redis启动的配置文件 当这里不输入时 默认使用这个配置打开Redis服务。

如果想方便的话,可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的配置。
如果运行成功了。会出现和下面大致相似的返回。

成功图片
简单解释一下Port是端口。PID是进程号。
注意 服务启动后命令行不能关闭。

扩展:
即使在windows下任然有比较好的终端解决方案。可以下载git使用git 的bash。或者直接使用docker。在docker中启动Redis或许是最优雅的解决方案。不过我个人建议开发的话换成macOS。

MacOS

1
$ brew install redis

搞定了!

命令行

注意 在类unix系统中,redis-cli是作为一个命令存在的。它的作用是启动一个与Redis的交互的命令行模式。Windows用户要双击redis-cli.exe 可执行文件进入,这里是下面命令执行的前提。

创建键(key)

使用set key value的方法就可以建立一组键值对了。比如:

1
set zzh goodboy

这里zzh就被设置成了goodboy了。这里在此运行set命令可以把key zzh设置成其他的值,可以自己试试。

获取key

使用get key可以得到key被设置的value的值。

使用dump key可以得到序列化后的value的值。

使用 exists key可以查询key是否存在。

删除key

使用del key删除key

重命名key

RENAME key newkey 将key改为newkey 的名字。如果newkey存在的话,则newkey的内容会丢失。
RENAMENX key newkey仅当 newkey 不存在时,将 key 改名为 newkey.

设置过期时间

这里的的key-value有类似于缓存的机制可以在一定时间过后自动的消亡。所以可以设置过期时间。
EXPIRE key seconds为给定 key 设置过期时间。时间为秒。
EXPIREAT key timestampEXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
PEXPIRE key milliseconds设置 key 的过期时间以毫秒计。
PEXPIREAT key milliseconds-timestamp设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
PERSIST key移除 key 的过期时间,key 将持久保持。

查询过期时间

PTTL key 以毫秒为单位返回 key 的剩余的过期时间。
TTL key以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。

查询key

KEYS params可以用keys加上查询条件的方式。比如我要查询所有以aba开头的key。

1
keys aba*


实用工具介绍

接下来将要介绍使用RedisDesktopManager(以下简称RDM) 使用教程。RDM是一款开源的redis管理GUI。

下载安装。

下载地址

连接服务器

  1. 点击新建连接。让rdm新建一个到服务器的连接

新建位置

  1. 填写选项。点击完成。

填写连接选项

name: 连接的名称,自己取的不会影响连接的属性,尽量起有意义的值,比如环境,开发环境还是测试环境可以用dev和test表示。
host: redis服务启动的ip地址或者域名。本机可以是localhost或者172.0.0.1。建议使用域名的方式,这样修改host的域名配置节省大量时间。
port: redis 服务启动的端口号。
Auth:获取权限的秘钥。可以理解登录的密码。本地服务启动时默认没有密码可不填。其他环境需要联系管理员获取。

在某个库下新建key

  1. 选中某一个库,右键,选择新建key。
  2. 在新建中可以写key的类型和key的值。

添加key

查询key

  1. 一样的选择一个库比如db0然后右键有一个筛选。(filter 英文为过滤器)
  2. 现在他会提示输入一个’regex’。也就是说他支持正则表达式查询。这里可以先理解为正常关键字查询即可。
  3. 查完完你会发现列表中key变少了。怎么办?同样选择库右键,有一个还原筛选即可调回所有的key。

扩展:
regex 正则表达式。是一种通用的计算机技术。甚至可以专门拿一本书来学。它可以实现文本中的模式配置。
比如以xx开头,以xx结尾。以xx开头但是不包含yy结尾。以字母开头,以数字结尾。这些你能想到的模式都可以表示出来。
学习正则是一个庞大的工程。建议在使用时查询规则来尝试。先学习其最基本的语法.[7]

修改删除操作

  1. 选中一个key在其右侧就有一系列的操作方法。如下图:
    操作key

redis + DB 的讨论

现在一般应用已经放弃了menchace+DB的组合而投身到redis+DB的阵营中来。特别是那种缓存需求量特别大,切需要管理的应用。
首先redis具有缓存的性质。key-value存在内存中读写速度快,而且可以设置消亡时间,这都符合一个缓存的要求。
但是memchae和redis不同,一断电,一重启,所有的键值对都将消失。redis则可以优雅的继续正常工作,因为redis提供了数据持久化的解决方案。要知道在缓存服务器重启的一瞬间,请求key的IO对数据库的压力是恐怖的。那么这里为什么说到了数据库呢?这一般与redis到DB的二层结构有关。
我们模拟一个应用场景。一个webapp要调用用户的基本信息。但是由于一开始的公司发展原因,用户的基本信息不一张表里面,甚至不在一个库里面。比如要调取用户的购买的会员要走支付和crm的接口。这两个还算正常的,有的情况下一个信息接口要调用7、8个部门,而且算下来有10个sql之多。这样一个接口的速度可能慢的夸张。更要命的是,这样的接口一开始数据变化是比较大的,但是一旦用户成为长期用户这些信息将很少改变。可是使用这样接口的场景却非常的多。怎么办呢?
一般(以java或者php举例)情况下,程序员使用缓存的办法来解决。当有人第一次请求这个接口的时候,执行sql查询数据库。现在将查出来的数据放在缓存中(比如Redis服务中)。现在有意思了,在第二次请求的时候,程序会先检查key是否存在,如果存在,直接获取value就可以了。这样非常快,因为数据在内存中。这样大大的提高的应用的速度,减少了数据库IO的压力。
那么你或许会问如果数据改变了呢?这样读出来的缓存中的value和数据库中的数据不是不一致了吗?对这就是一种bug。一般可以手动的删除key。让程序在请求的时候重新走sql获取值,生成新key就可以了。或者更彻底的方法是在开发内部形成一套缓存key的生成规范,在修改数据的时候,使用程序删除key就可以了。

扩展:
上面的例子包含一个通用的知识—分布式设计。使用多级缓存的方式只不过是其中很小的一部分。不过这是架构师的研究范围。
这里有一片非常简短的基础的博文的介绍.[8]

这里还设计到了两个常用的概念。颗粒度和命中率。
颗粒度指的是一个key对应value所包含内容的大小,是一个相对的概念。比如一个key缓存了一整个网页,的颗粒度要比访问只缓存了数据段的颗粒度要大。在保证命中率高的情况下,我们希望颗粒度尽量的大一些,这证明了,资源的利用效率比较高。那么命中率是什么呢?指的是单位时间内请求同一个key的次数。
考虑这样一个问题:数据a一分钟被请求10次,b被请求1000次。那么单独的为两个数据设置key就是合理的。如果使用hashmap为两数据设置联合的缓存可能就浪费了请求数据时IO的性能。
注意!然而一般情况下对性能的影响不是特别大,如果请求次数不上到一定级别的话(但是讲道理到了一定数量级了,性能瓶颈就不由程序员这样解决了)是没有多大差别的。

本文使用是叫做markdown的语法写成的。这里有其教程[9]

引用表

  • [1] Redis基础介绍
  • [2]Redis中的数据类型
  • [3]订阅发布模式介绍
  • [4]Redis下订阅发布模式的支持
  • [5]Window下的安装教程
  • [6]RedisDesktopManager官方使用手册
  • [7]正则表达式基本语法
  • [8]初认分布式知识
  • [9]markdown语法教程

附录:

表1:Redis 支持的语言表

ActionScript C C++ C# Clojure
Common Lisp Dart Erlang Go Haskell
Haxe Io Java Node.js Lua
Objective-C Perl PHP Pure Data Python
R Ruby Scala Smalltalk Tcl

配置文件参数说明:

redis.conf 配置项说明如下:
1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
daemonize no
2. 当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定(这个会和操作系统有关)
pidfile /var/run/redis.pid
3. 指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字
port 6379
4. 绑定的主机地址
bind 127.0.0.1
5.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
timeout 300
6. 指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
loglevel verbose
7. 日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
logfile stdout
8. 设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
databases 16
9. 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
save <seconds> <changes>
Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000
分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。

10. 指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
rdbcompression yes
11. 指定本地数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
12. 指定本地数据库存放目录
dir ./
13. 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
slaveof <masterip> <masterport>
14. 当master服务设置了密码保护时,slav服务连接master的密码
masterauth <master-password>
15. 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭
requirepass foobared
16. 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
maxclients 128
17. 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
maxmemory <bytes>
18. 指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendonly no
19. 指定更新日志文件名,默认为appendonly.aof
 appendfilename appendonly.aof
20. 指定更新日志条件,共有3个可选值: 
no:表示等操作系统进行数据缓存同步到磁盘(快) 
always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全) 
everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec

21. 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)
 vm-enabled no
22. 虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
 vm-swap-file /tmp/redis.swap
23. 将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0
 vm-max-memory 0
24. Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值
 vm-page-size 32
25. 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。
 vm-pages 134217728
26. 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4
 vm-max-threads 4
27. 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
glueoutputbuf yes
28. 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
29. 指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)
activerehashing yes
30. 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
include /path/to/local.conf

我将一直的无知与迷惑,我是黄油香蕉君,再见。

给作者买杯咖啡吧。喵~