Redis几个认识误区 – Tim[后端技术]

Posted on

Redis几个认识误区 – Tim[后端技术]

Tim[后端技术]

Tim's blog, 关于后端架构、互联网技术、分布式、大型网络应用、NoSQL、技术感悟等

Home | About | English version | 留言(Guestbook) | 订阅RSS Add to Google

Saturday, Dec 4th, 2010 by Tim | Tags: key value store, redis

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

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

1. 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在内存中设计了各种数据类型,让业务能够高速原子的访问这些数据结构,并且不需要关心持久存储的问题,从架构上解决了前面两种存储需要走一些弯路的问题。

2. Redis不可能比Memcache快

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

  • Libevent。和Memcached不同,Redis并没有选择libevent。Libevent为了迎合通用性造成代码庞大(目前Redis代码还不到libevent的1/3)及牺牲了在特定平台的不少性能。Redis用libevent中两个文件修改实现了自己的epoll event loop(4)。业界不少开发者也建议Redis使用另外一个libevent高性能替代libev,但是作者还是坚持Redis应该小巧并去依赖的思路。一个印象深刻的细节是编译Redis之前并不需要执行./configure。
  • CAS问题。CAS是Memcached中比较方便的一种防止竞争修改资源的方法。CAS实现需要为每个cache key设置一个隐藏的cas token,cas相当value版本号,每次set会token需要递增,因此带来CPU和内存的双重开销,虽然这些开销很小,但是到单机10G+ cache以及QPS上万之后这些开销就会给双方相对带来一些细微性能差别(5)。

3. 单台Redis的存放数据必须比物理内存小

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

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

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

4. Redis的VM实现是重复造轮子

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

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

5. 用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,详细方法见参考文献(7)。

6. 使用aof代替snapshot

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

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

小结

要想成功使用一种产品,我们需要深入了解它的特性。Redis性能突出,如果能够熟练的驾驭,对国内很多大型应用具有很大帮助。希望更多同行加入到Redis使用及代码研究行列。

参考文献

  1. On Designing and Deploying Internet-Scale Service(PDF)
  2. Facebook’s New Real-Time Messaging System: HBase To Store 135+ Billion Messages A Month
  3. What’s wrong with 1975 programming
  4. Linux epoll is now supported(Google Groups)
  5. CAS and why I don’t want to add it to Redis(Google Groups)
  6. Plans for Virtual Memory(Google Groups)
  7. Full of keys(Salvatore antirez Sanfilippo)

-EOF- 上一篇博文多IDC数据时序问题及方法论在新浪微博上面有更多讨论及留言,有兴趣可以去围观。http://t.sina.com.cn/10503/zF0tex7z7b(需登录)

62 Comments »

  1. Eguo Wang says:

Dec 4th 2010 at 03:09

我之前项目选用的是mongodb,相对于常规kv数据库提供了更多实用的查询操作。我有一个问题想请教你:redis中高效的条件搜索如何做呢?难道真的要自己解数据后构建吗?或使用附加的搜索引擎?

  1. Eguo Wang says:

Dec 4th 2010 at 03:25

看到wiki中有几个指令大概是做搜索操作。

  1. kula says:

Dec 4th 2010 at 09:25

redis的vm模式在实践中存在一些问题.

我使用过redis2.0.2, 发现当vm模式打开的时候, 并发连接数在1500以上时, redis latency会大大增加.平均每个请求的latency会超过4000ms, 观察redis的进程cpu占用率, 会超过100%. 最后迫于无奈,关掉了redis的vm功能. 此时并发连接不变的情况下,redis的latency下降到2ms以下. cpu占用率下降到1%.

没有深入研究过这个症状,但初步怀疑是redis的vm实现有点不靠谱.

  1. kula says:

Dec 4th 2010 at 09:26

redis的vm模式在实践中存在一些问题. 我使用过redis2.0.2, 发现当vm模式打开的时候, 并发连接数在1500以上时, redis latency会大大增加.平均每个请求的latency会超过4000ms, 观察redis的进程cpu占用率, 会超过100%. 最后迫于无奈,关掉了redis的vm功能. 此时并发连接不变的情况下,redis的latency下降到2ms以下. cpu占用率下降到1%. 没有深入研究过这个症状,但初步怀疑是redis的vm实现有点不靠谱.

  1. kasicass says:

Dec 4th 2010 at 10:09

是不是笔误,呵呵。

“没一行需要存储一些重复信息” ==> “每一行需要存储一些重复信息”

  1. empyreaner says:

Dec 4th 2010 at 12:07

@Eguo Wang redis的搜索都需要自己做索引。使用keys指令做搜索消耗比较大,不能作为常用指令。

  1. yiihsia says:

Dec 4th 2010 at 17:19

VM还是不好用,频繁访问老会报错, hashset更适合像cache这样一对一的存储,批量get的方法只能针对一个具体的hash值

  1. fzuslide says:

Dec 5th 2010 at 00:36

Redis在写snapshot的时候CPU使用率很高,数据库本身很大的情况下,回写磁盘过程持续的时间会比较久。这种情况下AOF开销相对较小,然后定时的BGrewriteAOF来减小aof大小,replication还是必须要做的。

  1. davies says:

Dec 6th 2010 at 17:35

Redis 并不是神奇, 它有点像个拥有十八般武艺的四不像, 想要解决所有问题, 却没有完全好地解决掉任何一个问题.

  1. Hanson Lu says:

