Redis详细介绍

来源:互联网 发布:mac os破解版 编辑:程序博客网 时间:2024/06/05 10:31

  • 基础特征
  • Redis使用场景
  • Redis存储方式
  • Redis内存管理
  • Redis读写分离
  • Redis通信协议
  • Redis事务
  • Redis集群
  • 通过keepalived实现高可用方案

Redis
Redis(Remote Dictionary Server)是一个基于内存的高性能key/value数据库,与Memcached一样,为了保证效率,数据都是缓存在内存中。最大的区别是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。Redis的出现,很大程度补偿了Memcached这类键值存储的不足,在部分场合可以对关系数据库起到很好的补充作用。

1 基础特征

Redis在很多方面与Memcached具有相似的特征,更多场景是作为Memcached的替代出现的,但它又具有更为优秀的一面。
(1)支持数据的持久化
Memcached把数据全部存放在内存之中,服务器重启后数据会消失,而且数据不能超过内存大小;而在Redis中不是有所的数据都一直存储在内存,可以根据需要将内存中的部分数据保存在磁盘中,以保证数据的持久化,服务器遇到重启情况,数据很快可以恢复使用。
(2)支持多种数据结构
Redis不仅仅支持简单的key/value类型数据,同时还提供list,set、zset和hash等类型的数据,所有的数据类型都具有push/pop、add/remove、执行服务端的并集、交集等操作,这些操作都是具有原子性的,它还支持各种不同的排序能力。
(3)支持主从复制
Redis的主从复制实现简单却功能强大,支持多级Master/Slave,一个master支持多个slave连接,slave可以接受其他slave的连接;主从同步时master和slave都是非阻塞的。Redis主从复制可以用来实现数据的持久性,slave作为master的扩展,提供一些read-only的服务,也可以将数据持久化放在slave做,从而提升master的性能。

2 Redis使用场景

(1)访问计数
利用Redis的原子技术INCR、INCRBY等命令实现最典型的Redis应用。如文章的浏览技术,最典型的浏览转提交的场景,每次浏览都意味着一次提交操作。Key一般是id(可能是字符串或数字),value是数字,操作类型有递增(INCRBY)和获取(GET),可以支持数据过期,可以支持批量递增和批量获取并高性能的支持。
如果key的数目非常大,推荐使用Redis的Hash数据类型,利用多级key的思路。具体方式是:将原来的key拆分为两部分,如12345678里的高位12345作为hash的key,地位678作为hash结构内部的key。这样内存消耗可以降低到原来的1/3左右,因为hash内部会对数据做压缩(Hash-zipmap)。
(2)用户Profile
可利用Hash,List等数据结构实现使用范围非常广的场景,如用户的配置(Profile)信息、在线用户的音乐播放记录等。该类数据的特点是浏览量大,更新量大或二者皆有,而数据往往比较短,可能是一组标记或者一组id,操作上可以局部修改,整体获取等。
如果是简单的标记位,可以把Redis的string看做一个标记位数组,支持按bit获取和放置。如将用户id做key,第2个bit存储用户是否会员,第三个bit标记用户的性别;如果是三级结构key->field->value,则需要使用Redis的hash结构。
如没有排序需求,可以使用Redis的List;如果有排序需求,可以使用Redis的Sorted Set。
(3)排行榜
利用Sorted Set数据结构实现排行榜功能。比如常见的用户积分排名、文库里文档的下载排行以及常见的拉链类型的应用。榜单长度可长可短,榜单个数也可大可小。该类数据操作的特点是经常在榜单里添加、删除、修改或递增Item,获取某个Item的排序名次。数据支持分页获取,并且支持倒排或正排。
这种场景需要使用Redis的Sorted Set数据类型。该数据类型支持超长拉链和高性能的操作。
(4)Cache缓存
从功能上,可以把Redis当做Cache来用并且Redis内部支持多种淘汰方式,如:LRU、Random或TTL等,但是Redis作为Cache有两点不足:为了节省内存,Redis的LRU和TTL的算法并不精确。以LRU为例,它没有记录完整的LRU链表,而是采用抽样的办法,先随机选中N个候选,再从中选择最近未访问的key,再淘汰。
由于使用的内存分配器和Memcached的Slab机制特点的不同,Redis在大value上的内存使用率不高。因此,如果是Cache类是需求,使用memcache服务更合适。
(5)缓冲区队列
可利用List,Pub/Sub实现简单的队列,或发布/订阅结构,这种解决方案并不可靠。有一种类似消息队列、或者Pub/Sub的场景下,把Redis作为缓冲区使用,可以提供非常好的写入吞吐。
(6)反向Cache
类似微博中经常出现的短链热点,短时间有数以万计的人点击、跳转,在跳转的过程中可能需要做一些逻辑的控制,比如用户等级或是已经登录等信息,当有大量的垃圾用户进行恶意调用或攻击时,由于原来采用的Memcached+mysql的架构,Memcached短时间内没有命中,流量就会直接穿透cache,直接访问mysql,导致数据库连接被打满,系统吞吐量降低,响应时间增加。
可以使用Redis记录所有用户的关键信息,在跳转时查询一次Redis获取基本用户信息,做一次反向的Cache,就可以减少Memcached未命中的情况[7]。

