码迷,mamicode.com
首页 > 其他好文 > 详细

redis(1)

时间:2016-12-23 19:14:37      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:主从   size   结构   开发   条件   可能性   多个   upd   run   

一、Redis介绍

Redis 是一款开源的,基于 BSD 许可的,高级键值 (key-value) 缓存 (cache) 和存储 (store) 系统。由于 Redis 的键包括 string,hash,list,set,sorted set,bitmap 和 hyperloglog,所以常常被称为数据结构服务器

你可以在这些类型上面运行原子操作,例如,追加字符串,增加哈希中的值,加入一个元素到列表,计算集合的交集、并集和差集,或者是从有序集合中获取最高排名的元素。

为了满足高性能,Redis 采用内存 (in-memory) 数据集 (dataset)。根据你的使用场景,你可以通过每隔一段时间转储数据集到磁盘,或者追加每条命令到日志来持久化。

Redis 还支持主从异步复制非常快非阻塞初次同步网络断开时自动重连局部重同步。 特性包括:

  • 事务
  • 持久化
  • 主从异步复制
  • 非常快的非阻塞初次同步
  • 网络断开时自动重连局部重同步
  • 订阅/发布
  • Lua 脚本
  • 带 TTL 的键
  • LRU 回收键
  • 自动故障转移 (failover)
  • 等等

你可以通过多种语言来使用 Redis。

Redis 是由 ANSI C 语言编写的,在无需额外依赖下,运行于大多数 POSIX 系统,如 Linux、*BSD、OS X。Redis 是在 Linux 和 OS X 两款操作系统下开发和充分测试的,我们推荐 Linux 为部署环境。Redis 也可以运行在 Solaris 派生系统上,如 SmartOS,但是支持有待加强。没有官方支持的 Windows 构建版本,但是微软开发和维护了一个 64 位 Windows 的版本。

二、数据类型

2.1 key-value

1、关于键:

api文档: http://www.redis.cn/commands.html#generic

  • 二进制安全
  • 包含空格
  • 最大512M
  • 不要太长,太长可以考虑md5或者其他方式提取特征码
  • 不要太短而失去可读性: 例如user:1000:follower就比较合适
  • 命名风格应该统一
  • 支持键过期策略,精确到毫秒
  • 支持键空间

2、关于value

支持以下几种:

  • 二进制安全 (binary-safe) 的字符串。
  • 列表:按照插入顺序排序的字符串元素 (element) 的集合 (collection)。通常是链表。
  • 集合:唯一的,无序的字符串元素集合。
  • 有序集合:和集合类似,但是每个字符串元素关联了一个称为分数 (score) 的浮点数。元素总是按照分数排序,所以可以检索一个范围的元素 (例如,给我前 10,或者后 10 个元素)。
  • 哈希:由字段 (field) 及其关联的值组成的映射。字段和值都是字符串类型。这非常类似于 Ruby 或 Python 中的哈希 / 散列。
  • 位数组 (位图):使用特殊的命令,把字符串当做位数组来处理:你可以设置或者清除单个位值,统计全部置位为 1 的位个数,寻找第一个复位或者置位的位,等等。
  • 超重对数 (HyperLogLog):这是一个用于估算集合的基数 (cardinality,也称势,译者注) 的概率性数据结构。不要害怕,它比看起来要简单,稍后为你揭晓。

2.2 字符串String

http://www.redis.cn/commands.html#string

  • 二进制安全的value
  • 数值类型支持原子增原子减
  • 支持创建时指定过期时间
  • ...

2.3 列表List

http://www.redis.cn/commands.html#list

  • 是一种双端链表,因此可以是,也可以是队列
  • 支持阻塞操作
  • 支持上限列表: Capped

什么时候用列表:

以例子来说明:

  • 比如可以要记录用户最近提交的更新,把列表当做栈使用
  • 2种流行的Ruby库,resqu和sidekiq,都是使用Redis的列表当做钩子,来实现后台作业,思路是把List当做一个中间件,生成者往里面添加项,而消费者消费并且执行任务。