Dec 10th 2010 at 09:17

以后有个开源哦项目Prevayler,也是使用snapshot + 日志的方式实现持久化,也是挺不错的,不过由于开启了fsync操作,导致效率很低,不知redis是否使用了fsync

  1. Bob says:

Dec 13th 2010 at 10:01

最近也在关注这方面的资料,有在InfoQ上看到天涯团队的一篇文章: http://www.infoq.com/cn/news/2010/11/tianya-memlink

里面提到了2点,

  1. Redis的复制机制不完善,失步之后要重新同步所有数据。
  2. Redis的操作时单线程的,没有办法利用多核的优势。

不知Tim怎么看这两个问题?对实际应用的影响大吗?

  1. Tim says:

Dec 13th 2010 at 10:29

@bob

  1. 可以架两级slave解决
  2. 通过单服务器多端口刚好发挥这种优势,我上次微博公开演讲也介绍过。
  3. test says:

Dec 13th 2010 at 10:30

我觉得你的很多想法都非常奇怪。

  1. kefeng says:

Jan 26th 2011 at 09:41

支持作者的观点,深有体会。

  1. chao.liu says:

Feb 25th 2011 at 17:27

用get/set方式使用Redis: 最好不要在redis client上封装get set的方式使用hash的方式,否则sort操作的时候可能会有问题。

  1. chao.liu says:

Feb 25th 2011 at 19:54

