对Redis的理解,Redis是什么,Redis和Memcache谁快?

JSON 2017-08-31 22:26:57 46737

    前段时间微博发生了一起大的系统故障,结果说是因为Redis集群的问题,很多技术的朋友都比较关心,其中的原因不会超出James Hamilton On Designing and Deploying Internet-Scale Service 概括的那几个范围,James 第一条经验“Design for failure ”是所有互联网架构成功的一个关键。互联网系统的工程理论其实非常简单,James paper 中内容几乎称不上理论,而是多条实践经验分享,每个公司对这些经验的理解及执行力决定了架构成败。

    题外话说完,最近又研究了  Redis  。去年曾做过一个MemcacheDB, Tokyo Tyrant, Redis performance test ,到目前为止,这个benchmark 结果依然有效。这1年我们经历了很多眼花缭乱的key / value 存储产品的诱惑,从Cassandra的淡出(Twitter 暂停在主业务使用)到Hbase 的兴起(Facebook新的邮箱业务选用HBase),当再回头再去看Redis,发现这个只有1万多行源代码的程序充满了神奇及大量未经挖掘的特性。Redis性能惊人,国内前十大网站的子产品估计用1台Redis就可以满足存储及Cache的需求。除了性能印象之外,业界其实普遍对Redis的认识存在一定误区。本文提出一些观点供大家探讨。

一、 Redis是什么?

    这个问题的结果影响了我们怎么用  Redis  。如果你认为  Redis  是一个key value store , 那可能会用它来代替  MySQL  ;如果认为它是一个可以持久化的cache , 可能只是它保存一些频繁访问的临时数据。  Redis  是REmote DIctionary Server 的缩写,在  Redis  在官方网站的的副标题是A persistent key-value database with built-in net interface written in ANSI-C for Posix systems ,这个定义偏向key value store 。还有一些看法则认为  Redis  是一个memory database ,因为它的高性能都是基于内存操作的基础。另外一些人则认为  Redis  是一个data structure server ,因为Redis支持复杂的数据特性,比如List, Set等。对Redis的作用的不同解读决定了你对Redis的使用方式。

    互联网数据目前基本使用两种方式来存储,关系数据库或者key value。但是这些互联网业务本身并不属于这两种数据类型,比如用户在社会化平台中的关系,它是一个list,如果要用关系数据库存储就需要转换成一种多行记录的形式,这种形式存在很多冗余数据,每一行需要存储一些重复信息。如果用key value存储则修改和删除比较麻烦,需要将全部数据读出再写入。Redis在内存中设计了各种数据类型,让业务能够高速原子的访问这些数据结构,并且不需要关心持久存储的问题,从架构上解决了前面两种存储需要走一些弯路的问题。

二、Redis不可能比Memcache快?

    很多开发者都认为  Redis  不可能比  Memcached  快,  Memcached  完全基于内存,而Redis 具有持久化保存特性,即使是异步的,Redis 也不可能比Memcached 快。但是测试结果基本是Redis占绝对优势。一直在思考这个原因,目前想到的原因有这几方面。

    Libevent Memcached 不同,Redis并没有选择Libevent Libevent 为了迎合通用性造成代码庞大(目前Redis代码还不到libevent的1/3)及牺牲了在特定平台的不少性能。Redis用libevent 中两个文件修改实现了自己的epoll event loop 。业界不少开发者也建议Redis使用另外一个libevent高性能替代libev,但是作者还是坚持Redis应该小巧并去依赖的思路。一个印象深刻的细节是编译Redis之前并不需要执行./configure

    CAS 问题。CAS Memcached 中比较方便的一种防止竞争修改资源的方法。CAS 实现需要为每个cache key设置一个隐藏的cas token cas 相当value 版本号,每次set token 需要递增,因此带来CPU和内存的双重开销,虽然这些开销很小,但是到单机10G+ cache以及QPS 上万之后这些开销就会给双方相对带来一些细微性能差别。

三、单台Redis的存放数据必须比物理内存小

  Redis  的数据全部放在内存带来了高速的性能,但是也带来一些不合理之处。比如一个中型网站有100万注册用户,如果这些资料要用Redis来存储,内存的容量必须能够容纳这100万用户。但是业务实际情况是100万用户只有5万活跃用户,1周来访问过1次的也只有15万用户,因此全部100万用户的数据都放在内存有不合理之处,RAM需要为冷数据买单。

