Redis简介redis
Redis是REmote DIctionary Server(远程字典服务器)缩写。数据库
以字典结构存储数据,并容许其余应用经过TCP协议读写字典中的内容。缓存
支持的键值数据类型有:字符串类型string、散列类型hash、列表类型list、集合类型set、有序集合类型zset。ruby
内存存储与持久化服务器
Redis能够为每一个健设置生存时间(Time To Live,TTL),生存时间到期后会被自动删除。能够做为缓存系统使用。网络
在性能上Redis是单线程模式,而Memcached支持多线程,因此在多核服务器上后者性能更高一些。数据结构
Redis是使用C语言开发的。多线程
Redis多数据库ide
一个Redis实例提供了多个用来存储数据的字典,客户端能够指定将数据存储在哪一个字典中。函数
每一个字典相似于一个独立的数据库。每一个字典对外以一个从0开始的递增数字命名,默认支持16个,不支持自定义数据库名字。
通常不一样应用的数据应该使用不一样的Redis实例存储。
Redis不区分命令大小写
Redis提供的全部命令都是原子操做(atomic operation)。
Redis对于键的命名并无强制要求,较好的实践用“对象类型:对象ID:对象属性”来命名一个键,如使用键 user:1:friends来存储ID为1的用户的好友列表。
Redis各个数据类型都不支持数据类型的嵌套。
—————————————————————————————————————
Redis安装
Redis约定版本号(即第一个小数点后的数字)为偶数的版本是稳定版(如2.四、2.6),奇数版本是非稳定版(如2.五、2.7)。
下载安装:
wget http://download.redis.io/redis-stable.tar.gz
tar xzf redis-stable.tar.gz
cd redis-stable
make
Redis没有其余外部依赖。
Redis运行
启动Redis:1.直接启动(命令:redis-server);2.经过初始化脚本启动;
中止Redis:redis-cli SHUTDOWN (kill命令效果与发送SHUTDOWN命令同样)
Redis命令行客户端
redis-cli (Redis Command Line Interface)是Redis自带的基于命令行的Redis客户端。
Redis配置
Redis提供了一个配置模板 redis.conf,位于源代码目录的根目录下。
—————————————————————————————————————
Redis的数据结构
字符串类型
简介:能够存储任何形式的字符串,一个字符串类型键容许存储的数据的最大容量是512MB。
命令:SET key value / GET key
散列类型
简介:散列类型适合存储对象,使用对象类别和ID构成键名,使用字段表示对象的属性,而字段值则存储属性值。
命令:HSET key field value / HGET key field ( HMSET key field value [fielld value ...] / HMGET key field [field ...])
列表类型
简介:列表类型能够存储一个有序的字符串列表,经常使用的操做是向列表的两端添加元素,或者得到列表的某一个片断。列表类型内部是使用双向链表实现的,向两端添加删除元素较快,但经过索引访问元素较慢。
命令:LPUSH key value [value ...] / RPUSH key value [value ...] / LPOP key / RPOP key / LRANGE key start stop
集合类型
简介:集合中每一个元素都是不一样的,且没有顺序。经常使用操做是向集合中加入或删除元素、判断某个元素是否存在等,集合类型在Redis内部是使用值为空的散列表实现的,因此这些操做较快。集合类型键之间还能够进行并集、交集和差集运算。
命令:SADD key member [member ...] / SREM key member [member ...] / SDIFF key [key ...] / SINTER key [key ...] / SUNION key [key ...]
有序集合类型
简介:在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数,按照这个分数对每一个元素进行排序。咱们进行得到分数最高(或最低)的前N个元素、得到指定分数范围内的元素等于分数有关的操做。虽然集合中每一个元素都是不一样的,可是他们的分数却能够相同。有序集合能够调整某个元素的为止,经过更改该元素的分数。
命令:ZADD key score member [score member ...] / ZSCORE key member / ZRANGE key start stop [WITHSCORES] / ZREVRANGE key start stop [WITHSCORES]
—————————————————————————————————————
Redis的事务:
Redis中的事务(transaction)是一组命令的集合。事务同命令同样都是Redis的最小执行单元,一个事务中的命令要么都执行,要么都不执行。
事务的原理是先将属于一个事务的命令发送给Redis,而后再让Redis依次执行这些命令。
事务示例:
redis> MULTI
OK
redis> SADD "user:1:following" 2
QUEUED
redis> SADD "user:2:followers" 1
QUEUED
redis> EXEC
1) (integer) 1
2) (integer) 1
上面的代码演示了事务使用方式。
首先MULTI命令告诉Redis,下面的命令属于一个事务,先缓存不执行;
Redis回答OK;
发送两个SADD命令,Redis没有执行命令,而是放入等待队列QUEUED;
要执行的命令发送完毕后,发送EXEC命令告诉Redis能够执行了;
Redis将等待执行的命令按照发送顺序执行,并依次返回执行结果。
故障处理:
若是在发送EXEC命令前客户端断线,则Redis会清空事务队列,全部命令都不执行;但若是已经发送了EXEC命令后客户端断线,则Redis会执行全部命令的。
Redis的事务还能保证一个事务内的命令依次执行而不被其余命令插入。
若是一个事务中的某个命令执行出错,Redis会如何处理?
当在命令执行前出现错误,如语法错误,Redis会直接返回错误,全部命令都不执行;
当在命令执行中出现错误,如执行某个命令时运行时错误,因为执行前没法发现,Redis会接收并执行,全部命令都会执行。
Redis的事务没有关系数据库事务提供的回滚(rollback)功能。
WATCH命令
咱们已经知道在一个事务中只有当全部命令都依次执行完后才能获得每一个结果的返回值,但是有些状况下须要先得到一条命令的返回值,而后再根据这个值执行下一个命令。
上面的状况在使用事务来实现时会产生竞态条件。事务家族的另外一个成员WATCH,该命令能够监控一个或多个键,一旦其中一个键被修改(或删除),以后的事务就不会执行了。监控一直持续到EXEC命令(事务中的命令是在EXEC以后才执行的,因此MULTI命令后能够修改WATCH监控的键值)。
因为WATCH命令的做用只是当被监控的键值被修改后阻止以后一个事务的执行,而不能保证其余客户端不修改这一键值,因此咱们须要在EXEC执行失败后从新执行整个函数。
生存时间
有时效的数据,好比限时优惠活动、缓存或验证码等,过了必定的时间就须要删除这些数据。
Redis可使用EXPIRE命令设置一个键的生存时间,到时候后Redis会自动删除它。默认不设置时间的为永久存在。
命令:EXPIRE key seconds //上述命令标识key键在seconds秒后会被删除,
实现访问频率的限制:例如要限制每一个用户每分钟最多能访问100次。
思路:每一个用户存储“rate.limiting:用户ip”字符串类型键,用户每次访问则递增,第一次访问时要设置该键的生存时间为1分钟。每次用户访问都读取键值,判断超过100则限制。该键每分钟会自动删除,用户下一分钟能够从新计算限制值。
实现缓存:为了提升网站的负载能力,经常须要将一些访问频率较高可是对CPU或IO资源消耗较大的操做的结果缓存起来,并但愿让这些缓存过一段时间自动过时。
能够经过给键设置生存时间的方式来实现。每次访问先查询缓存,有则返回缓存值,没有则从新计算并放缓存并同时设置缓存生存时间。
可是服务器的内存是有限的,Redis能使用的内存也是有限的。缓存键的生存时间设置的过长会致使Redis占满内存,设置太短会致使缓存命中率太低。实际开发中会发现很难为缓存键设置合理的生存时间,为此能够限制Redis可以使用的最大内存,并让Redis按照必定的规则淘汰不须要的缓存键,这种方式在只将Redis用做缓存系统时很是实用。
—————————————————————————————————————
Redis的排序
SORT命令:
SORT命令能够对列表类型、集合类型和有序集合类型键进行排序,而且能够完成与关系数据库中的链接查询相相似的任务。
除了能够排列数字外,SORT命令还能够经过ALPHA参数实现按照字典顺序排列非数字元素。
SORT命令默认是按照从小到大的顺序排列,若是想从大到小的顺序排列,须要使用DESC参数。
SORT命令实现分页:经过支持LIMIT参数来返回指定范围的结果。用法和SQL语句同样,LIMIT offset count,表示跳过前offset个元素并获取以后的count个元素。
BY参数:
通常存储数据时都以对象的ID为标识,但更多的时候咱们但愿根据ID对应的对象的某个属性进行排序。
BY参数的语法为“BY参考键”。参考键能够是字符串类型的键或者是散列类型键的某个字段(表示为键名->字段名)。
若是提供了BY参数,SORT命令将再也不依据元素自身的值进行排序,而是对每一个元素使用元素的值替换参考键中的第一个“*”并获取其值,而后依据该值对元素排序。
例如:SORT tag:ruby:posts BY post:*->time DESC
GET参数:
GET参数不影响排序,它的做用是使SORT命令的返回结果再也不是元素自身的值,而是GET参数中指定的键值。
例如:SORT tag:ruby:posts BY post:*->time DESC GET post:*->title
STORE参数:
SORT命令会直接返回排序结果,若是但愿保持排序结果,可使用STORE参数。STORE参数经常使用来结合EXPIRE命令缓存排序结果。示例伪代码:
#判断是否存在以前排序结果的缓存
$isCacheExists = EXISTS cache.sort
if $isCacheExists is 1
#若是存在则直接返回
return LRANGE cache.sort, 0, -1
else
#若是不存在,则使用SORT命令排序并将结果存入cache.sort键中做为缓存
$sortResult = SORT some.list STORE cache.sort
#设置缓存的生存时间为10分钟
EXPIRE cache.sort, 600
#返回排序结果
return $sortResult
—————————————————————————————————————
消息通知
任务队列:即传递任务的队列,能够借助任务队列实现通知的过程。
任务队列的好处:松耦合,生产者和消费者无需知道彼此的实现细节;易于扩展消费者,能够有多个并能够分布在不一样的服务器中。
Redis实现任务队列:使用Redis的列表类型,以及其LPUSH和RPOP命令实现队列的概念。BRPOP和BLPOP还实现了没有元素则阻塞机制。
优先级队列:优先消费紧急的消息。
可经过使用BRPOP命令实现,BRPOP能够同时接收多个键,格式如:BRPOP key [key ...]
意义是同时检测多个键,若是全部键都没有元素则阻塞,若是其中有一个键有元素则会从该键中弹出元素。若是多个键都有元素则按照从左到右的顺序取第一个键中的一个元素。
如此一来将须要优先处理的消息的键放消费顺序的前面,这样无论后面有没有元素,挤压了多少,只要前面的有元素则会优先处理。
发布/订阅模式:分两种角色,分别是发布者和订阅者。订阅者能够订阅一个或若干个频道(channel),而发布者能够向指定的频道发送消息,全部订阅此频道的订阅者都会收到此消息。
命令:PUBLISH channel message / SUBSCRIBE channel [channel ...]
按照规则订阅:使用PSUBSCRIBE命令订阅指定的规则。规则支持glob风格通配符格式。如:PSUBSCRIBE channel.?*
—————————————————————————————————————
Redis的管道
客户端和Redis使用TCP协议链接。不管是客户端向Redis发送命令仍是Redis向客户端返回命令的执行结果,都须要通过网络传输,这两部分的总耗时称为往返时延。在执行多个命令时每条命令都须要等待上一条命令执行完才能执行,即便命令不须要上一条命令的执行结果。
Redis的底层通讯协议对管道(pipelining)提供了支持。经过管道能够一次性发送多条命令并在执行完后一次性将结果返回,当一组命令中每条命令都不依赖于以前命令的执行结果时就能够将这组命令一块儿经过管道发出。管道经过减小客户端与Redis的通讯次数来实现下降往返时延累计值得目的。
—————————————————————————————————————
优化Redis的存储空间
Redis是一个基于内存的数据库,全部的数据都存储在内存中,因此优化存储、减小内存空间占用对成本控制来讲很是重要。
1.精简键名和键值;
2.内部编码优化:Redis为每种数据类型提供了两种内部编码方式,而且Redis会根据实际状况自动调整。
数据类型 内部编码方式 OBJECT ENCODING命令结果
字符串类型 REDIS_ENCODING_RAW raw
REDIS_ENCODING_INT int
散列类型 REDIS_ENCODING_HT hashtable
REDIS_ENCODING_ZIPLIST ziplist
列表类型 REDIS_ENCODING_LINKEDLIST linkedlist
REDIS_ENCODING_ZIPLIST ziplist
集合类型 REDIS_ENCODING_HT hashtable
REDIS_ENCODING_INTSET intset
有序集合类型 REDIS_ENCODING_SKIPLIST skiplist
REDIS_ENCODING_ZIPLIST ziplist
共享对象:Redis启动后会预先创建10000个分别存储从0到9999这些数字的redisObject类型变量做为共享对象,若是要设置的字符串键值在这10000个数字内(如 SET key1 123)则能够直接引用共享对象而不用再创建redisObject了。因而可知,使用字符串类型键存储对象ID这样小数字是很是节省存储空间的,Redis只需存储键名和一个对共享对象的引用便可。
REDIS_ENCODING_ZIPLIST编码类型是一种紧凑的编码格式,它牺牲了部分读取性能以换取极高的空间利用率,适合在元素较少时使用。
—————————————————————————————————————
脚本
Redis在2.6版推出了脚本功能,容许开发者使用Lua语音编写脚本传到Redis中执行,脚本中能够调用大部分的Redis命令。使用脚本的好处以下:
1.减小网络开销;多个命令能够放到脚本中发送一个请求便可,减小网络往返时延。
2.原子操做;整个脚本将做为一个总体执行,中间不会被其余命令插入。
3.复用;脚本会永久存储在Redis中,其余客户端也能够复用。
Lua是一个高效的轻量级脚本语言。Lua在葡萄牙语种是“月亮”的意思,它的徽标形似卫星,寓意着Lua是一个“卫星语音”,可以方便的嵌入到其余语言中使用。
—————————————————————————————————————
持久化:经过持久化功能,Redis保证了即便在服务器重启的状况下也不会损失(或少许损失)数据。
RDB方式;
AOF方式(Append Only File);
—————————————————————————————————————
复制:
若是数据存储在一台服务器上,当硬盘出现故障时,也会致使数据丢失。
为了不单点故障,Redis提供了复制功能能够自动实现同步的功能,将数据库复制多个副本以部署在不一样的服务器上。
经过复制能够实现读写分离以提升服务器的负载能力。
Redis数据库分两类:主数据库、从数据库;
主数据库能够进行读写操做,当发生写操做时自动将数据同步给从数据库;
从数据库通常是只读的,并接收主数据库同步过来的数据。
在Redis中使用复制功能很是简单,只需在从数据库的配置文件中加入“slaveof 主数据库IP 主数据库端口”便可,主数据库无需进行任何配置。
除了使用配置文件设置slaveof参数,还能够在运行时使用SLAVEOF命令修改。
Redis的复制原理:
当一个从数据库启动后,会向主数据库发送SYNC命令,主数据库接收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和全部缓存的命令发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。当主从数据库断开重连后会从新执行上述操做,不支持断点续传。
从数据库不只能够接收主数据库的同步数据,本身也能够同时做为主数据库存在。
例如:A有B和C两个从,B有D和E两个从;当向B写数据时只能同步到D和E,不能同步到A或C。
持久化操做很是耗时,为了提升性能,能够经过复制功能创建一个(或若干个)从数据库,并在从数据库中启用持久化,同时在主数据库禁用持久化。
当从数据库崩溃时重启后主数据库会自动将数据同步过来,因此无需担忧数据丢失。
当主数据库崩溃时,须要在从数据库中使用SLAVEOF NO ONE命令将从数据库提高成主数据库继续服务,并在原来的主数据库启动后使用SLAVEOF命令将其设置成新的主数据库的从数据库,便可将数据同步回来。
—————————————————————————————————————
耗时命令日志:
当一条命令执行时间超过限制时,Redis会将该命令的执行时间等信息加入耗时命令日志(slow log)以供开发查看。
能够经过配置文件的slowlog-log-slower-than参数设置这一限制,单位是微妙(1000000微秒=1秒),默认值是10000。
耗时命令日志存储在内存中,能够经过配置文件的slowlog-max-len参数来限制记录的条数。