我们以一些例子来说明list结构是如何自动创建key和删除的。

插入3个元素:自动创建了mylist

lpush mylist 1 2 3

全部删除,自动删除了 mylist

192.168.0.211:6379> lpop mylist
"3"
192.168.0.211:6379> lpop mylist
"2"
192.168.0.211:6379> lpop mylist
"1"
192.168.0.211:6379> lpop mylist
(nil)
192.168.0.211:6379> exists mylist
(integer) 0

2.4 哈希Hash

http://www.redis.cn/commands.html#hash

  • 哈希就是字段值对(fields-values pairs)的集合,即看成Map。
  • 拥有少量字段 (少量指的是大约 100) 的哈希会以占用很少存储空间的方式存储,所以你可以在一个很小的 Redis 实例里存储数百万的对象。
  • 每个哈希可以存储多达多于 40 亿个字段值对 (field-value pair)。

作为最常用的redis结构,一般有2种设计的思路,多个key和单个key。

多个Key的大概设计:

hmset user:1000 username antirez birthyear 1977 verified 1 

hmset user:1001 username jerry birthyear 1971 verified 1 

 

单个Key的大概设计:

hset users 1000 "{username:antirez,birthyear:1977,verified:1}"
hset users 1001 "{username:jerry,birthday:1971,verified:2}"

2.5 无序集合Set

http://www.redis.cn/commands.html#set

  • 无序字符串
  • 不允许重复
  • 支持集合操作,交集、并集、差集

2.6 有序集合

http://www.redis.cn/commands.html#sorted_set

关于顺序:

  • 如果 A 和 B 是拥有不同分数的元素,A.score > B.score,则 A > B。
  • 如果 A 和 B 是有相同的分数的元素,如果按字典顺序 A 大于 B,则 A > B。A 和 B 不能相同,因为排序集合只能有唯一元素。(2.8新特性)

特点:

  • 通过双端数据结构实现,包括了跳表(skiplist)和哈希表(hashtable),所以每次添加时候执行O(log(N))的操作。
  • 有序,不是请求时才排序的,顺序是依赖于表示有序集合的数据结构。

三、使用twitter演示上述结构

这是一个简单的例子,只包含4张表:用户(user)、关注(following)、粉丝(followers)、帖子(updates)

1. 用户:

#1. 使用字符串产生唯一user_id
INCR next_user_id => 1000 
#2. 使用hash结构的第一种设计来存储用户名密码 
HMSET user:1000 username antirez password p1pp0  

如果要支持getUserIdByUsername(String username)类似的操作:

# 使用hash结构一个key方式存储username->id
HSET users antirez 1000 

2. 粉丝和关注:

每个用户可能有多个粉丝,用户->粉丝的映射关系可以使用有序集合来存储,使用时间来作为score

# user1000的粉丝增加了一个是:user1234,时间是...
ZADD followers:1000 1401267618 1234

关注也一样:

# user1000也可以关注对方1234
ZADD followering:1000 1401267618 1234

3. 帖子

这里不搞的太麻烦,帖子就是唯一的更新,也就是posts

这里最适合的结构是列表List,使用栈,把最新的放在栈顶

再利用列表的LLEN和LRange进行排序,这里不演示:

posts:1000 => a List of post ids - every new post is LPUSHed here.  

四、持久化机制

redis和memcached最大不同之处就在于redis既可以做缓存,又可以做存储。存储便依赖于redis的持久化机制。

支持2种:rdb和aof。

4.1 rdb

1、什么是rdb:

  • rdb就是使用快照(Snapshotting)技术保存数据集。
  • 也就是说rdb是基于时间点的数据备份
  • 默认情况下,redis使用rdb的机制进行持久化,名为dump.rdb的二进制文件。
  • 可以设置N秒之内至少M次改动时保存数据集。设置如"save 60 1000",亦可手动SAVE或者BGSAVE命令。

2、工作原理:

  1. redis调用fork()创建子进程c1。
  2. 利用copy-on-write机制,c1开始将数据集写入一个临时rdb文件。
  3. c1完成之后替换掉旧文件。