补充: sort支持根据hashs filed进行排序 例如: SORT mylist BY weight/*->fieldname GET object/*->fieldname 如果client上封装了set方法使其使用hashes的方式存储以节省内存,此时hashes的key是根据一定的算法确定的,假如是sha1,那么set方法的key会分布到不同的hashes的key中,此时如果做排序会导致 需要遍历hashes。

  1. chao.liu says:

Feb 25th 2011 at 20:33

接上: 在启用vm的情况下 如果按照参文献7中所说 ,通过sha1算法将key value放入到不同的hashes中,这时会出现一个问题:vm的换出是根据age/*log asize 来选出最适合的key,将对应的value放入swap中,由于hashes的key是通过算法算出来的,有可能导致部分的冷filed因为与hot fileld使用同一个key 而无法被交换出去。内存开销是小了,但可能无法换出了。

  1. domiguo says:

Apr 29th 2011 at 15:47

我们也打算使用redis,但是对他的persistence有一些担心, 请问你们使用redis的方法后端还有其它设备的备份吗,比如Mysql之类的,还是完全靠redis本身的persistence加上一些业务级别的保证?

  1. rjgcs123 says:

May 27th 2011 at 17:11

云集国内redis大佬的QQ群正在招募各路redis朋友,不管你是正在使用redis,还是在研究redis,或者是对redis感兴趣,你都可以加入到我们的阵营。大家一起讨论redis各类用法,key-value、list、set、map使用,redis优化、内存监控、主从配置等等问题,这里都会有高手给你解决。

注意啦,国内顶尖级别的redisQQ群是 43016055

  1. simonliu says:

Jun 9th 2011 at 11:44

访问操作系统的 SWAP 需要 block 进程。实际上自己实现 VM,访问存在磁盘上的冷数据时肯定是要 block 进程的。所以这点理由有点牵强。

  1. geelou says:

Jul 5th 2011 at 13:11

redis java分群 163264749 是java的 Redis PHP分群 163265386 是php的 redis c,c++,c/#分群 163269313 是.net的 redis shell,python群 69287882 是shell,python,prel脚本类的

  1. kyozhou says:

Jul 11th 2011 at 17:23

非常好,尤其是对于redis的性能超过memcached的描述。

  1. fenglibin2010 says:

Aug 16th 2011 at 16:26

写得非常好,我们也准备使用REDIS,对一些概念又更加清晰

  1. pally says:

Aug 22nd 2011 at 13:37

very good! happy to see it!

  1. Roowe says:

Oct 13th 2011 at 00:04

看了评论,我都不怎么敢用了,本身出于用缓存来减少服务器的压力,而不是用NoSQL,这货貌似是NoSQL。。

  1. the5fire says:

Jul 30th 2012 at 11:08

学习了,刚开始看redis。

  1. GF says:

Aug 9th 2012 at 13:17

MySQL 最新开发版 5.6.6 目前尚未发布,但从官网给出的 CHANGES 文档可得知,该版本将内嵌 memcached 的支持,以后可以用No SQL的方式使用mysql,在数据库中充分利用memcached的优点。缓存和数据的一致性问题不再是个问题。

  1. Eguo Wang says:

Oct 30th 2012 at 11:43

DDDDD!!

  1. julie says:

Nov 12th 2012 at 15:37

大家有没有在广域网中使用过redis?master和slave的同步性能情况怎样,有人知道吗?

RSS feed for comments on this post, TrackBack URI Cancel Reply

Leave a Comment

Name (required)

E-mail (required, never displayed)

URI

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 3.0 License

Twitter的跨数据中心图片存储系统Blobstore

Posted on

Twitter的跨数据中心图片存储系统Blobstore

Twitter**的跨数据中心图片存储系统Blobstore**

发表于**3小时前| 962次阅读|来源CSDN编译|6**条评论|作者王鹏**

TwitterBlobstoreKestrel

摘要:Google、Facebook以及Twitter这些网络巨头都面临着同样的问题:如何构建跨数据中心服务?现在数以百万计的用户开始使用Twitter来分享照片,这些都离不开Twitter图片存储系统Blobstore的支持,该系统不仅引入了新的特性和功能,而且不断提升了用户体验,本文主要解析了该跨数据中心的图片存储系统。

【CSDN报道】Twitter一直没有自己的图片存储系统,此前系统从2011年6月开始内置采用Photobucket的服务,另外,也支持Instagram等第三方图片应用上传到Twitter系统中。随着Twitter整体由开放转向封闭,切断第三方图片上传,同时自行提供图片系统是势所必然的。

12**月11日,Twitter工程博客发表[文章](http://engineering.twitter.com/2012/12/blobstore-twitters-in-house-photo.html),介绍了9月份已经上线使用的图片存储系统Blobstore的底层架构。其中比较引人注目的是,Blobstore支持多数据中心同步。GigaOM的文章指出,这与[Google Spanner](http://www.csdn.net/article/2012-09-19/2810132-google-spanner-next-database-datacenter)是异曲同工的。**

CSDN**进行了编译整理,文章如下:**

Blobstore**的设计目标**

Blobstore是由Twitter开发的一个低成本和可扩展的的存储系统,可以用来存储图片以及其他的二进制对象(称为“blob”)。在开始构建Blobstore时,Twitter有三个设计目标:

· 低成本:可以大大减少花费在添加图片到Tweet中的时间和成本。

· 高性能:图片延迟保持在几十毫秒之内,同时保证每秒上千万张吞吐量的图片请求。

· 易于操作:随着Twitter基础设施的不断增长,能够扩展操作开销。

Blobstore**是如何进行工作的?**

当用户推送一张照片,我们把照片发送到一组Blobstore前端的服务器。前端服务器解析后会给该照片一个特定的写地址,接下来将其转发到具体的服务器进行实际的数据存储。我们可以把这些存储服务器称之为存储节点,它们把照片信息存储到一个磁盘上,然后通知元数据存储——图像已经存储完毕并记录所需要的信息以便进行照片检索。元数据存储库,这是一个非关系型键/值存储集群,它可以自动的进行多数据中心(multi-data-center)的同步功能,更重要的是可以跨所有的Twitter的数据中心,进而在Blobstore上提供的一致性的视图数据。

Blobstore核心是Blob Manager,它运行在前端,用于存储节点以及索引集群。Blob Manager充当系统中心“协调员”的角色,对集群进行管理。它是所有前端信息(决定应该把文件存储到哪个地方)的源。不仅如此,它还负责更新映射,在增加存储节点或者由于添加失败节点被移除时,协调数据的迁移。

还有一点比较重要,就是依靠Kestrel。这是Twitter现有的异步队列服务器,主要用来处理任务,比如说复制图像以及确保数据中心中数据的完整性。

Twitter确保一旦图像上传成功,用户就可以立即从数据中心中进行读取,而且绝对是最原始的图像。而且在如此之短的时间内,图像已经复制到Twitter所有其他的数据中心之内,并且可以从这些数据中心进行读取。此功能主要依赖于Blobstore内的多数据中心元数据存储对文件的中央索引。Twitter高度关注短时间内一个图像是否被已经被写入它最初的数据中心,他们使用路由请求,确保该Kestrel队列能够进行数据复制。

Blobstore**的组成**

http://articles.csdn.net/uploads/allimg/121217/145_121217171537_1.jpg

如何进行数据的创建工作?**

当Blobstore收到一个图像请求时,我们需要先确定其位置再进行访问数据。虽然有一些方法可以解决这个问题,但是每一种都有自己的优点和缺点。其中有一个途径就是通过映射或者Hash每个图像,通过一些特有的方法分配到一个给定的服务器之上,不过这种方法有一个相当大的缺点,就是在管理图像的流动时要复杂得多。例如,要从Blobstore中添加或删除一个服务器,那么就需要为受到变更影响的每个独立的图像再计算一个新的位置。很显然,这大大增加了运营的复杂性,因为数据的移动会产生大量的记录。

另一个方法,我们可以为个人的数据块创建了一个固定大小的容器称之为“virtual bucket”,第一步我们先把这些图像映射到该容器之上,然后我们再把容器映射到独立的存储节点上,这样我们就保持virtual bucket的总数量不变(对整个集群的寿命来说这是很好的方法)。那么为了确定一张给定的图像应该存储在哪个virtual bucket之上,我们就需要对图像的唯一ID执行一个简单的Hash标记。只要virtual bucket的数量保持不变,这个Hashing也将保持稳定。这种方式稳定的原因在于:我们把对数据的移动放在一个更粗粒度的级别上,而不再是针对于单个图像。

如何安置数据?**

当我们把virtual bucket映射到物理存储节点上时,我们的头脑应该保持清醒,必须保留一些规则以确保当我们丢失服务器或硬盘设备时,不能同时把数据丢失。如果我们把所有给定的图像副本都放在单一机架的服务器之上,一旦服务器出了问题,那就意味着图像将不可能再次使用。

如果我们把数据从一个给定的存储节点完全镜像到另一个存储节点之上,我们不太可能会出现不可用的数据,因为同时失去两个节点的可能性极低。然而,每当我们失去一个节点,我们会从另一个节点重新复制数据到源节点。当然我们必须缓慢的进行恢复,以便不影响单一剩余节点的性能。

如果我们采取相反的方法,让集群中的任何服务器都共享所有服务器中的数据,当我们恢复失去的副本时,从本质上说,为了恢复数据我们就需要读取整个集群。然而,我们也会有一个非常高的数据丢失的可能性(因为任何两个节点分享一个块数据块,丢失几率会很高)。所以,最优方法是两种办法的折中:对于一个给定的数据片段,会有限定数量的机器分享的数据的副本——肯定是超过一个,但是绝对用不到整个集群。

当我们确定映射数据到存储节点上时,我们把所有的这些因素都纳入考虑之中。那么产生的结果就是:我们构建了一个库,它被称为“libcrunch”,它非常了解各种数据的存储规则,比如说rack-awareness;它了解复制数据的方式,以便最大限度地减少数据丢失的风险,同时最大化数据恢复时的吞吐量;并且在集群中的任何拓扑(如添加节点或删除节点)改变时,试图最小化数据迁移的数量。最重要的一点,它让我们能够映射整个数据中心的网络拓扑结构,所以存储节点已经有更好的数据位置,我们只需要考虑rack-awareness以及通过PDU zones和路由器来确定副本的存储位置。

http://articles.csdn.net/uploads/allimg/121217/145_121217171912_1.jpg

图:Blobstore 数据存储方式

拓扑管理**

随着磁盘和节点数量的不断增加,存储失败的机率也在不断升高。存储能力需要增强,磁盘和节点在出问题以后需要被立即取代,服务器也需要移动。为了使Blobstore更易于操作,我们投入了大量的时间和精力到libcrunch之上,还且随着集群的改变也开发了相关的工具。

http://articles.csdn.net/uploads/allimg/121217/145_121217172315_1.jpg

当一个存储节点失败之后,驻留在这个节点上的数据需要从现存的节点拷贝到正确的复制因子之上。失败的节点被标记为不可用的集群拓扑,因此libcrunch需要计算从virtual buckets映射到存储节点的改变。随着该映射的变更,就会指示存储节点复制和迁移virtual buckets到一个新的位置。

Zookeeper**

拓扑和放置规则存储在Zookeeper集群中。Blob Manager处理这种交互,当一个操作符对系统进行变更时,它就会调用存储在Zookeeper中的这个信息。拓扑的改变包括复制因子的调整、添加或删除节点失败以及调整其他的libcrunch输入参数等等。

跨数据中心复制**

Kestrel主要用于跨数据中心复制,这是因为kestrel是一个持久性的队列,可以用它来实现跨数据中心图像数据的异步复制。

确认数据中心路由(Data center-aware Routing)**

TFE(Twitter的前端)是一个Twitter的核心组件。我们为TFE编写了一个定制的插件,这样就扩展了默认的路由规则。我们的元数据存储跨越多个数据中心,因为元数据存储(每blob)都很小(仅有几个字节),我们复制这个信息通常比blob数据要快得多。如果一个用户试图访问一个blob,但是数据还没有复制到最近的数据中心中,那么我们就会查找这个元数据信息以及请求代理到最近的存储blob数据的数据中心。但是如果复制被延迟,我们仍然可以发送路由请求到最初存储blob的数据中心,这样它就能把数据复制到最近的数据中心,即使读取用户图像的成本有一点的延迟,但是“无伤大雅”。

未来的工作**

我们已经发布了第一个Blobstore的内部版本,尽管Blobstore开始仅仅只能处理一些图片相关的信息,但是我们正在往其中添加其他的功能和需要blob storage的用例。而且我们也不断对其进行迭代,让它更健壮、更具扩展性而且更易于进行维护。(编译/@CSDN王鹏,审校/包研)

Redis容量及使用规划 – Tim[后端技术]

Posted on

Redis容量及使用规划 – Tim[后端技术]

Tim[后端技术]

Tim's blog, 关于后端架构、互联网技术、分布式、大型网络应用、NoSQL、技术感悟等

Home | About | English version | 留言(Guestbook) | 订阅RSS Add to Google

Wednesday, Jan 5th, 2011 by Tim | Tags: memcache, memcached, mysql, redis

在使用Redis过程中,我们发现了不少Redis不同于Memcached,也不同于MySQL的特征。 (本文主要讨论Redis未启用VM支持情况)

1. Schema

MySQL: 需事先设计 Memcached: 无需设计 Redis: 小型系统可以不用,但是如果要合理的规划及使用Redis,需要事先进行类似如下一些规划

  • 数据项: value保存的内容是什么,如用户资料
  • Redis数据类型: 如String, List
  • 数据大小: 如100字节
  • 记录数: 如100万条(决定是否需要拆分)
  • ⋯⋯

上面的规划就是一种schema,为什么Redis在大型项目需要事先设计schema?因为Redis服务器有容量限制,数据容量不能超出物理内存大小,同时考虑到业务数据的可扩充性,记录数会持续增多、单条记录的内容也都会增长,因此需要提前规划好容量,数据架构师就是通过schema来判断当前业务的Redis是否需要“分库分表”以满足可扩展需求。

2. 容量及带宽规划

容量规划 MySQL: < 硬盘大小 Memcached: < RAM Redis: < RAM

带宽规划 由于Redis比MySQL快10倍以上,因此带宽也是需要事先规划,避免带宽跑满而出现瓶颈。

3. 性能规划(QPS)

当系统读写出现瓶颈,通常如何解决? MySQL 写: 拆分到多服务器 读: (1) 拆分 (2) 写少也可以通过增加Slave来解决

Memcached 读写: 都通过hash拆分到更多节点。

Redis: 写:拆分 读: (1) 拆分 (2) 写少也可以通过增加Slave来解决

4. 可扩展性

MySQL: 分库分表 Memcached: hash分布 Redis:也可以分库,也可以hash分布

小结

通过以上分析,Redis在很多方面同时具备MySQL及Memcached使用特征,在某些方面则更像MySQL。 由于Redis数据不能超过内存大小,一方面需要进行事先容量规划,保证容量足够;另外一方面设计上需要防止数据规模无限制增加,进而导致Redis不可扩展。 Redis需要象MySQL一样预先设计好拆分方案。

小问题

在MySQL中,通过预先建立多表或者库可以在业务增长时候将这些表或库一分为二部署到更多服务器上。 在Redis中,“分库分表”应当如何实现?有什么好的设计模式?

16 Comments »

  1. ciel says:

Jan 5th 2011 at 03:41

因为自己的项目可能会用到redis, 有个小问题想问问blog主. java+redis这样的组合有没有问题, jedis适合用到生产环境去了么?

  1. gyf19 says:

Jan 5th 2011 at 09:27

目前看来 redis VM 还不靠谱。

  1. 孙立 says:

Jan 5th 2011 at 09:31

由于redis使用内存,不方便事先建立,我觉得可以才行采用虚拟node的模式来实现拆分。

  1. empyreaner says:

Jan 5th 2011 at 10:06

redis的发展非常快,现在的这些问题可能等到几个月后就都不是问题了。 redis最近几天又加了个diskstorage分支,正在测试完全使用硬盘存储全部数据,内存只作为缓存。VM也许将在未来的版本中废弃。(作者的效率太高了) redis cluster也快要出来了,可以减少人工分库分hash的麻烦。

  1. 王道中强流 says:

Jan 5th 2011 at 10:10

我喜欢MongoDB多一点

  1. 神仙 says:

Jan 5th 2011 at 10:34

redis 2.0 已经可以只把部分数据放内存了,不知道效果怎样

  1. Zoom.Quiet says:

Jan 5th 2011 at 11:17

嗯嗯嗯,我们在大规模使用 Redis时,没有深入,直接在超过1kw 时就放棄了,

  • 内存不足
  • 速度成比例下降 直接使用自定义的内存结构体,速度提高30倍… 但凡是通用的 DB类服务,都内置了N多稳定性保证的机制, 整体上就无法满足极限状态中的响应… 只要业务稳定不变,及时替换成专用内存结构很靠谱;
  • 但是,无法兼顾所有意外情况,内存泄漏问题将逐步爆发
  • 慢慢追加各种保守措施后就发觉,其实又在实现另外一个 Redis 而已…
  1. yuping322 says:

Jan 5th 2011 at 13:24

在MySQL中,通过预先建立多表或者库可以在业务增长时候将这些表或库一分为二部署到更多服务器上。 在Redis中,“分库分表”应当如何实现?有什么好的设计模式?

个人看法. redis+zookeeper。 维持一致性在zookeeper里。

  1. tony says:

Jan 6th 2011 at 11:27

redis 消耗内存很严重,用不起。

  1. KnightE says:

Jan 6th 2011 at 17:50

用HASH把绝大部分GET/SET替换后,内存节约了很多。 性能上目前还没有遇到什么问题,目前有30多个节点在线上跑。 不过通过分片(节点)存储后,sort就无法很好的使用了,这是一个目前还需要从DB走的问题,不知道Tim有什么建议。

  1. redcreen says:

Feb 27th 2011 at 17:07

@KnightE: 数据分片后无法通过规则将需要sort的数据分布到同一个节点上么?

  1. eyu says:

May 26th 2011 at 10:50

把redis原型改造成了一个消息队列服务器,但是在释放大数据量的时候出现了速度严重下滑,替换成tcmalloc后恢复正常。另外貌似存在内存泄漏的问题。。。

  1. rjgcs123 says:

May 27th 2011 at 17:13

云集国内redis大佬的QQ群正在招募各路redis朋友,不管你是正在使用redis,还是在研究redis,或者是对redis感兴趣,你都可以加入到我们的阵营。大家一起讨论redis各类用法,key-value、list、set、map使用,redis优化、内存监控、主从配置等等问题,这里都会有高手给你解决。

注意啦,国内顶尖级别的redisQQ群是 43016055

  1. Sean says:

Jun 30th 2011 at 00:24

请问现在有没有人考虑用MemBase,貌似也支持持久化缓存的.

  1. Leric says:

Nov 30th 2011 at 10:41

Redis本来就不是设计作为通用数据库用的,想把所有数据都放在redis里的企图从一开始就是错误的。个人觉得Redis用纵向扩展就行了,空间不够加内存,性能不够换机器(估计性能问题会出现在网络IO上),能遇到更庞大的数据访问问题的地方,也就得人工shard数据了。Redis的主从的主要作用在高可用性上,性能上感觉意义不大。

RSS feed for comments on this post, TrackBack URI Cancel Reply

Leave a Comment

Name (required)

E-mail (required, never displayed)

URI

Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 3.0 License

YouTube 架构学习体会

Posted on

YouTube 架构学习体会 - 开源中国 OSChina.NET

当前访客身份:游客 [ 登录 | 加入开源中国 ]

开源中国

讨论区

当前位置: 讨论区 » 技术分享 » MySQL 搜 索 红薯

YouTube 架构学习体会

红薯 发表于 2011-11-21 23:20 1年前, 19回/7508阅, 最后回答: 5个月前

Java、PHP、Ruby、iOS、Python 等 JetBrains 开发工具低至 99 元(3折),详情»

这几天一直在关注和学习一些大型网站的架构,希望有一天自己也能设计一个高并发、高容错的系统并能应用在实践上。今天在网上找架构相关的资料时,看到一个被和谐的视频网站YouTube的架构分析,看了以后觉得自己又向架构走近了一步,于是赶快拿出来与大家一起分享。 YouTube发展迅速,每天超过1亿的视频点击量,但只有很少人在维护站点和确保伸缩性。这点和PlentyOfFish类似,少数人维护庞大系统。是什么原因呢?放心绝对不是靠人品,也不是靠寂寞,下面就来看看YouTube的整体技术架构吧。 平台

Apache Python Linux(SuSe) MySQL psyco,一个动态的Python到C的编译器 lighttpd代替Apache做视频查看 状态 支持每天超过1亿的视频点击量 成立于2005年2月 于2006年3月达到每天3千万的视频点击量 于2006年7月达到每天1亿的视频点击量 2个系统管理员,2个伸缩性软件架构师 2个软件开发工程师,2个网络工程师,1个DBA Web服务器 1,NetScaler用于负载均衡和静态内容缓存 2,使用mod_fast_cgi运行Apache 3,使用一个Python应用服务器来处理请求的路由 4,应用服务器与多个数据库和其他信息源交互来获取数据和格式化html页面 5,一般可以通过添加更多的机器来在Web层提高伸缩性 6,Python的Web层代码通常不是性能瓶颈,大部分时间阻塞在RPC 7,Python允许快速而灵活的开发和部署 8,通常每个页面服务少于100毫秒的时间 9,使用psyco(一个类似于JIT编译器的动态的Python到C的编译器)来优化内部循环 10,对于像加密等密集型CPU活动,使用C扩展 11,对于一些开销昂贵的块使用预先生成并缓存的html 12,数据库里使用行级缓存 13,缓存完整的Python对象

14,有些数据被计算出来并发送给各个程序,所以这些值缓存在本地内存中。这是个使用不当的策略。

应用服务器里最快的缓存将预先计算的值发送给所有服务器也花不了多少时间。只需弄一个代理来监听更改,预计算,然后发送。 视频服务 1,花费包括带宽,硬件和能源消耗 2,每个视频由一个迷你集群来host,每个视频被超过一台机器持有 3,使用一个集群意味着: -更多的硬盘来持有内容意味着更快的速度 -failover。如果一台机器出故障了,另外的机器可以继续服务 -在线备份 4,使用lighttpd作为Web服务器来提供视频服务: -Apache开销太大 -使用epoll来等待多个fds -从单进程配置转变为多进程配置来处理更多的连接 5,大部分流行的内容移到CDN: -CDN在多个地方备份内容,这样内容离用户更近的机会就会更高 -CDN机器经常内存不足,因为内容太流行以致很少有内容进出内存的颠簸 6,不太流行的内容(每天1-20浏览次数)在许多colo站点使用YouTube服务器 -长尾效应。一个视频可以有多个播放,但是许多视频正在播放。随机硬盘块被访问 -在这种情况下缓存不会很好,所以花钱在更多的缓存上可能没太大意义。 -调节RAID控制并注意其他低级问题 -调节每台机器上的内存,不要太多也不要太少 视频服务关键点

1,保持简单和廉价 2,保持简单网络路径,在内容和用户间不要有太多设备 3,使用常用硬件,昂贵的硬件很难找到帮助文档 4,使用简单而常见的工具,使用构建在Linux里或之上的大部分工具

5,很好的处理随机查找(SATA,tweaks)

缩略图服务 1,做到高效令人惊奇的难 2,每个视频大概4张缩略图,所以缩略图比视频多很多 3,缩略图仅仅host在几个机器上 4,持有一些小东西所遇到的问题: -OS级别的大量的硬盘查找和inode和页面缓存问题 -单目录文件限制,特别是Ext3,后来移到多分层的结构。内核2.6的最近改进可能让 Ext3允许大目录,但在一个文件系统里存储大量文件不是个好主意 -每秒大量的请求,因为Web页面可能在页面上显示60个缩略图 -在这种高负载下Apache表现的非常糟糕 -在Apache前端使用squid,这种方式工作了一段时间,但是由于负载继续增加而以失败告终。它让每秒300个请求变为20个 -尝试使用lighttpd但是由于使用单线程它陷于困境。遇到多进程的问题,因为它们各自保持自己单独的缓存 -如此多的图片以致一台新机器只能接管24小时 -重启机器需要6-10小时来缓存 5,为了解决所有这些问题YouTube开始使用Google的BigTable,一个分布式数据存储: -避免小文件问题,因为它将文件收集到一起 -快,错误容忍 -更低的延迟,因为它使用分布式多级缓存,该缓存与多个不同collocation站点工作 -更多信息参考Google Architecture,GoogleTalk Architecture和BigTable 数据库

1,早期 -使用MySQL来存储元数据,如用户,tags和描述 -使用一整个10硬盘的RAID 10来存储数据 -依赖于信用卡所以YouTube租用硬件 -YouTube经过一个常见的革命:单服务器,然后单master和多read slaves,然后数据库分区,然后sharding方式 -痛苦与备份延迟。master数据库是多线程的并且运行在一个大机器上所以它可以处理许多工作,slaves是单线程的并且通常运行在小一些的服务器上并且备份是异步的,所以slaves会远远落后于master -更新引起缓存失效,硬盘的慢I/O导致慢备份 -使用备份架构需要花费大量的money来获得增加的写性能 -YouTube的一个解决方案是通过把数据分成两个集群来将传输分出优先次序:一个视频查看池和一个一般的集群 2,后期 -数据库分区 -分成shards,不同的用户指定到不同的shards -扩散读写 -更好的缓存位置意味着更少的IO -导致硬件减少30% -备份延迟降低到0

-现在可以任意提升数据库的伸缩性

数据中心策略 1,依赖于信用卡,所以最初只能使用受管主机提供商 2,受管主机提供商不能提供伸缩性,不能控制硬件或使用良好的网络协议 3,YouTube改为使用colocation arrangement。现在YouTube可以自定义所有东西并且协定自己的契约 4,使用5到6个数据中心加CDN 5,视频来自任意的数据中心,不是最近的匹配或其他什么。如果一个视频足够流行则移到CDN 6,依赖于视频带宽而不是真正的延迟。可以来自任何colo 7,图片延迟很严重,特别是当一个页面有60张图片时

8,使用BigTable将图片备份到不同的数据中心,代码查看谁是最近的

学到的东西 1,Stall for time。创造性和风险性的技巧让你在短期内解决问题而同时你会发现长期的解决方案 2,Proioritize。找出你的服务中核心的东西并对你的资源分出优先级别 3,Pick your battles。别怕将你的核心服务分出去。YouTube使用CDN来分布它们最流行的内容。创建自己的网络将花费太多时间和太多money 4,Keep it simple!简单允许你更快的重新架构来回应问题 5,Shard。Sharding帮助隔离存储,CPU,内存和IO,不仅仅是获得更多的写性能 6,Constant iteration on bottlenecks: -软件:DB,缓存 -OS:硬盘I/O -硬件:内存,RAID 7,You succeed as a team。拥有一个跨越条律的了解整个系统并知道系统内部是什么样的团队,如安装打印机,安装机器,安装网络等等的人。

With a good team all things are possible。

文章出处:http://www.itivy.com/ivy/archive/2011/3/6/634350416046298451.html

标签: MySQL Nginx Lighttpd Apache Youtube 补充话题说明»

分享到 **

收藏 **

134 **

举报 **

0 | 3 **

按默认排序 | 显示最新评论 | 回页面顶部 共有19个评论 发表评论»

  • FoxHu

FoxHu 回答于 2011-11-22 18:05

举报 学习了! 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

  • 沈健

沈健 回答于 2011-11-22 18:25

举报 真是只有这么点人?9个人? 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

  • timo

timo 回答于 2011-11-22 18:52

举报 果然都是精兵强将 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

  • Richardx

Richardx 回答于 2011-11-22 21:58

举报 最近也在学习大型网站的架构 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

  • pizigou

pizigou 回答于 2011-11-23 09:29

举报 2,后期 -数据库分区 -分成shards,不同的用户指定到不同的shards -扩散读写 -更好的缓存位置意味着更少的IO -导致硬件减少30% -备份延迟降低到0 -现在可以任意提升数据库的伸缩性 这块红薯老大可否解说下?这里说得太笼统,看起来跟初期的结构没什么差别,貌似还增加了管理维护成本。 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

  • 该用户已被和谐

该用户已被和谐 回答于 2011-11-23 09:37

举报 不错! 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

  • javaspace

javaspace 回答于 2011-11-23 21:11

举报 有受益 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

  • 黑曜石

黑曜石 回答于 2011-11-23 21:37

举报 我1年前爬到一本youtube的构架PDF 貌似是在sohu的书库 当时我就震精了 偌大一个项目 只有4个engineer 其中哥们 活着只做两件事 一是写代码 二就是烂醉 醒来继续写代码 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

  • 我是常萎

我是常萎 回答于 2011-11-23 21:49

举报 太牛掰了,仅仅一年多就 每天1亿的视频点击,视频是从哪来的,都是网友上传的吗? --- 共有 2 条评论 ---

有帮助(0) | 没帮助(0) | 评论(2) | 引用此评论

  • 笨笨熊

笨笨熊 回答于 2011-12-08 16:15

举报 牛人基本在国外 有帮助(0) | 没帮助(0) | 评论(0) | 引用此评论

非会员用户 回评论顶部 | 回页面顶部

有什么技术问题吗? 我要提问 全部(4926)...红薯的其他问题

类似的话题

© 开源中国(OsChina.NET) | 关于我们 | 广告联系 | @新浪微博 | 开源中国手机版 | 粤ICP备12009483号-3 开源中国手机客户端: Android iPhone WP7

兼容xhtml

Posted on

兼容xhtml,html,ff,ie的滚动条css样式一览-div+css设计网

DIV- CSS.Net

Div+css入门教程

Div+css高级技术 Div+css布局

Web 标准化 浏览器兼容

SEO新手入门教程

SEO高级技术 Google SEO优化技术

百度SEO优化技术 SEO搜索引擎优化精华

SEM网站营销

相关内容

最新发布

首页 > Div+css高级技术

正文:兼容xhtml,html,ff,ie的滚动条css样式一览

日期:2009-7-8 12:15:16 | 来源 | 浏览次数 1423 | 复制网址 | 转发朋友 | 打印 | 评论

ID 7402 在用ie6浏览有框架的xhtml页面的时候,默认会水平和垂直滚动条会一起出现,这是ie6的一个bug,在firefox上是正常的,出现的原因是其对XHTML 1.0 transitional doctype的解释缺陷.对于这个bug一般有3种解决方案, 方法1: 代码: html { overflow-y: scroll; } 原理:强制显示ie的垂直滚动条,而忽略水平滚动条 优点:完全解决了这个问题, 允许你保持完整的XHTML doctype. 缺点:即使页面不需要垂直滚动条的时候也会出现垂直滚动条。 方法2: 代码: html { overflow-x: hidden; overflow-y: auto; } 原理:隐藏横向滚动,垂直滚动根据内容自适应 优点:在视觉上解决了这个问题.在不必要的时候, 未强制垂直滚动条出现. 缺点:只是隐藏了水平滚动条,如果页面真正需要水平滚动条的时候, 屏幕以外的内容会因为用户无法水平滚动,而看不到。 方法3: 代码: body { margin-right: -15px; margin-bottom: -15px; } 原理:这会在margin的水平和垂直方向上添加一个负值, IE添加了该精确数值后, 便会去除对滚动条的需求假象. 优点:在视觉上解决了这个问题.,垂直滚动根据内容自适应 缺点:由于"人为创建"了15px的外边距(margin), 所以无法使用该填充过的屏幕区域.

设置滚动条样式 在原来的html的时候,我们可以这样定义整个页面的滚动条 body{ scrollbar-3dlight-color:/#D4D0C8; //- 最外左 -// scrollbar-highlight-color:/#fff; //- 左二 -// scrollbar-face-color:/#E4E4E4; //- 面子 -// scrollbar-arrow-color:/#666; //- 箭头 -// scrollbar-shadow-color:/#808080; //- 右二 -// scrollbar-darkshadow-color:/#D7DCE0; //- 右一 -// scrollbar-base-color:/#D7DCE0; //- 基色 -// scrollbar-track-color:/#;//- 滑道 -// }

但是同样的代码,我们应用在 xhtml下就不起作用了,我相信好多好朋友也遇到过同样的问题 那么怎么才能在xhtml下应用滚动条样式呢?看下列代码 html{ scrollbar-3dlight-color:/#D4D0C8; //- 最外左 -// scrollbar-highlight-color:/#fff; //- 左二 -// scrollbar-face-color:/#E4E4E4; //- 面子 -// scrollbar-arrow-color:/#666; //- 箭头 -// scrollbar-shadow-color:/#808080; //- 右二 -// scrollbar-darkshadow-color:/#D7DCE0; //- 右一 -// scrollbar-base-color:/#D7DCE0; //- 基色 -// scrollbar-track-color:/#;//- 滑道 -// }

这段代码和上一段唯一的不同就是在css定义的元素上,一个是body一个是html。我们再测试一下,把html页面的"body"修改成"html"测试一下,发现依然可以实现效果。那到底是为什么呢?

从字面上来看,xhtml比html多一个x,那么这个x其实也就是xml,为什么要加一个xml在里面?其实最根本的原因就是要让html更加结构化标准化(因为html实在是太烂)。我们在html里面定义的是body,因为html不是很标准所以这样可以生效,而在xhtml里面这样就不行了,我看看那个图很明显,body标签本身不是根元素,只有html才是根元素,而页面的滚动条也是属于根元素的,所以这就是我们为什么定义body没有效果的原因,因为我们定义的只是一个子原素。ok,我们知道了原理,来做一个试验如果把定义"body"或"xhtml"换成"/", /{ scrollbar-3dlight-color:/#D4D0C8; //- 最外左 -// scrollbar-highlight-color:/#fff; //- 左二 -// scrollbar-face-color:/#E4E4E4; //- 面子 -// scrollbar-arrow-color:/#666; //- 箭头 -// scrollbar-shadow-color:/#808080; //- 右二 -// scrollbar-darkshadow-color:/#D7DCE0; //- 右一 -// scrollbar-base-color:/#D7DCE0; //- 基色 -// scrollbar-track-color:/#;//- 滑道 -// }

在html和xhtml都通过,因为/*就是定义页面上的任何标签当然也包括了“html”这个标签。

(ps:其实与其说是html与xhtml的区别到不如说是有无XHTML 1.0 transitional doctype的区别,但是如果你把页面的XHTML 1.0 transitional doctype去掉的话,那么这个页面就没有doctype,默认的显示方式就是html4.01,不过你要把XHTML 1.0 transitional doctype修改成HTML 4.01 doctype同样页面定义body也不会有效果的,虽然这个页面的标准是html 4.01)

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/keyunq/archive/2009/05/26/4217934.aspx 热门标签 滚动条,css样式,兼容,xhml,html,firefox,

上一篇: 防止网页被框架显示

下一篇: div滚动条样式一览 回复:

日期:2009-8-29 | 作者:匿名 | IP 61.136.225//

回复:

日期:2009-10-21 | 作者:匿名 | IP 113.205.25// ff 没有滚动条样式, 这个怎么兼容FF 呀? 回复:兼容xhtml,html,ff,ie的滚动条css样式一览

友情连接: