Redis相关知识

NoSql数据库
分类 代表数据库 优点 缺点 数据模型 典型应用
键值存储数据库 Redis 快速查询 存储的数据缺少结构化 一系列键值对 内容缓存,主要用于处理大量数据的高访问负载
列式存储数据库 HBase 查找速度快,可扩展性强,更容易进行分布式扩展 功能相对局限 以列簇式存储,将同一列数据存在一起 分布式的文件系统
文档型数据库 MongoDB 数据结构要求不严格 查询性能不高,而且缺乏统一的查询语法 一系列键值对 Web应用
图形数据库 Neo4J 利用图结构相关算法 需要对整个图做计算才能得出结果,不容易做分布式的集群方案 图结构 社交网络


Redis是使用c语言开发的一个高性能键值数据库。Redis可以通过一些键值类型来存储数据。
redis的应用场景:缓存(数据查询、短连接、新闻内容、商品内容等等)(最多使用);分布式集群架构中的session分离;聊天室的在线好友列表;任务队列,(秒杀、抢购、12306等等);应用排行榜;网站访问统计;数据过期处理(可以精确到毫秒)。
Redis的数据类型
数据类型 Value的形式 读写操作 典型应用
String 字符串、整数和浮点数 读写整个或者部分字符串,不能只更新对象中的一个属性 商品编号、订单号采用string的递增数字特性生成
Hash 无序KV的HashTable 插入、删除和读取某项,读写整个Hashtable,字段值只能是字符串类型,不支持散列类型、集合类型等其它类型。不区分插入(返回1)和更新(返回0) 存储商品信息
商品字段
【商品id、商品名称、商品描述、商品库存、商品好评】
定义商品信息的key
商品1001的信息在 Redis中的key为:[items:1001]
List 字符串链表,无序,有重复元素 Redis的list是采用来链表来存储的,两端存储数据, 商品评论列表
思路:在Redis中创建商品评论列表;用户发布商品评论,将评论信息转成json存储到list中;用户在页面查询评论列表,从redis中取出json数据展示到页面。
Set 无序的字符串集合,字符串不可以重复 插入、删除和读取某个字符串,查看某个字符串是否属于集合,对于集合执行归、并、差操作
Sortedset 字符串结合,每个字符串映射带一个浮点数分数,按照分数排序 插入、删除和读取某项,可以根据范围进行查找 商品销售排行榜
需求:根据商品销售量对商品进行排行显示
思路:定义商品销售排行榜(sorted set集合),Key为items:sellsort,分数为商品销售量。
Redis常用关键字
常用关键字 解释
Keys 返回满足给定pattern 的所有key
Exists 确认一个key 是否存在
Del 删除一个key
Rename 重命名key
Type 返回值的类型
Expire 设置生命周期