3、rdb优点:

  • 基于时间点,适合用于备份
  • 写入之后不能修改,因此可以复制,适合作为容灾技术传递给远程数据中心,例如S3
  • RDB性能不错,因为只需要fork()一个子进程
  • redis实例重启时基于RDB比基于AOF更快

4、rdb缺点:

  • 基于时间点,有数据间隙,间隙数据有丢失的可能性
  • fork()子进程如果太频繁、如果数据集较大且CPU性能不强的话,会出事故,甚至停止服务。

4.2 aof

1、什么是aof:

  • Append only file,即只追加文件,顺序io
  • 将修改redis的数据集命令不断追加
  • aof支持每个命令都追加、每s追加、以及不主动追加依赖于操作系统三种方式
  • 建议是每秒1次fsync操作

2、aof原理:

  • redis进程,假设是p进程,调用fork,创建了一个子进程c
  • c开始向一个临时文件写aof文件
  • p在内存缓冲区积累这段时间内的新变更(同时将新的变更写入旧的aof文件以确保安全)
  • 当c写完之后,给p发送一个信号,p把缓冲区的内容添加到aof文件的末尾
  • redis自动重命名aof文件,替换老的为新的

3、aof优点:

  • 更安全,如果使用每秒的策略,那最多就丢失1s的数据
  • 追加文件,容易修复,安全,redis还有专门的修复工具
  • aof内容容易理解
  • aof文件支持自动重写以控制文件size

4、aof缺点:

  • 作为备用策略,aof文件通常比rdb大的多
  • aof安全,但是慢
  • aof针对特殊命令有罕见bug

4.3 如何选择

  • 如果你同时使用2种,可以达到和PostgreSQL提供的数据安全程度!
  • 如果完全不关注,可以把AOF和RDB都关闭了,单纯作为缓存而不是存储!
  • 如果你关注数据,需要存储,但是可以接收几分钟的数据丢失,可以只使用RDB!
  • 如果你想要单独使用AOF,不鼓励,因为数据必须要备份,备份就需要RDB,而且避免了AOF的BUG,宁愿2个都用!

4.4 如何备份

Redis 对数据备份非常友好,因为你可以在数据库运行时拷贝 RDB 文件:RDB 文件一旦生成就不会被修改,文件生成到一个临时文件中,当新的快照完成后,将自动使用 rename(2) 原子性的修改文件名为目标文件。

这意味着,在服务器运行时拷贝 RDB 文件是完全安全的。以下是我们的建议:

  • 创建一个定时任务(cron job),每隔一个小时创建一个 RDB 快照到一个目录,每天的快照放在另外一个目录。
  • 每次定时脚本运行时,务必使用 find 命令来删除旧的快照:例如,你可以保存最近 48 小时内的每小时快照,一到两个月的内的每天快照。注意命名快照时加上日期时间信息。
  • 至少每天一次将你的 RDB 快照传输到你的数据中心之外,或者至少传输到运行你的 Redis 实例的物理机之外。

4.5 如何修复AOF文件

有可能在写 AOF 文件时服务器崩溃(crash),文件损坏后 Redis 就无法装载了。如果这个发生的话,你可以使用下面的步骤来解决这个问题:

  • 创建 AOF 的一个拷贝用于备份。
  • 使用 Redis 自带的 redis-check-aof 工具来修复原文件:
  • $ redis-check-aof --fix
  • 使用 diff -u 来检查两个文件有什么不同。用修复好的文件来重启服务器。

五、复制

1、redis复制的特性:

一种使用和配置都非常简的主动(master-slave)复制,允许Redis从服务器成本主服务器的精确副本。

  • 异步复制:2.8开始,从服务器会周期性的报告从复制流中处理的数据里的数据量。一个主服务器可以拥有多个从服务器。
  • 支持复杂结构,master->s1->s2....
  • 主服务器复制的时候master是非阻塞的。
  • Redis的复制在slave上也是非阻塞的。
  • 通过在slave上redis.conf中进行相应的配置,slave也能够继续使用旧版本的数据集处理请求。可以配置当复制流down掉的时候,从服务器返回给客户端一个error。然后,初始化同步结束后,旧的数据集需要被删除,新的数据集需要被载入。在这个简短的窗口期内,从服务器会阻塞到来的连接
  • 复制可以用来支持可伸缩性,用多个slave处理只读查询(例如,繁重的SORT操作可以分配到从服务器上),也可以仅仅用来作为数据冗余
  • 可以使用复制来避免主服务器将全部数据集磁盘的开销:只需要配置你的主服务器的redis.conf来防止保存(所有的"保存"指令),然后连接一个不断复制的从服务器。但是,这种设置要确保主服务器不会自动重启。

2、使用redis主从要注意安全性:即数据不丢失

(1).我们设置节点 A 作为主服务器,关闭了持久化,节点 B 和节点 C 从节点 A 复制。
(2).A 崩溃了,但是它拥有某个自动重启系统,重启了这个进程。但是,由于持久化是被关闭的,这个节点以空的数据集重启。
(3). 节点 B 和节点 C 从空的 A 复制,于是它们完全销毁了他们的数据拷贝。

当开启了哨兵时,关闭主服务器的自动重启就明智的,防止哨兵没有检测到Master的自动重启。

3、redis复制的原理

  • 当slave连接master的时候,不管是第一次还是重新连接上,连接发送一个SYNC命令。
  • 主服务器开始在后台保存,并且开始缓冲所有新收到的会修改数据集的命令。
  • 主服务器保存完之后,传送一份数据库文件给从服务器,从服务器保存到磁盘并且加载到内存。
  • 主服务器发送缓冲命令给从服务器。

- 是通过命令流完成的,和Redis协议是一样的格式。

- 可以用telnet给一台正在工作的Redis端口发送 SYNC命令,然后会看到大量的传输。

- 当主从链路断开,从服务器可以自动重连。如果主服务器收到多个并发的同步请求,只会执行一个后台来保存服务所有的服务器。

- 当重连后,总是执行一个全量同步,在2.8之后,可以选择执行部分同步.(partial resynchronization)

 

4、支持部分重同步(partial resynchronization)

即在复制中途断开,再重连之后,可以继续复制过程,而不需要一次完整的重新同步。

通过在主服务器上创建一个复制流的内存缓冲区(in-memory backlog)实现。主服务器和所有从服务器记录一个复制偏移量(offset)和一个主服务器的ID(run id),当链接断掉时,从服务器会重链接,并且请求服务器继续恢复复制。
如果满足以下条件:

  • 主服务器的运行ID一样
  • 指定的偏移量offset在复制缓冲区中可用

就可以继续增量复制,否则执行完整重同步。

5、无盘复制,试验性:(Diskless replication)

完整的全量同步需要在磁盘上创建一个RDB文件,然后从磁盘加载同一个RDB给从服务器,性能一般。
因此在2.8.18版本后试验性的支持无盘复制。
原理是:子进程通过线路(write)发送RDB给从服务器,而且不需要使用磁盘作为中间存储。

6、 默认slave 是read-only的:

在2.6版本在在之后默认从服务器默认开启只读模式。
这个行为由conf中的slave-read-only所控制
而且支持运行时通过CONFIG SET修改,在某些failover策略中关闭read-only使用有意义的。

举个例子:可以考虑使用传统的高可用模型来建立架构,比如说使用keep-alived来保持高可用,这就需要slave也支持写模式了。

7、支持密码验证

8、支持N个副本才可以写的机制:

即在master上配置一个健康监测机制,当成功检测到有N个健康的slave才允许写操作。

在Redis主服务器上设置:
min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>

(1) Redis主服务器每秒钟Ping主服务器,上报处理完的复制流的数据量。

(2) Redis主服务器记录上一次从每一个从服务器中收到ping 的时间,健康监测

(3) 用户配置最小的从服务器数量,每台从服务器拥有一个不大于最大秒数的滞后lag.

 

redis(1)

标签:主从   size   结构   开发   条件   可能性   多个   upd   run   

原文地址:http://www.cnblogs.com/carl10086/p/6149735.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!