3 Redis存储方式

Redis有两种存储方式,默认是snapshot方式,实现方法是定时将内存的快照(snapshot)持久化到硬盘,这种方法缺点是持久化之后如果出现crash则会丢失一段数据。因此在完美主义者的推动下作者增加了aof方式。aof即append only mode,在写入内存数据的同时将操作命令保存到日志文件,在一个并发更改上万的系统中,命令日志是一个非常庞大的数据,管理维护成本非常高,恢复重建时间会非常长,这样导致失去aof高可用性本意。另外更重要的是Redis是一个内存数据结构模型,所有的优势都是建立在对内存复杂数据结构高效的原子操作上,这样就看出aof是一个非常不协调的部分。
其实aof目的主要是数据可靠性及高可用性,在Redis中有另外一种方法来达到目的:Replication。由于Redis的高性能,复制基本没有延迟。这样达到了防止单点故障及实现了高可用。

4 Redis内存管理

Redis内存管理通过在zmalloc.h和zmalloc.c中重写c语言对内存的管理来完成的。
(1)zmalloc
原型:void *malloc(unsigned int num_bytes);
分配一块指定大小的内存区域,并返回指向该区域头部的指针,分配失败则返回NULL;
(2)zcalloc
原型:void *calloc(unsigned n, unsigned size);
在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。
(3)zrealloc
原型:oid *realloc(void *mem_address, unsigned int newsize);
先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。
(4)zfree
原型:void free(void *ptr);
释放ptr指向的存储空间。被释放的空间通常被送入可用存储区池,以后可在调用malloc、realloc以及calloc函数来再分配。

5 Redis读写分离

通过复制可以实现读写分离以提高服务器的负载能力。在常见的场景中,读的频率大于写,当单机的Redis无法应付大量的读请求时(尤其是较耗时的请求,比如SORT命令等)可以通过复制功能建立多个从数据库,主数据库只进行写操作,而从数据库负责读操作。

6 Redis通信协议

Redis的通信协议是Redis客户端与Redis之间交流的语言,通信协议规定了命令和返回值的格式。Redis支持两种通信协议,一种是二进制安全的统一请求协议(unified request protocol),一种是比较直观的便于在telnet程序中输入的简单协议。这两种协议只是命令的格式有区别,命令返回值的格式是一样的。

7 Redis事务

(1)Redis作为一种高效的分布式数据库,同样支持事务。
Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行。Redis事务的实现需要用到 MULTI 和 EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。