Redis持久化方案
RDB方式 AOF方式
通过快照来将数据持久化到磁盘中,redis非法关闭,那么会丢失最后一次持久化之后的数据。
保存:如果RDB文件已经存在将会替换已有的RDB文件。保存RDB文件期间会阻塞主进程,这段时间期间将不能处理新的客户端请求,直到保存完成为止。为避免主进程阻塞,Redis提供了rdbSaveBackground函数。在新建的子进程中调用rdbSave,保存完成后会向主进程发送信号,同时主进程可以继续处理新的客户端请求。
读取:载入RDB过程中,每载入1000个键就处理一次已经等待处理的客户端请求。
保存点:
此时如果保存点设置过大,就会导致宕机丢失的数据过多。保存点设置过小,又会造成IO瓶颈;当对数据进行保存时,可能会由于数据集过大导致操作耗时,这会导致Redis可能在短时间内无法处理客户端请求。 将操作的记录存储到aof持久化文件中,在使用aof和rdb方式时,如果redis重启,则数据从aof文件加载。
保存:1.将客户端请求的命令转换为网络协议格式;2.将协议内容字符串追加到变量server.aof_buf中3.当AOF系统达到设定的条件时,会调用aof_fsync(文件描述符号)将数据写入磁盘。
其中第三步提到的设定条件,就是AOF性能的关键点。目前Redis支持三种保存条件机制:
1.AOF_FSYNC_NO:不保存。此模式下,每执行一条客户端的命令,都会将协议字符串追加到server.aof_buf中,但不会执行写入磁盘。
写入只发生在:
1.Redis被正常关闭;2.Aof功能关闭;3.系统写缓存已满,或后台定时保存操作被执行上面三种情况都会阻塞主进程,导致客户端请求失败。
2.AOF_FSYNC_EVERYSECS:每一秒保存一次。由后台子进程调用写入保存,不会阻塞主进程。如果发生宕机,那么最大丢失数据会在2s以内的数据。这也是默认的设置选项。
3.AOF_FSYNC_ALWAYS:每执行一个命令都保存一次。
这种模式下,可以保证每一条客户端指令都被保存,保证数据不会丢失。但缺点就是性能大大下降,因为每一次操作都是独占性的,需要阻塞主进程。
AOF需要将所有的命令都保存到磁盘,那么这个文件会随着时间变得越来越大。读取也会变得很慢。
缺点:AOF文件通常会大于相同数据集的RDB文件;
AOF模式下性能与RDB模式下性能高低,主要取决于AOF选用的fsync模式。


Redis主从复制避免单点故障。主redis中的数据和从redis上的数据保持实时同步,当主redis写入数据时通过主从复制机制会复制到两个从redis服务上;只有一个主redis,可以有多个从redis;主从复制不会阻塞master,在同步数据时,master 可以继续处理client 请求;一个redis可以即是主又是从。
Redis架构细节:
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
(2)节点的fail是通过集群中超过半数的节点检测失效时才生效。
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
(4)redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value。
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
Redis容错:
集群中所有master参与投票,如果半数以上master节点与其中一个master节点通信超过(cluster-node-timeout),认为该master节点挂掉.
如果集群任意master挂掉,且当前master没有slave,则集群进入fail状态。也可以理解成集群的[0-16383]slot映射不完全时进入fail状态。

如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态。

下面的转自:http://www.jb51.net/article/109462.htm