这跟操作系统非常相似,操作系统所有应用访问的数据都在内存,但是如果物理内存容纳不下新的数据,操作系统会智能将部分长期没有访问的数据交换到磁盘,为新的应用留出空间。现代操作系统给应用提供的并不是物理内存,而是虚拟内存(Virtual Memory )的概念。

基于相同的考虑,Redis 2.0 也增加了VM特性。让Redis 数据容量突破了物理内存的限制。并实现了数据冷热分离。

四、Redis的VM实现是重复造轮子

Redis 的VM依照之前的epoll实现思路依旧是自己实现。但是在前面操作系统的介绍提到OS也可以自动帮程序实现冷热数据分离,Redis只需要OS申请一块大内存,OS会自动将热数据放入物理内存,冷数据交换到硬盘,另外一个知名的“理解了现代操作系统(3)”的Varnish就是这样实现,也取得了非常成功的效果。

作者antirez在解释为什么要自己实现VM中提到几个原因。主要OS的VM换入换出是基于Page 概念,比如OS VM1 Page 是4K, 4K中只要还有一个元素即使只有1个字节被访问,这个页也不会被SWAP, 换入也同样道理,读到一个字节可能会换入4K无用的内存。而Redis自己实现则可以达到控制换入的粒度。另外访问操作系统SWAP内存区域时block进程,也是导致Redis要自己实现VM原因之一。

五、用get / set方式使用Redis

作为一个key / value 存在,很多开发者自然的使用set/get 方式来使用  Redis  ,实际上这并不是最优化的使用方法。尤其在未启用VM 情况下,Redis 全部数据需要放入内存,节约内存尤其重要。

假如一个key-value单元需要最小占用512字节,即使只存一个字节也占了512字节。这时候就有一个设计模式,可以把key复用,几个key-value放入一个key中,value再作为一个set存入,这样同样512字节就会存放10-100倍的容量。

这就是为了节约内存,建议使用hashset而不是set/get的方式来使用Redis。

六、使用aof代替snapshot

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

其实aof 目的主要是数据可靠性及高可用性,在  Redis  中有另外一种方法来达到目的:Replication 。由于  Redis  的高性能,复制基本没有延迟。这样达到了防止单点故障及实现了高可用。

版权所属:SO JSON在线解析

原文地址:https://www.sojson.com/blog/243.html

转载时必须以链接形式注明原始出处及本声明。

本文主题:

如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。

关于作者
一个低调而闷骚的男人。
相关文章
redis数据库支持什么过期的管理特性?
redis数据库支持什么过期的管理特性?
Redis与Memcached的比较 ,然后选择了Redis
Redis教程,Redis集群搭建与Spring-data-redis的使用(Spring-data-redis使用篇)
JSON是什么?它能带来什么?它XML比较?
Shiro教程(四)Shiro + Redis配置
Redis教程,Redis集群搭建与Spring-data-redis的使用(介绍篇)
Redis教程,Redis集群搭建与Spring-data-redis的使用(集群搭建篇)
老黄历有红色绿色是什么意思?它们有的寓意?
DES算法的基本原理主要步骤是什么?
最新文章
Linux I/O重定向 1109
Ruby 循环 - while、for、until、break、redo 和 retry 508
Node.js:全局对象 386
如何使用终端检查Linux上的内存使用情况 378
JavaScript对象详细剖析 200
Python print() 函数 294
PHP if/else/elseif 语句 307
HTML5 Canvas弧线教程 276
Java赋值运算符 349
XML内部实体和外部实体 367
最热文章
最新MyEclipse8.5注册码,有效期到2020年 (已经更新) 685856
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 674999
免费天气API,全国天气 JSON API接口,可以获取五天的天气预报 608198
免费天气API,天气JSON API,不限次数获取十五天的天气预报 603591
Jackson 时间格式化,时间注解 @JsonFormat 用法、时差问题说明 554846
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 509890
Elasticsearch教程(四) elasticsearch head 插件安装和使用 480826
Jackson 美化输出JSON,优雅的输出JSON数据,格式化输出JSON数据... ... 267520
Java 信任所有SSL证书,HTTPS请求抛错,忽略证书请求完美解决 244560
Elasticsearch教程(一),全程直播(小白级别) 226583
支付扫码

所有赞助/开支都讲公开明细,用于网站维护:赞助名单查看

查看我的收藏

正在加载... ...