(2)Redis事务错误处理
语法错误表示命令不存在或者参数错误,这种情况需要区分Redis的版本,Redis 2.6.5之前的版本会忽略错误的命令,执行其他正确的命令,2.6.5之后的版本会忽略这个事务中的所有命令,都不执行。
运行错误表示命令在执行过程中出现错误,比如用GET命令获取一个散列表类型的键值。这种错误在命令执行之前Redis是无法发现的,所以在事务里这样的命令会被Redis接受并执行。如果事务里有一条命令执行错误,其他命令依旧会执行(包括出错之后的命令)。

8 Redis集群

Redis主从复制配置和使用都非常简单。通过主从复制可以允许多个slave server拥有和master server相同的数据库副本。下面是关于Redis主从复制的一些特点
(1) master可以有多个slave;
这里写图片描述
(2)除了多个slave连到相同的master外,slave也可以连接其他slave形成图状结构;
这里写图片描述
(3)主从复制不会阻塞master。也就是说当一个或多个slave与master进行初次同步数据时,master可以继续处理client发来的请求。相反slave在初次同步数据时则会阻塞不能处理client的请求;
(4)主从复制可以用来提高系统的可伸缩性,我们可以用多个slave 专门用于client的读请求,比如sort操作可以使用slave来处理。也可以用来做简单的数据冗余;
(5)可以在master禁用数据持久化,只需要注释掉master 配置文件中的所有save配置,然后只在slave上配置数据持久化。
下面介绍下主从复制的过程
当设置好slave服务器后,slave会建立和master的连接,然后发送sync命令。无论是第一次同步建立的连接还是连接断开后的重新连接,master都会启动一个后台进程,将数据库快照保存到文件中,同时master主进程会开始收集新的写命令并缓存起来。后台进程完成写文件后,master就发送文件给slave,slave将文件保存到磁盘上,然后加载到内存恢复数据库快照到slave上。接着master就会把缓存的命令转发给slave。而且后续master收到的写命令都会通过开始建立的连接发送给slave。从master到slave的同步数据的命令和从 client发送的命令使用相同的协议格式。当master和slave的连接断开时slave可以自动重新建立连接。如果master同时收到多个 slave发来的同步连接命令,只会使用启动一个进程来写数据库镜像,然后发送给所有slave。

9 通过keepalived实现高可用方案

Keepalived 是一个用c写的路由选择软件,配合IPVS 负载均衡实用,通过VRRP 协议提供高可用。目前最新版本1.2.7.Keepalived 机器之间实用VRRP路由协议切换VIP,切换速度秒级,且不存在脑裂问题。可以实现。
可以实现一主多备,主挂后备自动选举,漂移VIP,切换速度秒级;切换时可通过运行指定脚本更改业务服务状态。

如两台主机A、B,可以实现如下切换:
(1)A 、B 依次启动,A作为主、B为从;
(2)主A 挂掉,B接管业务,作为主;
(3)A 起来,作为从SLAVE OF B;
(4)B 挂掉,A 切回主。

将一台全部作为主,即可实现主从,可做读写分离;也可以通过多个VIP,在一台机器上多个实例中一半主、一半从,实现互备份,两机同时负责部分业务,一台宕机后业务都集中在一台上。
这里写图片描述
切换流程:
(1)当Master挂了后,VIP漂移到Slave;Slave 上keepalived 通知Redis 执行:slave of no one,开始提供业务;
(2)当Master起来后,VIP 地址不变,Master的keepalived 通知Redis 执行slave of slave IP host,开始作为从同步数据;
(3)依次类推。

主从同时Down机情况:
(1)非计划性,不做考虑,一般也不会存在这种问题;
(2)计划性重启,重启之前通过运维手段SAVE DUMP 主库数据;需要注意顺序:
1)关闭其中一台机器上所有Redis,是得master全部切到另外一台机器(多实例部署,单机上既有主又有从的情况);并关闭机器;
2)依次dump主上Redis服务;
3)关闭主;
4)启动主,并等待数据load完毕;
5)启动从。
删除DUMP 文件(避免重启加载慢)

原创粉丝点击