内存管理优化
Redis Hash是value内部为一个HashMap,如果该Map的成员数比较少,则会采用类似一维线性的紧凑格式来存储该Map, 即省去了大量指针的内存开销,这个参数控制对应在redis.conf配置文件中下面2项:
hash-max-zipmap-entries 64 hash-max-zipmap-value 512       
当value这个Map内部不超过多少个成员时会采用线性紧凑格式存储,默认是64,即value内部有64个以下的成员就是使用线性紧凑存储,超过该值自动转成真正的HashMap。
hash-max-zipmap-value 含义是当 value这个Map内部的每个成员值长度不超过多少字节就会采用线性紧凑存储来节省空间。
以上2个条件任意一个条件超过设置值都会转换成真正的HashMap,也就不会再节省内存了,那么这个值是不是设置的越大越好呢,答案当然是否定的,HashMap的优势就是查找和操作的时间复杂度都是O(1)的,而放弃Hash采用一维存储则是O(n)的时间复杂度,如果
成员数量很少,则影响不大,否则会严重影响性能,所以要权衡好这个值的设置,总体上还是最根本的时间成本和空间成本上的权衡。
list-max-ziplist-value 64 list-max-ziplist-entries 512       
list数据类型节点值大小小于多少字节会采用紧凑存储格式、list数据类型多少节点以下会采用去指针的紧凑存储格式。
内存预分配:
Redis内部实现没有对内存分配方面做过多的优化(对比Memcache),在一定程度上会存在内存碎片,不过大多数情况下这个不会成为Redis的性能瓶颈,不过如果在Redis内部存储的大部分数据是数值型的话,Redis内部采用了一个shared integer的 方式来省去分配内存的开销,即在系统启动时先分配一个从1~n 那么多个数值对象放在一个池子中,如果存储的数据恰好是这个数值范围内的数据,则直接从池子里取出该对象,并且通过引用计数的方式来共享,这样在系统存储 了大量数值下,也能一定程度上节省内存并且提高性能,这个参数值n的设置需要修改源代码中的一行宏定义REDIS_SHARED_INTEGERS,该值 默认是10000,可以根据自己的需要进行修改,修改后重新编译就可以了。
持久化机制:
定时快照方式(snapshot):
该持久化方式实际是在Redis内部一个定时器事件,每隔固定时间去检查当前数据发生的改变次数与时间是否满足配置的持久化触发的条件,如果满足则通 过操作系统fork调用来创建出一个子进程,这个子进程默认会与父进程共享相同的地址空间,这时就可以通过子进程来遍历整个内存来进行存储操作,而主进程 则仍然可以提供服务,当有写入时由操作系统按照内存页(page)为单位来进行copy-on-write保证父子进程之间不会互相影响。
该持久化的主要缺点是定时快照只是代表一段时间内的内存映像,所以系统重启会丢失上次快照与重启之间所有的数据。
基于语句追加方式(aof):
aof方式实际类似mysql的基于语句的binlog方式,即每条会使Redis内存数据发生改变的命令都会追加到一个log文件中,也就是说这个log文件就是Redis的持久化数据。
aof的方式的主要缺点是追加log文件可能导致体积过大,当系统重启恢复数据时如果是aof的方式则加载数据会非常慢,几十G的数据可能需要几小时才能加载完,当然这个耗时并不是因为磁盘文件读取速度慢,而是由于读取的所有命令都要在内存中执行一遍。另外由于每条命令都要写log,所以使用aof的方式,Redis的读写性能也会有所下降。
可以考虑将数据保存到不同的Redis实例中,每个实例的内存大小在2G左右,避免将鸡蛋放到一个篮子里,既可以减少缓存失效给系统带来的影响,又可以加快数据恢复的速度,不过同时也给系统设计带来了一定的复杂性。
Redis持久化崩溃问题:
有Redis线上运维经验的人会发现Redis在物理内存使用比较多,但还没有超过实际物理内存总容量时就会发生不稳定甚至崩溃的 问题,有人认为是基于快照方式持久化的fork系统调用造成内存占用加倍而导致的,这种观点是不准确的,因为fork 调用的copy-on-write机制是基于操作系统页这个单位的,也就是只有有写入的脏页会被复制,但是一般你的系统不会在短时间内所有的页都发生了写 入而导致复制,那么是什么原因导致Redis崩溃的呢?
答案是Redis的持久化使用了Buffer IO造 成的,所谓Buffer IO是指Redis对持久化文件的写入和读取操作都会使用物理内存的Page Cache,而大多数数据库系统会使用Direct IO来绕过这层Page Cache并自行维护一个数据的Cache,而当Redis的持久化文件过大(尤其是快照文件),并对其进行读写时,磁盘文件中的数据都会被加载到物理内 存中作为操作系统对该文件的一层Cache,而这层Cache的数据与Redis内存中管理的数据实际是重复存储的,虽然内核在物理内存紧张时会做 Page Cache的剔除工作,但内核很可能认为某块Page Cache更重要,而让你的进程开始Swap ,这时你的系统就会开始出现不稳定或者崩溃了。我们的经验是当你的Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了。
总结:
1、根据业务需要选择合适的数据类型,并为不同的应用场景设置相应的紧凑存储参数。
2、当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能以及最大的内存使用量。
3、如果需要使用持久化,根据是否可以容忍重启丢失部分数据在快照方式与语句追加方式之间选择其一,不要使用虚拟内存以及diskstore方式。
4、不要让你的Redis所在机器物理内存使用超过实际内存总量的3/5。
redis.conf中的maxmemory选项,该选项是告诉Redis当使用了多少物理内存后就开始拒绝后续的写入请求,该参数能很好的保护好你的Redis不会因为使用了过多的物理内存而导致swap,最终严重影响性能甚至崩溃。

redis.conf文件中 vm-enabled 为 no 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值