Category Archives: Arch-Scalability

[repost ]Scaling Play! to Thousands of Concurrent Requests

original:http://www.toptal.com/scala/scaling-play-to-thousands-of-concurrent-requests

Web Developers often fail to consider the consequences of thousands of users accessing our applications at the same time. Perhaps it’s because we love to rapidly prototype; perhaps it’s because testing such scenarios is simply hard.

Regardless, I’m going to argue that ignoring scalability is not as bad as it sounds—if you use the proper set of tools and follow good development practices.

Ignoring scalability is not as bad as it sounds—if you use the proper tools.

Lojinha

Some time ago, I started a project called Lojinha (which translates to “small store” in Portuguese), my attempt to build an auction site. (By the way, this project is open source). My motivations were as follows:

  • I really wanted to sell some old stuff that I don’t use anymore.
  • I don’t like traditional auction sites, especially those that we have down here in Brazil.
  • I wanted to “play” with the Play! Framework 2 (pun intended).

So obviously, as mentioned above, I decided to use the Play! Framework. I don’t have an exact count of how long it took to build, but it certainly wasn’t long before I had my site up and running with the simple system deployed at http://lojinha.jcranky.com. Actually, I spent at least half of the development time on the design, which uses Twitter Bootstrap (remember: I’m no designer…).

The paragraph above should make at least one thing clear: I did not worry about performance too much, if at all when creating Lojinha.

And that is exactly my point: there’s power in using the right tools—tools that keep you on the right track, tools that encourage you to follow best development practices by their very construction.

In this case, those tools are the Play! Framework and the Scala language, with Akka making some “guest appearances”.

Let me show you what I mean.

Immutability and Caching

It’s generally agreed that minimizing mutability is good practice. Briefly, mutability makes it harder to reason about your code, especially when you try to introduce any parallelism or concurrency.

Play! makes you use immutability a good portion of the time, and so does the Scala language itself. For instance, the result generated by a controller is immutable. Sometimes you might consider this immutability “bothersome” or “annoying”, but these “good practices” are “good” for a reason.

In this case, the controller’s immutability was absolutely crucial when I finally decided to run some performance tests: I discovered a bottleneck and, to fix it, simply cached this immutable response.

By caching, I mean saving the response object and serving an identical instance, as is, to any new clients. This frees the server from having to recalculate the result all over again. It wouldn’t be possible to serve the same response to multiple clients if this result were mutable.

The downside: for a brief period (the cache expire time), clients can receive outdated information. This is only a problem in scenarios where you absolutely need the client to access the most recent data, with no tolerance for delay.

For reference, here is the code for loading the start page with a list of products, without caching:

def index = Action { implicit request =>
  Ok(html.index(body = html.body(Items.itemsHigherBids(itemDAO.all(false))), menu = mainMenu)) 
}

Now, adding the cache:

def index = Cached("index", 5) {
  Action { implicit request =>
    Ok(html.index(body = html.body(Items.itemsHigherBids(itemDAO.all(false))), menu =     mainMenu))
  }
}

Quite simple, isn’t it? Here, “index” is the key to be used in the cache system and 5 is the expiration time, in seconds.

After caching, the throughput went up to 800 requests per second. That’s an improvement of more than 4x for less than two lines of code.

To test the effect of this change, I ran some JMeter tests (included in the GitHub repo) locally. Before adding the cache, I achieved a throughput of approximately 180 requests per second. After caching, the throughput went up to 800 requests per second. That’s an improvement of more than 4x for less than two lines of code.

Memory Consumption

Another area where the right tools can make a big difference is in memory consumption. Here, again, Play! pushes you in the right (scalable) direction. In the Java world, for a “normal” web application written with theservlet API (i.e, almost any Java or Scala framework out there), it’s very tempting to put lots of junk in the user session because the API offers easy-to-call methods that allow you do so:

session.setAttribute("attrName", attrValue);

Because it’s so easy to add information to the user session, it is often abused. As a consequence, the risk of using up too much memory for possibly no good reason is equally high.

With Play!, this is not an option—the framework simply doesn’t have a server side session space. The user session is kept in a browser cookie, and you have to live with it. This means that the session space is limited in size and type: you can only store strings. If you need to store objects, you’ll have to use the caching mechanism we discussed before. For example, you might want to store the current user’s e-mail address or username in the session, but you will have to use the cache if you need to store an entire user object from your domain model.

Play! keeps you on the right track, forcing you to carefully consider your memory usage, which produces first-pass code that is practically cluster ready.

Again, this might seem like a pain at first, but in truth, Play! keeps you on the right track, forcing you to carefully consider your memory usage, which produces first-pass code that is practically cluster ready—especially given that there is no server-side session that would have to be propagated throughout your cluster, making life infinitely easier.

Async Support

Play! also shines in async(hronous) support. And beyond its native features, Play! allows you to embedAkka, a powerful tool for async processing.

Altough Lojinha does not yet take full advantage of Akka, its simple integration with Play! made it really easy to:

  1. Schedule an asynchonrous e-mail service.
  2. Process offers for various products concurrently.

Briefly, Akka is an implementation of the Actor Model made famous by Erlang. If you are not familiar with the Actor Model, just imagine it as a small unit that only communicates through messages.

To send an e-mail asynchronously, I first create the proper message and actor. Then, all I need to do is something like:

EMail.actor ! BidToppedMessage(item.name, itemUrl, bidderEmail)

The e-mail sending logic is implemented inside the actor, and the message tells the actor which e-mail we would like to send. This is done in a fire-and-forget scheme, meaning that the line above sends the request and then continues to execute whatever we have after that (i.e., it does not block).

For more information about Play!’s native Async, take a look at the official documentation.

Conclusion

In summary: I rapidly developed a small application, Lojinha, capable of scaling up and out very well. When I ran into problems or discovered bottlenecks, the fixes were fast and easy, with much credit due to the tools I used (Play!, Scala, Akka, and so forth), which pushed me to follow best practices in terms of efficiency and scalability. With little concern for performance, I was able to scale to thousands of concurrent requests.

When developing your next application, consider your tools carefully.

[repost ]12306 外包给阿里巴巴、IBM 等大企业做是否可行?

original:http://www.zhihu.com/question/22451397

12306首秀被骂的狗血喷头后铁道部找来IBM、阿里巴巴等大企业要解决方案,给出的条件是资金管够但是问题得解决。几大企业最后都拒绝了。12306开始自己尝试解决问题。他们发现市面上可以买到的成套解决方案都不足以应付春运购票负载,所以只能自己改进已有的数据库(注:其实是改用VMware SQLFire/GemFire,这里我之前理解错误)。以前12306用的是小型机,发现性能严重不足,遂改用x86系统+linux平台(原平台为HP Superdome小型机,UNIX系统,Sybase ASE数据库)。最后他们的核心系统用了十几个节点(现在应该是17节点)的多路Xeon E7(具体几路待考),每个节点配1TB内存,数据库全部在内存中运行。2013年春运,12306系统峰值负载11万tps,与2012年淘宝双11活动峰值负载相当,新的系统基本经受住了考验。

 

补充:以上内容是我在2013年7月得知的信息,彼时没有任何公开来源提到过12306新系统的技术细节。甚至,当时局外人没人知道12306已经在2012年开始做了技术改造。直到数日之前,铁总首次向媒体公开了技术改造的详情:分布式集群内存数据技术引领12306技术革命。这篇文章给出的细节,与我之前看到的内容完全一致。由此我可以确信信息来源是此次技术升级的核心人士。

另外,关于第三方合作对方给出的信息是IBM、Oracle、Sybase全部不能满足要求,主要是这些厂商的方案部署以后,要升级时不能做到不停机灵活扩展。也就是说,IBM没有做到是他们技术不足“搞不定”。阿里巴巴参与了改造,负责了排队系统。此外,虽然后端经受住了压力,前端却如大家所看到的那样还是频频卡死。到底卡死的原因是前端水平太低还是访问压力太大,暂时没有可靠的信息供判断。

 

淘宝的问题是其系统架构是分散度较高的,各个订单之间关联度不大;而12306每出一张票都要对全线路做数据更新(因为一条线路存在多个站点),因此系统负载相较淘宝来说集中很多,直接搬淘宝的方案也无法解决问题。淘宝的应用类型决定了阿里巴巴可以通过部署大量的服务器来分散压力,但12306就不行。其实他们的核心系统的硬件成本不过数百万,不是他们不想采购更多服务器,而是买更多的服务器也没什么用途。最后,在经过软件层面的优化之后,12306的瓶颈其实是核心节点的CPU、内存性能。但是这个性能的提升不是朝夕的事情,而是受限于摩尔定律,基本上每两年才能翻一倍多些。(这段话是我自己的分析,不过现在12306的后端数据库系统应付现有需求已经够用了)

补充:关于座位实时复用,我看到的信息明确表明12306出票时,每出一张区间票都要实时调整该线路其他受影响区间段的余票数量,且这是很大的压力来源;另外,对方表示所使用的GemFire数据库与简单的memcache/redis数据缓冲不同,有着本质区别。

==========================

然后我说点对铁路系统购票困难现象的看法:

 

一种商品只要出现供不应求现象,那么结果只有两种:大家排队购买;出现黑市,变相提高商品的流通价格并抑制需求。

 

12306这个事情,就是标准的限价商品供不应求之后出现排队与黑市现象的例子。因为供不应求,所以有了黄牛、抢票软件与秒杀。如果供应充足,一个车次直到发车前都有一两张余票,那么黄牛、抢票就毫无存在价值,旅客也用不着守在电脑前和其他人比拼手速和网速以及电脑性能网络性能了。

 

现在供应不足的前提下,12306就算把系统做的性能再高,也只是会加快热门车次票务秒杀的速度而已——而这更会刺激抢票软件,大家为了在更短的时间里成功抢到队列名额就会不断提升自己的抢票性能。打个比方说就是一个店门前排队,消费者为了增加买到商品的概率去雇人代排,每个消费者都雇了好多人,造成店门口的通道拥挤不堪。为了减缓拥堵,商家不断拓宽通道,但每次一拓宽消费者们就会增加雇佣的排队劳力把新增的通道空间占满,形成恶性循环。这样下去,只要还存在供不应求的现象,这种循环就不会有终止的时候。也就是说,12306的问题主要不是出在网站本身。

 

那么怎样解决供应不足的问题?这么多年来铁路不断升级运力修建新线,已经建成全球最庞大的铁路运输系统,可是到了春运还是只能勉强应付。从这个角度来说铁路部门在供应不足的问题上也不该承担太大责任,他们已经做得很不错了。

 

那么问题的根源就出在不断增加的需求上了。为什么我国铁路系统需要承担如此庞大的客运流量需求?很显然,是因为全国范围的人口流动。大量务工上学人员过节要返乡,节后回驻地,这个刚性需求是合理的。可是为什么他们必须要到外地去打工上学?为什么数以亿计的人员要远离家乡去谋生求学?

 

最后我们会发现,区域发展不平衡才是罪魁祸首。正因为多少人在家乡无法得到足够的机会与资源,他们必须到发达地区奋斗和实现自己的价值。只要这种不平衡现象还在继续,每年春节前后就不可避免地出现大批人员全国范围流动的情况,就不可避免地出现运输能力不足的尴尬。改进12306也好,增加铁路网投资也好,最终都只是治标不治本。如果这个社会不去直面根本问题,那么这些表象的症结永无解开的时候。

 

说起来,有几个人愿意背井离乡呢?

=============================================

然后这个问题争了几天,我实在忍不住要吐槽一下了:

 

12306这个事情,网上有多少网友从一开始就献计献策了,也有不少网友提供了很不错的建议。但不得不说,很多网友在提建议时完全就是一种居高临下、自以为是的态度,上来就先认定需求简单可以轻松应付,随便有点经验的工程师就能搞定,12306出问题全怪体制太烂,国企效率低下,一帮人光拿钱不做事,技术水平太低……

 

淘宝2013年双11活动,峰值流量是一秒钟完成1.3万笔订单。12306在2014年1月6日全天网络出票400万张。看起来双11流量完爆12306是吧?等等!别忘了12306这400万张票可不是全天悠悠闲闲平均地卖出去的,而是分成10个时段集中被抢走的。每个时段开始放票后数分钟之内大部分票就已经被抢光了。以每个时段40万票,峰值持续三分钟估算,高峰期一分钟出票在10万张以上毫不夸张。诚然,一分钟10万订单还比不上淘宝2013双11,但别忘了一年以前阿里巴巴也只是达到了一分钟15万订单的水平而已(并且在高峰期一样卡爆)。而且一分钟10万出票还满足不了需求的,以旅客购票的热情来看,达到一分钟50万票都不一定能让所有旅客满意。

 

淘宝在2012年双11时已经是业界顶尖水平了,其软硬件技术皆为自主研发,既便如此面对一分钟十几万的订单量都会卡死。请问,觉得12306“需求简单,问题可以轻松解决”的,是不是水平已经高到了阿里巴巴都要请你们去领导整个技术团队的级别呢?是不是你们的方案可以轻松应付每分钟数十万笔订单,达到全球一流水平了?

 

淘宝面临的需求是业界从未有过的,所以淘宝的路很艰难。12306面临的需求是其他人遇到过的么?全世界哪个国家、哪种客运票务系统敢说自己的负载达到12306三分之一的水平?面对空前庞大的压力,诸位“技术高手”只是凭着自己一点程序员的经验,在电脑前一个人思考上一会儿就给出个“简单、实用、省钱、轻松应付”的解决方案——你们知不知道“自大”这两个字怎么写啊?

 

作为局外人,本来就难以了解铁路售票系统内部的业务逻辑。想出建议可以,那么是不是先收集些信息,了解下背景?是不是先拉出一份需求清单来,把客户的想法搞明白搞清楚了,然后再考虑技术实现?能不能不要上来就想着技术上怎么方便怎么做,把客户需求随意地简化?好多人提的方案在票务供应不足的情况下直接就超售了,难道你要让旅客前一分钟还为订到票高兴,下一分钟对着“您的票被取消”的提示破口大骂么?或者订票延迟确认——知不知道旅客看到选择的车次没能买到票后会做什么?马上去看其他车次有没有票啊!你延迟确认几分钟,然后对排队的账户做抽签,多少旅客会觉得自己被耽误了啊!旅客的要求就是速度越快越好,最好是下订单后一秒钟出结果才安心哩。这还仅仅是简单想一下就能知道的问题,局外人不了解或不能轻易想到的问题又有多少?诸位高谈阔论时,有没有虚心地去找找内部人士了解或者搜索类似的票务系统的研究论文?真觉得自己的头脑聪明绝顶,连背景调查都不做就可以轻松把握所有细节?还有,你们想出来的方案做没做过实验啊?考虑没考虑过硬件适配性啊?你们了解现在市面上能买到的硬件系统,什么样级别的能满足可靠性、性能和可扩展性、可维护性的需求么?你们在多路服务器平台上验证过你们的分布式数据库构想么?哦原来你们什么都没做过,怕是连多节点集群互联该用什么连接方式都不知道,你们拍下脑瓜,一句“那些问题都好解决”就完事儿了?就算你们自己没做过,找找类似的案例会累死么?研究下别人做过的经验就不够高贵冷艳么?就贬低自己技术水平了么?连类似的案例研究都没有,随口就是别人做得到我做得到,真觉得自己写过几行代码就多么伟大了么?

 

还有一些人,看说IBM没做就一口认定是12306故意排挤IBM,认定IBM解决这问题肯定没压力。好嘛,IBM什么时候做过如此规模的票务系统了?你细节什么都不知就预设结论了?为啥淘宝当年没选择IBM作为方案提供商而是自主研发?IBM的大数据业务主要集中在金融领域,这不代表它在其他领域就样样精通好不好?它能拿出的方案无非是Power7小型机平台,Power7在数据库性能上又比Xeon E7强多点?然后Power7系统卖多少钱了解么?后续维护难度多大了解么?把适合银行金融行业的平台放到12306来真的合适么?说起来,不就是因为“12306”和“IBM”这俩名字放一起,诸位内心里首先就给前者打了负分对后者仰视么?要是把“12306”换成“nasdaq”,那结论就又是一回事儿了——哦正好nasdaq没用IBM方案,可见nasdaq是排挤IBM内部人赚黑心钱是吧?不过2013年工商银行系统升级故障,应该是和方案提供商IBM无关的,肯定是国企的体制问题无误!

 

评价一个事物,首先不是了解背景、研究问题产生的原因,首先是看被评价者处于什么立场,打着什么标签。如果是“敌对阵营”那就毫不犹豫地踩上一脚再说话,接下来就算研究也只研究“它的错误在哪儿”,不考虑“它也有对的可能性”。在12306这个问题上就是:12306是国企,是铁总下属机构,所以它出了问题一定是自身原因。票务系统做不好一定是铁路方面不懂技术,把该用来请大企业做方案的钱自己贪掉了,一定不可能是大企业都没信心解决这问题。旅客普遍使用抢票软件也是12306的责任,不是供应不足的原因……

 

最后呢?12306还是做到了全球最强的客运票务系统。一贯被认为是因循守旧的国企,在选择技术方案时放弃沿用多年的小型机/UNIX平台去拥抱业界还是新鲜事物的基于x86/linux的大规模分布内存数据库系统,承受住了堪比2012年淘宝双11的压力。在这个领域,12306可以自豪地说自己是做的最好的案例。它还在卡,还是偶尔崩溃,页面还是难看,可是这些迟早会改进。这个过程中也还是会有冷嘲热讽,还是会有所谓的大牛指点江山,但最终解决春运高峰期一天数百万张秒杀售票的,还是12306自己。

 

所以,走自己的路,让别人去说吧。

//—————————————————————–

在下转一篇文章,给诸位提供一些材料,不管是支持还是反对,至少可以指出支持反对哪一点,免得鸡同鸭讲。文章是两年前的,欢迎知情人士指出两年来是否有什么变化。

文章主要说了12306这个网站有多独特,技术难点在哪里,有什么可能的改善方法。

==================

由http://12306.cn谈谈网站性能技术

2012年1月16日 陈皓

http://12306.cn网站挂了,被全国人民骂了。我这两天也在思考这个事,我想以这个事来粗略地和大家讨论一下网站性能的问题。因为仓促,而且完全基于本人有限的经验和了解,所以,如果有什么问题还请大家一起讨论和指正。(这又是一篇长文,只讨论性能问题,不讨论那些UI,用户体验,或是是否把支付和购票下单环节分开的功能性的东西)

业务

任何技术都离不开业务需求,所以,要说明性能问题,首先还是想先说说业务问题。

  • 其一有人可能把这个东西和QQ或是网游相比。但我觉得这两者是不一样的,网游和QQ在线或是登录时访问的更多的是用户自己的数据,而订票系统访问的是中心的票量数据,这是不一样的。不要觉得网游或是QQ能行你就以为这是一样的。网游和QQ 的后端负载相对于电子商务的系统还是简单。
  • 其二有人说春节期间订火车的这个事好像网站的秒杀活动。的确很相似,但是如果你的思考不在表面的话,你会发现这也有些不一样。火车票这个事,还有很多查询操作,查时间,查座位,查铺位,一个车次不 行,又查另一个车次,其伴随着大量的查询操作,下单的时候需要对数据库操作。而秒杀,直接杀就好了。另外,关于秒杀,完全可以做成只接受前N个用户的请求(完全不操作后端的任何数据, 仅仅只是对用户的下单操作log),这种业务,只需要在内存cache中放好可秒杀的数量,还可以把数据分布开来放,100商品,10台服务器一台放10个,无需在当时操作任何数据库。可以订单数够后,停止秒杀,然后批量写数据库。而且秒杀的商品不多。火车票这个不是像秒杀那么简单的,春运时间,几乎所有的票都是热门票,而且几乎是全国人民都来了。(淘宝的双十一也就3百万用户,而火车票瞬时有千万级别甚至是亿级别的)
  • 其三有人拿这个系统和奥运会的票务系统比较。我觉得还是不一样。虽然奥运会的票务系统当年也一上线就废了。但是奥运会用的是抽奖的方式,也就是说不存在先来先得的抢的方式,而且,是事后抽奖,事前只需要收信息,事前不需要保证数据一致性,没有锁,很容易水平扩展。
  • 其四订票系统应该和电子商务的订单系统很相似,都是需要对库存进行:1)占住库存,2)支付(可选),3)扣除库存的操作。这个是需要有一致性的检查的,也就是在并发时需要对数据加锁的。B2C的电商基本上都会把这个事干成异步的,也就是说,你下的订单并不是马上处理的,而是延时处理的,只有成功处理了,系统才会给你一封确认邮件说是订单成功。我相信有很多朋友都收到认单不成功的邮件。这就是说,数据一致性在并发下是一个瓶颈
  • 其五铁路的票务业务很变态,其采用的是突然放票,而有的票又远远不够大家分,所以,大家才会有抢票这种有中国特色的业务的做法。于是当票放出来的时候,就会有几百万人甚至上千万人杀上去,查询,下单。几十分钟内,一个网站能接受几千万的访问量,这个是很恐怖的事情。据说12306的高峰访问是10亿PV,集中在早8点到10点,每秒PV在高峰时上千万。

多说几句:

  • 库存是B2C的恶梦,库存管理相当的复杂。不信,你可以问问所有传统和电务零售业的企业,看看他们管理库存是多么难的一件事。不然,就不会有那么多人在问凡客的库存问题了。(你还可以看看《乔布斯传》,你就知道为什么Tim会接任Apple的CEO了,最主要的原因是他搞定了苹果的库存周期问题)
  • 对于一个网站来说,浏览网页的高负载很容易搞定,查询的负载有一定的难度去处理,不过还是可以通过缓存查询结果来搞定,最难的就是下单的负载。因为要访问库存啊,对于下单,基本上是用异步来搞定的。去年双11节,淘宝的每小时的订单数大约在60万左右,京东一天也才能支持40万(居然比12306还差),亚马逊5年前一小时可支持70万订单量。可见,下订单的操作并没有我们相像的那么性能高。
  • 淘宝要比B2C的网站要简单得多,因为没有仓库,所以,不存在像B2C这样有N个仓库对同一商品库存更新和查询的操作。下单的时候,B2C的 网站要去找一个仓库,又要离用户近,又要有库存,这需要很多计算。试想,你在北京买了一本书,北京的仓库没货了,就要从周边的仓库调,那就要去看看沈阳或 是西安的仓库有没有货,如果没有,又得看看江苏的仓库,等等。淘宝的就没有那么多事了,每个商户有自己的库存,库存就是一个数字,并且库存分到商户头上了,反而有利于性能扩展。
  • 数据一致性才是真正的性能瓶颈。有 人说nginx可以搞定每秒10万的静态请求,我不怀疑。但这只是静态请求,理论值,只要带宽、I/O够强,服务器计算能力够,并支持的并发连接数顶得住10万TCP链接的建立 的话,那没有问题。但在数据一致性面前,这10万就完完全全成了一个可望不可及的理论值了。

我说那么多,我只是想从业务上告诉大家,我们需要从业务上真正了解春运铁路订票这样业务的变态之处。

前端性能优化技术

要解决性能的问题,有很多种常用的方法,我在下面列举一下,我相信12306这个网站使用下面的这些技术会让其性能有质的飞跃。
一、前端负载均衡

通过DNS的负载均衡器(一般在路由器上根据路由的负载重定向)可以把用户的访问均匀地分散在多个Web服务器上。这样可以减少Web服务器的请求负载。因为http的请求都是短作业,所以,可以通过很简单的负载均衡器来完成这一功能。最好是有CDN网络让用户连接与其最近的服务器(CDN通常伴随着分布式存储)。(关于负载均衡更为详细的说明见“后端的负载均衡”)
二、减少前端链接数

我看了一下http://12306.cn,打开主页需要建60多个HTTP连接,车票预订页面则有70多个HTTP请求,现在的浏览器都是并发请求的(当然,浏览器的一个页面的并发数是有限的,但是你挡不住用户开多个页面,而且,后端服务器TCP链接在前端断开始,还不会马上释放或重要)。所以,只要有100万个用户,就有可能会有6000万个链接(访问第一次后有了浏览器端的cache,这个数会下来,就算只有20%也是百万级的链接数),太多了。一个登录查询页面就好了。把js打成一个文件,把css也打成一个文件,把图标也打成一个文件,用css分块展示。把链接数减到最低。
三、减少网页大小增加带宽

这个世界不是哪个公司都敢做图片服务的,因为图片太耗带宽了。现在宽带时代很难有人能体会到当拨号时代做个图页都不敢用图片的情形(现在在手机端浏览也是这个情形)。我查看了一下12306首页的需要下载的总文件大小大约在900KB左右,如果你访问过了,浏览器会帮你缓存很多,只需下载10K左右的文件。但是我们可以想像一个极端一点的案例,1百万用户同时访问,且都是第一次访问,每人下载量需要1M,如果需要在120秒内返回,那么就需要,1M * 1M /120 * 8 = 66Gbps的带宽。很惊人吧。所以,我估计在当天,12306的阻塞基本上应该是网络带宽,所以,你可能看到的是没有响应。后面随着浏览器的缓存帮助12306减少很多带宽占用,于是负载一下就到了后端,后端的数据处理瓶颈一下就出来。于是你会看到很多http 500之类的错误。这说明后端服务器垮了。
四、前端页面静态化

静态化一些不常变的页面和数据,并gzip一下。还有一个变态的方法是把这些静态页面放在/dev/shm下,这个目录就是内存,直接从内存中把文件读出来返回,这样可以减少昂贵的磁盘I/O。使用nginx的sendfile功能可以让这些静态文件直接在内核心态交换,可以极大增加性能。
五、优化查询

很多人查询都是在查一样的,完全可以用反向代理合并这些并发的相同的查询。这样的技术主要用查询结果缓存来实现,第一次查询走数据库获得数据,并把数据放到缓存,后面的查询统统直接访问高速缓存。为每个查询做Hash,使用NoSQL的技术可以完成这个优化。(这个技术也可以用做静态页面)

对于火车票量的查询,个人觉得不要显示数字,就显示一个“有”或“无”就好了,这样可以大大简化系统复杂度,并提升性能。把查询对数据库的负载分出去,从而让数据库可以更好地为下单的人服务。
六、缓存的问题

缓存可以用来缓存动态页面,也可以用来缓存查询的数据。缓存通常有那么几个问题:

1)缓存的更新。也叫缓存和数据库的同步。有这么几种方法,一是缓存time out,让缓存失效,重查,二是,由后端通知更新,一量后端发生变化,通知前端更新。前者实现起来比较简单,但实时性不高,后者实现起来比较复杂 ,但实时性高。

2)缓存的换页。内存可能不够,所以,需要把一些不活跃的数据换出内存,这个和操作系统的内存换页和交换内存很相似。FIFO、LRU、LFU都是比较经典的换页算法。相关内容参看Wikipeida的缓存算法

3)缓存的重建和持久化。缓存在内存,系统总要维护,所以,缓存就会丢失,如果缓存没了,就需要重建,如果数据量很大,缓存重建的过程会很慢,这会影响生产环境,所以,缓存的持久化也是需要考虑的。

诸多强大的NoSQL都很好支持了上述三大缓存的问题。

后端性能优化技术

前面讨论了前端性能的优化技术,于是前端可能就不是瓶颈问题了。那么性能问题就会到后端数据上来了。下面说几个后端常见的性能优化技术。
一、数据冗余

关于数据冗余,也就是说,把我们的数据库的数据冗余处理,也就是减少表连接这样的开销比较大的操作,但这样会牺牲数据的一致性。风险比较大。很多人把NoSQL用做数据,快是快了,因为数据冗余了,但这对数据一致性有大的风险。这需要根据不同的业务进行分析和处理。(注意:用关系型数据库很容易移植到NoSQL上,但是反过来从NoSQL到关系型就难了)
二、数据镜像

几乎所有主流的数据库都支持镜像,也就是replication。数据库的镜像带来的好处就是可以做负载均衡。把一台数据库的负载均分到多台上,同时又保证了数据一致性(Oracle的SCN)。最重要的是,这样还可以有高可用性,一台废了,还有另一台在服务。

数据镜像的数据一致性可能是个复杂的问题,所以我们要在单条数据上进行数据分区,也就是说,把一个畅销商品的库存均分到不同的服务器上,如,一个畅销商品有1万的库存,我们可以设置10台服务器,每台服务器上有1000个库存,这就好像B2C的仓库一样。
三、数据分区

数据镜像不能解决的一个问题就是数据表里的记录太多,导致数据库操作太慢。所以,把数据分区。数据分区有很多种做法,一般来说有下面这几种:

1)把数据把某种逻辑来分类。比如火车票的订票系统可以按各铁路局来分,可按各种车型分,可以按始发站分,可以按目的地分……,反正就是把一张表拆成多张有一样的字段但是不同种类的表,这样,这些表就可以存在不同的机器上以达到分担负载的目的。

2)把数据按字段分,也就是竖着分表。比如把一些不经常改的数据放在一个表里,经常改的数据放在另外多个表里。把一张表变成1对1的关系,这样,你可以减少表的字段个数,同样可以提升一定的性能。另外,字段多会造成一条记录的存储会被放到不同的页表里,这对于读写性能都有问题。但这样一来会有很多复杂的控制。

3)平均分表。因为第一种方法是并不一定平均分均,可能某个种类的数据还是很多。所以,也有采用平均分配的方式,通过主键ID的范围来分表。

4)同一数据分区。这个在上面数据镜像提过。也就是把同一商品的库存值分到不同的服务器上,比如有10000个库存,可以分到10台服务器上,一台上有1000个库存。然后负载均衡。

这三种分区都有好有坏。最常用的还是第一种。数据一旦分区,你就需要有一个或是多个调度来让你的前端程序知道去哪里找数据。把火车票的数据分区,并放在各个省市,会对12306这个系统有非常有意义的质的性能的提高
四、后端系统负载均衡

前面说了数据分区,数据分区可以在一定程度上减轻负载,但是无法减轻热销商品的负载,对于火车票来说,可以认为是大城市的某些主干线上的车票。这就需要使用数据镜像来减轻负载。使用数据镜像,你必然要使用负载均衡,在后端,我们可能很难使用像路由器上的负载均衡器,因为那是均衡流量的,因为流量并不代表服务器的繁忙程度。因此,我们需要一个任务分配系统,其还能监控各个服务器的负载情况。

任务分配服务器有一些难点:

  • 负载情况比较复杂。什么叫忙?是CPU高?还是磁盘I/O高?还是内存使用高?还是并发高?还是内存换页率高?你可能需要全部都要考虑。这些信息要发送给那个任务分配器上,由任务分配器挑选一台负载最轻的服务器来处理。
  • 任务分配服务器上需要对任务队列,不能丢任务啊,所以还需要持久化。并且可以以批量的方式把任务分配给计算服务器。
  • 任务分配服务器死了怎么办?这里需要一些如Live-Standby或是failover等高可用性的技术。我们还需要注意那些持久化了的任务的队列如何转移到别的服务器上的问题。

我看到有很多系统都用静态的方式来分配,有的用hash,有的就简单地轮流分析。这些都不够好,一个是不能完美地负载均衡,另一个静态的方法的致命缺陷是,如果有一台计算服务器死机了,或是我们需要加入新的服务器,对于我们的分配器来说,都需要知道的。另外,还要重算哈希(一致性hash可以部分解决这个问题)。

还有一种方法是使用抢占式的方式进行负载均衡,由下游的计算服务器去任务服务器上拿任务。让这些计算服务器自己决定自己是否要任务。这样的好处是可以简化系统的复杂度,而且还可以任意实时地减少或增加计算服务器。但是唯一不好的就是,如果有一些任务只能在某种服务器上处理,这可能会引入一些复杂度。不过总体来说,这种方法可能是比较好的负载均衡。
五、异步、 throttle 和 批量处理

异步、throttle(节流阀) 和批量处理都需要对并发请求数做队列处理的。

  • 异步在业务上一般来说就是收集请求,然后延时处理。在技术上就是可以把各个处理程序做成并行的,也就可以水平扩展了。但是异步的技术问题大概有这些,a)被调用方的结果返回,会涉及进程线程间通信的问题。b)如果程序需要回滚,回滚会有点复杂。c)异步通常都会伴随多线程多进程,并发的控制也相对麻烦一些。d)很多异步系统都用消息机制,消息的丢失和乱序也会是比较复杂的问题。
  • throttle 技术其实并不提升性能,这个技术主要是防止系统被超过自己不能处理的流量给搞垮了,这其实是个保护机制。使用throttle技术一般来说是对于一些自己无法控制的系统,比如,和你网站对接的银行系统。
  • 批量处理的技术,是把一堆基本相同的请求批量处理。比如,大家同时购买同一个商品,没有必要你买一个我就写一次数据库,完全可以收集到一定数量的请求,一次操作。这个技术可以用作很多方面。比如节省网络带宽,我们都知道网络上的MTU(最大传输单元),以态网是1500字节,光纤可以达到4000多个字节,如果你的一个网络包没有放满这个MTU,那就是在浪费网络带宽,因为网卡的驱动程序只有一块一块地读效率才会高。因此,网络发包时,我们需要收集到足够多的信息后再做网络I/O,这也是一种批量处理的方式。批量处理的敌人是流量低,所以,批量处理的系统一般都会设置上两个阀值,一个是作业量,另一个是timeout,只要有一个条件满足,就会开始提交处理。

所以,只要是异步,一般都会有throttle机制,一般都会有队列来排队,有队列,就会有持久化,而系统一般都会使用批量的方式来处理

 

云风同学设计的“排队系统” 就是这个技术。这和电子商务的订单系统很相似,就是说,我的系统收到了你的购票下单请求,但是我还没有真正处理,我的系统会跟据我自己的处理能力来throttle住这些大量的请求,并一点一点地处理。一旦处理完成,我就可以发邮件或短信告诉用户你来可以真正购票了。

 

在这里,我想通过业务和用户需求方面讨论一下云风同学的这个排队系统,因为其从技术上看似解决了这个问题,但是从业务和用户需求上来说可能还是有一些值得我们去深入思考的地方:

 

1)队列的DoS攻击。首先,我们思考一下,这个队是个单纯地排队的吗?这样做还不够好,因为这样我们不能杜绝黄牛,而且单纯的ticket_id很容易发生DoS攻击,比如,我发起N个 ticket_id,进入购票流程后,我不买,我就耗你半个小时,很容易我就可以让想买票的人几天都买不到票。有人说,用户应该要用身份证来排队, 这样在购买里就必需要用这个身份证来买,但这也还不能杜绝黄牛排队或是号贩子。因为他们可以注册N个帐号来排队,但就是不买。黄牛这些人这个时候只需要干一个事,把网站搞得正常人不能访问,让用户只能通过他们来买。

 

2)对列的一致性?对这个队列的操作是不是需要锁?只要有锁,性能一定上不去。试想,100万个人同时要求你来分配位置号,这个队列将会成为性能瓶颈。你一定没有数据库实现得性能好,所以,可能比现在还差。抢数据库和抢队列本质上是一样的

 

3)队列的等待时间。购票时间半小时够不够?多不多?要是那时用户正好不能上网呢?如果时间短了,用户不够时间操作也会抱怨,如果时间长了,后面在排队的那些人也会抱怨。这个方法可能在实际操作上会有很多问题。另外,半个小时太长了,这完全不现实,我们用15分钟来举例:有1千万用户,每一个时刻只能放进去1万个,这1万个用户需要15分钟完成所有操作,那么,这1千万用户全部处理完,需要1000*15m = 250小时,10天半,火车早开了。(我并非信口开河,根据铁道部专家的说明:这几天,平均一天下单100万,所以,处理1000万的用户需要十天。这个计算可能有点简单了,我只是想说,在这样低负载的系统下用排队可能都不能解决业务问题

 

4)队列的分布式。这个排队系统只有一个队列好吗?还不足够好。因为,如果你放进去的可以购票的人如果在买同一个车次的同样的类型的票(比如某动车卧铺),还是等于在抢票,也就是说系统的负载还是会有可能集中到其中某台服务器上。因此,最好的方法是根据用户的需求——提供出发地和目的地,来对用户进行排队。而这样一来,队列也就可以是多个,只要是多个队列,就可以水平扩展了。这样可以解决性能问题,但是没有解决用户长时间排队的问题。

 

我觉得完全可以向网上购物学习。在排队(下单)的时候,收集好用户的信息和想要买的票,并允许用户设置购票的优先级,比如,A车次卧铺买 不到就买 B车次的卧铺,如果还买不到就买硬座等等,然后用户把所需的钱先充值好,接下来就是系统完全自动地异步处理订单。成功不成功都发短信或邮件通知用户。这样,系统不仅可以省去那半个小时的用户交互时间,自动化加快处理,还可以合并相同购票请求的人,进行批处理(减少数据库的操作次数)。这种方法最妙的事是可以知道这些排队用户的需求,不但可以优化用户的队列,把用户分布到不同的队列,还可以像亚马逊的心愿单一样,通过一些计算就可以让铁道部做车次统筹安排和调整(最后,排队系统(下单系统)还是要保存在数据库里的或做持久化,不能只放在内存中,不然机器一down,就等着被骂吧)。

小结

写了那么多,我小结一下:

 

0)无论你怎么设计,你的系统一定要能容易地水平扩展。也就是说,你的整个数据流中,所有的环节都要能够水平扩展。这样,当你的系统有性能问题时,“加30倍的服务器”才不会被人讥笑。

 

1)上述的技术不是一朝一夕能搞定的,没有长期的积累,基本无望。我们可以看到,无论你用哪种都会引发一些复杂性,设计总是在做一种权衡。

 

2)集中式的卖票很难搞定,使用上述的技术可以让订票系统能有几佰倍的性能提升。而在各个省市建分站,分开卖票,是能让现有系统性能有质的提升的最好方法

 

3)春运前夕抢票且票量供远小于求这种业务模式是相当变态的,让几千万甚至上亿的人在某个早晨的8点钟同时登录同时抢票的这种业务模式是变态中的变态。业务形态的变态决定了无论他们怎么办干一定会被骂。

 

4)为了那么一两个星期而搞那么大的系统,而其它时间都在闲着,有些可惜了,这也就是铁路才干得出来这样的事了。

 

更新2012年9月27日

Alexa 统计的12306的PV (注:Alexa的PV定义是:一个用户在一天内对一个页面的多次点击只算一次)

本文转载时请注明作者和出处,请勿于记商业目的

(转载本站文章请注明作者和出处 酷 壳 – CoolShell.cn ,请勿用于任何商业用途)

 

====================

注:有个地方要更新一下,以免误导。文中在比较 12306 和淘宝时提到:

「去年(2011年)双11节,淘宝的每小时的订单数大约在60万左右。」
淘宝的双十一也就3百万用户,而火车票瞬时有千万级别甚至是亿级别的。

文中这个数字现在已经不适用。淘宝的容量两年来有了巨大的提升。
2013 年淘宝双11的第一分钟,产生 33.9 万笔交易,有 1370 万人次同时在线。当天最高峰时一分钟有 79 万笔支付宝交易。

[repost ]Data massage: How databases have been scaled from one to one million nodes

original:http://www.slideshare.net/nixnutz/data-massage-how-databases-have-been-scaled-from-one-to-one-million-nodes

 

[repost ]阿里周宝方:集中式严重制约是去IOE的核心原因

original:http://tech.qq.com/a/20130830/016163.htm , http://www.csdn.net/article/2013-08-29/2816756-SDCC2013-ali-ioe

[导读]同时,他还认为,去IOE技术难以复制,对接去IOE技术的云计算平台更合适,去IOE需要信念,才能走得下去。

腾讯科技讯8月30日消息,2013SDCC中国软件开发者大会在北京新云南皇冠假日酒店开幕,本次大会的主题为“软件定义未来”,阿里技术保障部DBA负责人周宝方在大会上发表演讲,他表示,斯诺登事件让更多企业考虑去IOE的必要性,但是去IOE拥有很高的技术门槛,较大的额技术风险,水很深。

他认为,集中式严重制约是去IOE的核心原因,而IOE本身限制了很多开发者技术的发挥和许多企业的长远发展。同时,他还认为,去IOE技术难以复制,对接去IOE技术的云计算平台更合适,去IOE需要信念,才能走得下去。

今年,SDCC 2013将围绕软件定义数据中心、大数据、开放平台等九大主题,解析各种平台技术,分享生态系统构建之道;邀请国内外业界领袖和知名技术专家就本年度主流技术、产品、应用实践等热点议题进行深入分享。

 

阿里周宝方:集中式严重制约是去IOE的核心原因

 

阿里周宝方:集中式严重制约是去IOE的核心原因(腾讯科技配图)

以下是周宝方演讲实录:

周宝方:大家好,很荣幸参加今天的大会,因为之前也是有很多故事,在互联网上,包括最近斯诺登的事件,确实再次把阿里的去IOE推了上来。我把阿里去IOE的过程思考走过的弯路跟大家做一个分享。

先自我介绍一下,在阿里我花名叫后羿,大家知道阿里是花名文化,我数据库做的时间比较长一点,在阿里整个后端技术整合,我负责整个阿里的数据库技术。在过去几年去IOE,我参与了这个战略的制定,也是实施者。

首先讲IOE,去IOE的过程的话,简单跟大家展开一下,阿里在2010年到2013年整个这几年预算的指导思路演进的过程。为什么要这么做?其实从这点做是很容易大家能看出,阿里这几年在技术思路上的演进和变化。以及这中间所衍生出来一些技术逐步逐步成长,在中间都可以看得出来。这是2010年当时我在淘宝,当时我们做预算的时候,这是很重要预算指导的原则,当时确定这去小型机,甲骨文、EMC,这中间很重要落脚主要是技术的投入,希望把去小型机的替代技术可以摸索起来,一会儿也会讲这中间的故事,也不是一蹴而就,这中间有一些背景。2010年我们摸索去小型机过程当中,背后一个思想是我们阿里在转变,转变过程当中最主要一个原因,我们希望以互联网的技术来解决电子商务这样一个应用。

2011年我们去小型机技术逐步积累过程当中,已经开始逐步逐步全面去IOE,这中间已经是开始,如果当年2010年不再购买小型机,那2012年我们不购买EMC的设备,背后是坚定的互联网技术逐步逐步往我们深入系统去IOE的技术。

2012年整个不再过多谈去小型机,我们认为去小型机已经翻过来了,这个随着我们基础技术的整合,这个阿里去IOE技术,正在向整个集团全面推进。同时去IOE,整个阿里去商用化整个技术的进程也开始全面的启动,这是简单列一下去LB设备,其实还有很多工作我们都展开。

整个阿里每年年底做预算,不是简单盘点钱的事,而是我们梳理未来技术一年的规划。很多的项目都是要逐步逐步PK过去,为什么用这些技术,有没有更合理的技术框架?

2013年我们坚定以云计算的思路逐步逐步应用到阿里上去。

总结一下这四年整个的过程,我们简单做一个总结,从最初我们在基础计算积累不够,我们通过付费方式换取时间,我们买一些高帅富设备,解决发展。我们发现这些技术设备解决不了我们问题,我们开始采用一些商业技术,商业技术之后就是开源技术,开源技术之后我们能力在增强,我们有各种各样多元化技术的思路,来驾驭我们整个阿里的在线系统。

下面跟大家说一下去IOE的历程,这个图大家比较熟悉,所有典型的IOE的架构都长的很像,通过前端应用服务器联上数据库的系统。数据库底层通过交互机做接连,存储之间做一个HH的镜像,很多IOE的系统基本上长的大同小异。最初这个系统是什么样子?商品库最初放在一个系统当中,随着商品越来越大,一个系统已经容纳不了那么多,承载不了业务发展,我们考虑业务做垂直拆分,拆分完以后并没有解决我们问题。商品库垂直化拆完以后我们进入另外一个层面,对于这中间疯狂增长,我们疯狂对它进行水平拆分,这时候我们系统进入几何基数,上涨的交易。我们商品每年在往上翻,交易系统也是如此,这是对我们来说成本上面临非常大的压力。

我们很清楚一个IBM小型机,比如说P570、P590,满配的基础上价格大家清楚什么样级别,应该是五六百万的级别。当时市场的售价差不多在这样一个级别,在满配的基础上。这个只是说在这里一个很小的单元,需要这么多的价格,如果是按业务增长速度发展下去的话,这个相当于给某些厂商打工了。所以这是当时我们面临的现状,在OLap层面,现在网上也找得到,当时有那么一阵子甲骨文推淘宝有20个节点的RAC,好像是亚洲最多的RAC的集群,我们转换的时候换了一个思路,逐步放弃了RAC,而是用云来处理我们阿里的大数据。对于大数据底层处理的技术,我们传统的技术厂商技术基因决定这个不能彻底解决我们问题,这种矛盾在互联网行业特别明显。

讲一下去IOE核心的原因。之前在网上一直好像是有很多版本,其实都不正确,我做一下总结。

1、集中式强大单点远远满足不了,阿里特别是当时淘宝爆炸式业务增长应用的模式。所以这个给我们带来很多痛苦。这里举到稳定性的方面,当你很多系统都放在一个强大的单点里面,你一个单点出现故障的话,意味着影响面比较大,所以我们更倾向于这种分布式的这种架构。当一个单点出现问题的时候,它也只是影响局部的一部分,而在这个过程当中对局部的单点我们做非常灵活HH的策略,在稳定方面我们碰到了问题。在IDC切换方面我们遇到一些问题,中国IDC切换现状比较恶劣,各种各样条件不太好,对于我们而言经常要做一个事情就是容灾切换,当你应用系统三天两头碰到网络电力各种原因做快速切换的时候,这中间涉及数据库是成百上千的节点时候,你IOE的系统根本没办法满足你瞬间满足快速灵活的切换,这是当时让我们很头疼的点。还有类似阿里的双十一,我们几周时间让我们时间做到几倍这样策略,尽管我们IOE体现有限容量扩展性,但是毕竟这是比较有限的。所以集中式严重的制约了阿里业务的发展。另外秋游一些原因我们也正在面临的,比如说我们技术面临失控,这个怎么理解?比如说在双十一情况下,可能全球范围没有达到这样高程度并发的时候,会出现非常极端的一些问题。而这种问题你如果要求助于那些厂商,厂商也要拿具体业务数据做定制化的开发这中间来来回回时间成本是我们阿里难以承受。

比如说阿里双十一凌晨那一瞬间可能几个亿的交易就过去了,我们工程师到最后除了等待,什么都不能做,那我们做不到这种层面。所以说IOE确实让我们当时的技术面临失控的风险。

2、另外确确实实我感受到IOE的技术限制了技术潜力的发挥。这中间大家可以看到我们有很多技术,即便对这些技术把玩非常娴熟,毕竟是产品技术,这产品有很多底层细节你根本无法掌控。

3、IOE是专用的设备,对机架、电力、网络要求,要单独为它设计。像阿里快速发展,我们那时候要买服务器都是问题,你机房要摆那么过高帅富的设备,我们有很多小型机要进来,要用起重机给吊进来,这个成本难以承受的。阿里去IOE核心原因,我们总结一下大致有这么一些。非要增加一点就是安全。

4、安全。怎么理解安全?大家想想斯诺登事件,成本是我们比较次要的原因。说起去IOE相关技术的难点,当时我们也逐步逐步在摸索过来,首先我们解决是把一个数据库,特别对专业数据库我们逐步逐步要剥离,把数据库当做一个存储来用,不是这中间一大堆的应用逻辑。这中间怎么做事物的拆分,做数据的类别,怎么做数据的路由和,数据安全,规模化运维,异步数据同构,都是我们面临非常实际的问题。

有关去IOE的话题,我们这次有两场来讲,主要从宏观战略方面讲我们阿里为什么去IOE,明天有一场跟大家讲去IOE过程当中相关核心技术细节。这个简单给大家介绍一下我们当时面临一些难点。

跟大家介绍一下去IOE,在阿里内部Kickoff前后的故事。外部环境有这样几点,2009年2010年我们发现硬件技术突飞猛进的在发展,当时PC和小型机的处理能力不相上下。阿里内部我们做服务化,我们把各个应用系统,已经真正以服务化的方式来做了改造,所以对于我们几大C的应用系统,我们可以很确定对某几个库做底层的改造,上层做好服务商松偶合改造。我们2009年11月份做2010年的预算,当时我在预算当中提了一句,我们接下来正在尝试PC技术替代小型机的技术。当时我和我老板郑飞在当年预算,也是把这句写上去了,我们CTO抓住了这句话,既然已经思考这个问题,不如坚定写下来,说以后再不买,并且往这个方向来靠。所以当年的预算就2009年11月份预算其实是我们整个阿里去IOE的发端。中间故事其实都是来源于那一年预算,去IOE从当年的去小型机开始的。

首个在淘宝的核心业务系统上来做去IOE的是我们的商品库,这是在整个阿里去IOE历史上最漫长的一次技术的尝试。我说首个吃螃蟹这样一个项目。它有很重要的意义,它为未来后期整体去IOE的技术,这个过程当中摸索,逐步逐步一些技术上的探索,都是奠定了很好的基础。其实我们整个去IOE方面技术的成熟,主要的摸索其实来自于我们的商品库。它大概经历了三个阶段。

1、我们首先是之前就已经完成了对我们商品库Oracle,做了读写分离,我们当时说把读的流量从我们图库切到搜索上面,虽然有几秒的延迟,当时做这个决定内部压力和质疑声非常大,经过严密评估切过去之后发现效果还是比较好。我们把读的那部分已经切完之后,剩下部分我们尝试对小型机来做进一步的改造。作为预算我们接下来半年进入实质性去小型机的阶段,这中间大概花了半年时间,我们完成去小型机摸索的过程。完了以后我们剩下一年立刻展开去IOE的过程。阿里商品库的去IOE经历了这么几步,首先是读写分离,把读那部分分掉。第二步是我们去小型机,小型机去完,我们紧接着尝试去Oracle和EMC。我们去小型机在业内没有任何前任经验可借鉴的东西,当时质疑声非常大,我们后期做这个技术认证的过程当中我们逐步逐步在这中间积累了信心和经验。

整个列一下我们阿里系去IOE过程当中几个关键事件。我们20101月份启动,大概2011年7月份我们完成商品库的去IOE,分两步。我们差不多花了一年多的时间完成了商品库,可是后面交易其他一些核心系统,去IOE的过程花的时间很短。

这里可以看到一个动作,当我们这个技术逐步逐步积累成熟的时候,我们到后期的时候在推动这个技术战略的节奏是非常紧凑非常快的。随着后期整个数据库的融合,像B2B,阿里金融、以及支付宝都在全面推动去IOE,以至于今年6月4号整个阿里现金流系统,我们广告结算系统已经彻底摆脱了IOE的一个技术体系。

这是当年首批小型机下降的仪式,说是仪式很简单就是拍几张照,冷冷清清,当时我们只是自己觉得这件事情是对的,其实对这件事情关注人并不是那么多,只是一群人一直在这个方向上坚持下去。这是我们几个月前阿里最好一台小型机下线的仪式,可以看到在这个过程当中我们整个阿里技术高管全部参加进来。小型机作为工程放在我们支付宝的楼下大厅供大家展览。

去IOE后的相关技术架构,很简单,一批真正高富帅的机器最后转化为一对PC机。这中间核心思路是真正以随处可见PC的机的技术,替代一些专用集中的商用设备。对互联网行业其实就像是它所需要资源非常多,增长非常快,任何专用设备都有可能拖慢我们设备。

这是一个典型去IOE之后整体的架构,这里可以看到我们应用系统通过我们分布式数据层访问到我们数据,一方面是我们分布式缓存另外一方面是TFS。DB之间的部署是跨IDC部署的,底层做了数据的分布。DBC容灾由我们另外一套系统完成的。调动系统控制整个切换系统,最后达到我们数据层做底层切换。在整个阿里其实我们复杂庞大数据库都是由这样底层的模型堆积起来。

大家可以看到这个里数据的HH,首先大家可以看到就是说在我们这里,在分布式缓存这个我们命中率在90%以上,我们的毒只有10%不到落到DB层面,DB层面整个命中率又会是差不多90%这样一个命中率。就是说这中间如果我一个节点或者中间一块盘坏掉,对于整个上层的应用,对可用性的影响其实是微乎其微的。即便我们一个单点出现故障,我们底层的HH系统可以做到从一个IDC切到另外一个IDC,秒级可以做到数据弥补和检查,在这个逻辑图上可以看得很清楚。

和去IOE相关的战略价值。回过头我们做完这件事我们确实感触比较深,我们感觉自身是受益者。我们有这么几点战略受益跟大家做分析。

首先去IOE整个架构体系赋予阿里非常灵活的技术架构,类似像双十一非常残酷这样业务促销,其实对于阿里而言都相对而说很淡定做业务的扩容。我们做完这个技术是说我们真正技术自主可控起来,在明天我们介绍相关技术可以看到,我们数据库技术有很多数据点我们深入参与,并且从零开始做,无论从存储层面,从分布式数据处理,以及我们规模化研发支撑体系和自动化运维平台,都有大量的经验和产品的积累。

真正完成这件事情以后我们技术可以做到自主可控,同时又很多工程技术人才积累下来,我们现在回过头看这些人才是阿里很重要的竞争力核心之一,可以让我们成本降得最低。

举个例子,刚才我提到商品库,我们可以用原来IOE时代20%的成本把这个容量做到原来5到6倍,大家可以看一下,这中间真正是说我们做了这件事,从成本上可以给企业带来的竞争力。我们经常谈和竞争对手怎么样讲,背后技术带给企业的竞争力,很重要就是说单笔交易我们真正比竞争对手便宜多少,我们完成这个技术改造之后,我们可以用很低的成本支持我们业务快速成长。中间其实需要我们工程师做这些事情。成本解决我们有很多技术环节都是我们人深度参与进去,碰到斯诺登事件的时候至少我们觉得相对安全。

简单给大家介绍一下,这里不展开,去IOE相关的一些核心技术。首先是存储技术。存储技术我这里给大家辟谣。说到阿里去IOE,就说阿里用mysql,错了,阿里去IOE,mysql只是其中一个,有Oceanbase、RDS。在大数据库不用考虑一致性的问题,其实对于大型分割系统而言这些都是你要考虑,这中间很多技术点需要我们做这件事情的工程师逐步逐步解决的问题。数据流解决什么?真正个别应用系统的数据同步,在IDC情况下怎么做到高存储,这个怎么快速的存储这是要解决第三大技术。

第四个技术原来只需要你搞搞几十台的Oracle设备就可以,现在你面临数百台,数千台,对于运维体系,都是全新一套体系,你需要有一套架构可以架构它,你需要有一套平台,对研发支持的人员把这个复杂性对上层分装好,这里我们研发体系、分装体系会做很多技术。阿里并不是以Mysql技术,还有很多技术。

我们去完IOE相关技术的沉淀,我们做完这些这样以后我们有很多技术沉淀下来,这是为阿里进一步扩大业务范围积累很好经验和基础。同时很多的经验在我们来看,阿里去IOE的经验属于全社会的经验,我们非常希望把我们中间的经验和思考,在以后有机会合适的情况跟大家做这样一个分享。

小结一下,首先阿里去IOE是战略性的系统工程,会深远的影响到一个公司。它需要我们真正的技术人员,是以真正的说,不是像甲方的心态,所有东西都是有人帮你支持,而是把所有事情当做自己的事情,全方位在架构和细节层面把控住这个事情。

IOE是风险极大,受益很高的事情,做成这件事需要很强组织上的保障。比如说它需要有一个坚定的在这方面可以走出去,逐步逐步拿结果的团队,无论是技术上,以及碰到困难,都能够逐步逐步解决,影响相关团队往前走。

另外做这件事情需要我们决策者坚定支持,当你推动这件事情你一定面临很多方面压力,阻力同样也会非常之大。所以这需要坚定支持者,受益也会很大,做完这件事情,无论从成本,还是安全性,技术的可控性,以及团队能力积累都是非常明显的改观。

下面说一下体会,我觉得这几件事情做完确实说大家外面风言风语,有很多不是很正确的观点,从我们角度来说想和大家分享几点体会。

1、去IOE对某些厂商会有误伤,但是对于阿里而言,我们本质上以自主可控分布式的Commodiry、PC架构代替集中专用的IOE架构。我们做这件事情不是为了做而做,而是说我们也不是简单说说为了降低成本,或者因为某些是外国的技术,我们就不用。某些国内技术阻碍我们阿里业务发展我们同样会干掉它。

去IOE对于个人的技术成长,有非常明显拉动作用。这中间因为这毕竟是一个技术方案的转变,这其实设计到一个个人的技术的方向和企业的技术方向,如果说不是很好的切合起来的话,有可能你会成为一个阻力。特别是在快速变化,业务快速推进这样一个业务场景当中,就是这两个方向怎么切合,或者我们技术人员如何站在最高的角度帮助企业做转型的推动,是推动技术的变革非常重要的。

去IOE水很深风险很大,现在网上有很多人说开源怎么着,在我们看来开源只是解决了你入水的时候零成本的问题,你后期要驾驭它的时候你会面临很高它的运维以及发展的成本。这是需要很强的技术团队才能帮助你Hold,如果你没有做好准备之前不要轻易的去IOE。

另外就是说在我们看来并非所有企业都适合去IOE,但是规模化的企业我们建议去IOE,理由跟阿里类似。当你企业大到一定程度,当你企业快速发展的时候,你面临问题跟阿里快速发展面临问题都是大同小异的。

去IOE相关技术难以复制,很难像盒装软件一样我给你一个光盘你回去安装一下就立马干掉了,也不是一个简单的数据迁移,从A迁到B你这个就完成了。这需要做很多很多数据梳理和技术改造,人员在底层要很多技术梳理。去IOE技术阿里内部操作的,很难复制的。在我们看来做这个事情需要一个平台,这个平台如果能够有对接去IOE技术,这个会使你去IOE的门槛和成本降低。

做这个事情要耐得住寂寞走下去,你碰到阻力都会告诉你很难,你要放弃很容易,如果要一步一步走下去确实你需要做很多的功课,要内心足够强大才可以做这件事情。在宏观层面的去IOE,我们经历过的一些事情,中间一些思考和一些观点,简单跟大家分享一下,明天会有一些相关核心技术环节,感兴趣的同学可以一起听一下,谢谢大家!

 

[repost ]libPhenom is an eventing framework for building high performance and high scalability systems in C

original:http://facebook.github.io/libphenom/

System Requirements

libPhenom is known to compile and pass its test suite on:

  • Linux systems with epoll
  • OS X

libPhenom has been known to compile and pass its test suite on these systems, but they have not been tried in a little while, so may require a little bit of TLC:

  • BSDish systems that have the kqueue(2) facility, including FreeBSD 9.1 and OpenBSD 5.2
  • Illumos and Solaris style systems that have port_create(3C).

libPhenom depends on:

  • c-ares for DNS resolution. It expects to find it via pkg-config; you need to provide this in order for phenom to build successfully.
  • Concurrency Kit for its excellent concurrency primitives and key data structures. We include CK with phenom.

libPhenom works best if built with GCC version 4.3 or later, but should be able to build with any C99 compiler.

Build Status

Facilities

  • Memory management with counters – record how much of which kinds of memory your application is using.
  • Jobs – decompose your application into portions of work and let the phenom scheduler manage getting them done
  • streaming I/O with buffers
  • Handy data structures (hash tables, lists, queues)
  • Variant data type to enable serialization and deserialization of JSON
  • A printf implementation with registerable object formatting

Goals

  • Balance ease of use with performance
  • Aim to be neutral wrt. your choice of threaded or event-based dispatch and work well with both.
  • Where possible, avoid contention points in our implementation so as to avoid limiting scalability with the number of cores in the system.

How to use these docs

If you’re reading these on http://facebook.github.io/libphenom, simply start typing and the search box will suggest topics. You may select topics from the Topics menu or browse the header files via the Headers menu.

Getting it

You can obtain the sources from https://github.com/facebook/libphenom:

$ git clone https://github.com/facebook/libphenom.git

or grab a snapshot of master

Build

$ ./autogen.sh
$ ./configure
$ make
$ make check

Quick Start for using the library

You’ll want to set up the main loop using something like this:

#include "phenom/defs.h"
#include "phenom/job.h"
#include "phenom/log.h"
#include "phenom/sysutil.h"

int main(int argc, char **argv)
{
  // Must be called prior to calling any other phenom functions
  ph_library_init();
  // Optional config file for tuning internals
  ph_config_load_config_file("/path/to/my/config.json");
  // Enable the non-blocking IO manager
  ph_nbio_init(0);

  // Do stuff here to register client/server stuff.
  // This enables a very simple request/response console
  // that allows you to run diagnostic commands:
  // `echo memory | nc -UC /tmp/phenom-debug-console`
  // The code behind this is in
  // https://github.com/facebook/libphenom/blob/master/corelib/debug_console.c
  ph_debug_console_start("/tmp/phenom-debug-console");

  // Run
  ph_sched_run();

  return 0;
}

And link against libphenom and libcares. Want more inspiration? Take a look at the code in the test suite.

Status

We’re still hacking and evolving this library, so there may be some rough edges. We’re very open to feedback; check out the Contributing section below.

Contributing

If you’re thinking of hacking on libPhenom we’d love to hear from you! Feel free to use the Github issue tracker and pull requests to discuss and submit code changes.

We (Facebook) have to ask for a “Contributor License Agreement” from someone who sends in a patch or code that we want to include in the codebase. This is a legal requirement; a similar situation applies to Apache and other ASF projects.

If we ask you to fill out a CLA we’ll direct you to our online CLA page where you can complete it easily. We use the same form as the Apache CLA so that friction is minimal.

License

libPhenom is made available under the terms of the Apache License 2.0. See the LICENSE file that accompanies this distribution for the full text of the license.

[repost ]基于glusterfs和gearman的离线任务运算分布式化方案介绍

original:http://stblog.baidu-tech.com/?p=1887

web站点服务中,我们除了存在面向用户的服务功能外,往往也存在大量的后台离线的相关计算任务,如对前端的异步操作数据队列进行定期处理,对数据库中的数据进行汇总挖掘,监控,转储,对中间数据的进一步运算处理等等……一个web服务站点的背后,往往存在大量对应的后端处理任务的功能模块,用于支撑正常的业务功能系统。

在一个web站点的初始阶段,我们可能只需要有一台服务器,容纳部署所有的业务功能,包括了面向用户的前端web服务功能,数据存储,后端离线处理业务功能。随着站点的业务功能越来越多,用户访问数的增加以及数据量的增长,单台服务器的处理能力往往就面临瓶颈。这个时候简单的处理就是将前端web服务功能,数据库和后端业务模块分开部署在不同的机器上,但是可能过随着站点规模的逐渐庞大,单个服务器也无法支撑前端web服务,数据库服务或者后端离线业务功能。Web前端服务,数据库服务相对是通用的技术服务,相关业务都大同小异,其分布式化在业界有相对很成熟和典型的架构模式解决方案,但是不同系统的后端离线业务功能可能千差外别五花八门,不同开发者开发出来的功能架构也各不相同,本文介绍一种低代价的web站点离线任务分布式改造方案,其使用了glusterfs分布式文件系统以及gearman分布式运算框架。

我们知道,相关离线运算要能进行分布式化运算,做到单次执行在任意一台机器上执行都可以,其首先的要求就是程序依赖输入输出数据的非本地,我们要实现运算的分布式化,就必须实现所有存储数据的中心化存储以及分布式化。

 

一 存储的中心化和分布式化

我们知道一个web站点的业务功能必然要使用各种数据,需要存放各种数据,基本上是以关系型数据库,nosql数据服务,session数据,cache数据,原始的服务器文件数据存储。对于关系型数据库,nosql数据库,其本身就是中心化的数据存储,其分布式化也有成熟的解决方案,对于站点session,相关cache数据,也有成熟的memcached等利用而进行中心化存储,以及进行分布式的扩展。对于大多数后台离线业务功能来说,往往是开发人员逐渐开发堆积而来,这些功能程序往往会存在大量对本地文件的直接读写,如果改造使用其他存储方式,工作量巨大而且风险大,这些数据的中心化存储改造往往成了解决数据存储中心化的聚焦点,而且所幸,业界有大量成熟的分布式文件存储系统,能够帮我们解决本地文件存储的中心化和分布式化存储。我们介绍一种使用glusterfs进行对本地文件存储的分布式化处理方案。

分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网络与节点相连。分布式文件系统的设计基于客户机/服务器模 式。一个典型的网络可能包括多个供多用户访问的服务器。另外,对等特性允许一些系统扮演客户机和服务器的双重角色。例如,用户可以“发表”一个允许其他客 户机访问的目录,一旦被访问,这个目录对客户机来说就象使用本地驱动器一样。

GlusterFS是 一个高层次的分布式文件系统解决方案。通过增加一个逻辑层,对上层使用者掩盖了下面的实现,使用者不用了解也不需知道,文件的存储形式、分布。

内部实现是整合了许多存储块(server) 通过Infiniband RDMA或者 Tcp/Ip方 式互联的一个并行的网络文件系统,这样的许多存储块可以通过许多廉价的x86主 机,通过网络搭建起来。

其相对于传统NAS 、SAN、Raid的 优点就是:

1.容量可以按比例的扩展,且性能却不会因此而降 低。

2.廉价且使用简单,完全抽象在已有的文件系统之上。

3.扩展和容错设计的比较合理,复杂度较低。扩展使用translator方 式,扩展调度使用scheduling接口,容错交给了本地的文件系统来处理。

4.适应性强,部署方便,对环境依赖低,使用,调试和维护便利。

支持主流的linux系统发行版,包括 fc,ubuntu,debian,suse等, 并已有若干成功应用。

对于一个站点的后端离线功能的文件存储来说,我们既希望能将这些文件数据存储中心化,又希望能够兼容已有的代码,基于这两种考虑,我们可以按照如下的方案图来进行本地文件迁移到glusterfs文件系统:

 

这样,我们就即能实现文件存储的分布式化,又能兼容已有业务程序,做到无缝迁移。

二运算任务分布式化

当我们的业务程序依赖的存储和数据都中心化,而不依赖于本地存储的时候,我们的运算任务就可以在任何一台部署环境和代码运算服务器上运行,我们唯一缺少的就是一个任务的队列调度处理模块。我们介绍一种基于gearman的分布式运算框架。

Gearman是一个用来把工作委派给其他机器、分布式的调用更适合做某项工作的机器、并发的做某项工作在多个调用间做负载均衡、或用来在调用其它语言的函数的系统。

一个Gearman请求的处理过程涉及三个角色:Client -> Job -> Worker。

Client:请求的发起者,可以是 C,PHP,Perl,MySQL UDF 等等。

Job:请求的调度者,用来负责协调把 Client 发出的请求转发给合适的 Work。

Worker:请求的处理者,可以是 C,PHP,Perl 等等。

因为 Client,Worker 并不限制用一样的语言,所以有利于多语言多系统之间的集成。甚至我们通过增加更多的 Worker,可以很方便的实现应用程序的分布式负载均衡架构。

另外,我们的离线运算任务往往会存在着针对一类任务一些并发控制,任务去重,防追赶等等功能要求,我们就可以利用gearman做任务队列,同时做二次开发,利用其他技术手段,如mysql存储介质下的任务数据存储更新和分析,来实现这些并发控制和去重。可以按照如下给出的一种架构来进行离线任务分布式改造:

 

其中发送端调用统一的api来发送任务到gearman任务队列,并且记录相关任务信息到任务状态记录模块,由部署在运算机上的worker来消费和执行任务。

任务发送端的处理逻辑如下图所示:

 

按照这个流程,任务发送端可以实现任务的去重功能。

Worker的任务消费流程如下:

 

这样的结构不仅能够实现任务的分布式化执行,而且可以执行一类任务的并发控制,同时通过任务执行前检查机器资源状况,实现对机器资源的基础保护,防止大量任务在集中个别机器上执行,使该服务器出现负荷过重,任务拥塞的情况。

至此,我们解决掉存储的中心化和分布式化,任务的分布式化,新的任务的添加也只要纳入该框架下运行即可,随着我们的站点规模的增大,我们可以方便的加机器进行扩容,透明的进行存储扩容和运算能力扩容,就不会再面临结构上的不可扩展性。

下面以一个简单的平台应用例子来举例,有一个平台,其存在大量后台cronjob定期任务,也存在各种需要对平台的全量数据等进行批处理运算处理的功能,我们在架构设计的时候,必须考虑到服务的水平可扩展性,也必须要有高可用性,具备强大的热容灾能力,同时,我们也需要大量面对cronjob任务的防追赶,加锁,批处理任务的并发执行度控制等问题,下面看看如何设计该平台系统后端架构。

首先,该平台的存储我们都使用非本地的存储,包括数据库服务器,相关cache存储,还有分布式文件存储系统以及相关网络访问。

采用上面介绍的方案采用gearman分布式框架进行部署,2台gearman服务器,6台运算服务器,以主备的模式来使用gearman-server,充当执行任务的队列调度器,在6台机器上各自部署消费worker程序,在另外一台机器上部署启用linux系统的crontab,向gearman中发送cronjob任务给gearman,然后,针对任务的去重和并发控制,我们设计如下的任务记录模块,简单用mysql表来存储相关的任务消息,用于实现防追赶去重和并发控制效果,其中一张关键的任务执行记录表的格式如下:

 

针对不同类型的执行任务,我们可以设置不同类型的参数

 

将任务发送端程序和消费并发控制逻辑封装到平台公用模块中,透明的进行调用和任务消费执行

针对cronjob类型的任务,平台crontab主发送机上添加发送端任务

*/10 * * * * /home/work/php5/bin/php /home/work/ala-service/bin/cronjob/client_cronjob.php -t $type_id &> /dev/null

($type_Id为在任务注册表中添加的任务的编号id字段)

那么注册的任务触发后就会随机分配到6台运算机上去执行。

而针对应用程序主动调用发送的任务执行方式,我们只需要在发送端内嵌封装好的发送端程序即可实现任务发送,下面图举一个简单的PHP简单封装的发送端程序调用方式

发送端只要如此调用即可以发送任务去执行,后端运算机获取任务后进行执行。

如此,运营前面所述架构思路,做2次扩展开发,就可以方便的实现该后端平台的需求,其可以方便的水平扩展,机高的可用性,调用方便,实现真正的离线任务分布式化。

将任务发送端程序和消费并发控制逻辑封装到平台公用模块中,透明的进行调用和任务消费执行

针对cronjob类型的任务,平台crontab主发送机上添加发送端任务

*/10 * * * * /home/work/php5/bin/php /home/work/ala-service/bin/cronjob/client_cronjob.php -t $type_id &> /dev/null

($type_Id为在任务注册表中添加的任务的编号id字段)

那么注册的任务触发后就会随机分配到6台运算机上去执行。

而针对应用程序主动调用发送的任务执行方式,我们只需要在发送端内嵌封装好的发送端程序即可实现任务发送,下面图举一个简单的PHP简单封装的发送端程序调用方式

 

发送端只要如此调用即可以发送任务去执行,后端运算机获取任务后进行执行。

如此,运营前面所述架构思路,做2次扩展开发,就可以方便的实现该后端平台的需求,其可以方便的水平扩展,机高的可用性,调用方便,实现真正的离线任务分布式化。

[repost ]月PV破150亿:Tumblr架构揭密

original:http://os.51cto.com/art/201202/317899.htm

【51CTO精选译文】随着每月页面浏览量突破150亿次,Tumblr已经名正言顺地跻身博客类平台中的名人堂。用户们对它的简洁、美观以及对使用体验的专注追求赞不绝口;它的相关社区也同样氛围温馨、人气爆棚。总之,人们喜欢这位博客家族中的新贵。

tumblr

超过30%的月度增长不可能一帆风顺,过程中的坎坷与挑战也自然不言而喻,但最令人头痛的还是可靠性问题。正是经过技术人员的不懈努力,Tumblr才取得了如此惊人的规模及傲人的运行成绩:每天5亿次页面浏览、每秒四万次查询请求峰值、每天新数据存储量高达约3TB、总支持服务器达到1000余台。

大多数成功的新兴企业都面临着相似的困扰,由于从初来乍到的新成员一跃成为万众瞩目的焦点角色,一道巨大的危险鸿沟硬生生将原本孱弱的技术支持团队推向了风口浪尖。招聘员工、扩大基础设施、维护旧有基础设施的同时,仍然只有寥寥数位工程师负责着每个月巨大的数据吞吐量。这样的工作强度意味着我们在处理过程中必须有所侧重,而做出这样的选择无疑相当艰难。Tumblr目前也陷入了这样的困境,他们的做法是创建起一个由二十位精力充沛的工程师组成的技术小组,在应对日常事务的同时制订出多种极富创意的解决方案。

Tumblr创立之初就将自己定位为典型的大型LAMP(即由定制组件构成的系统)应用程序。如今他们前进的方向是通过Scala、HBase、Redis、Kafka、Finagle以及以架构为基础的新颖单元共同打造出多种分布式服务模块,借以构成完整的Dashboard导航内容。目前他们已经开始尝试修复PHP应用程序中的短期问题、将故障部分抽离出来并利用服务机制进行更正。

Tumblr发展的主题是在庞大的平台规模之上实施成功转型。即将LAMP堆栈转变为一套更具突破性特性的新堆栈,同时将原本适用于新兴企业的小型团队扩展为装备精良、擅长开发工作的成熟团队,进而为用户带来大量新功能及基础设施。为了帮助我们更透彻地理解Tumblr实现这一方针的具体做法,Tumblr公司分布式系统工程师Blake Matheny分享了他的心得体会。以下是Blake对Tumblr做出的信息汇总:

Tumblr官方网址:http://www.tumblr.com/

统计

  • 每天5亿次页面浏览量
  • 每月150亿次以上页面浏览量
  • 约20位技术工程师
  • 每秒4万次查询请求峰值
  • Hadoop集群每天接受超过1TB的数据量
  • MySQL/HBase/Redis/Memcache等系统每天需要处理数以TB计的信息
  • 每月用户数量及处理负载增长30%
  • 日常运行中涉及约1000个硬件节点
  • 每个月每位工程师平均要面对上亿次页面访问活动
  • 每天新增的博文及帖子约为50GB。新的用户关注列表每天带来约2.7TB的数据存储量
  • Dashboard系统每秒要应对百万次写入操作、5万次读取操作,这一数字还在不断增长之中

软件

  • 开发工作在OS X上进行,日常运行则交给Linux系统(CentOS、Scientific)
  • Apache
  • PHP, Scala, Ruby
  • Redis, HBase, MySQL
  • Varnish, HA-Proxy, nginx,
  • Memcache, Gearman, Kafka, Kestrel, Finagle
  • Thrift, HTTP
  • Func – 一款安全且脚本化良好的远程控制框架及API
  • Git, Capistrano, Puppet, Jenkins

硬件

  • 500 台web服务器
  • 200台数据库服务器(其中大多数作为故障发生时的后备资源存在)
    • 47个资源池
    • 30个区块
  • 30台缓存服务器
  • 22 台redis服务器
  • 15 台varnish服务器
  • 25个haproxy节点
  • 8 个nginx反向代理服务器
  • 14台作业队列服务器(kestrel+gearman)

架构

  • 比起其它社交型网络,Tumblr拥有一套完全不同的使用模式。
    • 每天有五千多万篇博文发表,每一篇都有数百次的平均浏览量。并不是说少数热门用户具备的数百万关注者拉升了平均浏览量,事实上每位Tumblr用户基本都有成百上千的关注者。这与以往任何类型的社交网络都有所不同,也恰恰是这种特性让Tumblr面临着史无前例的规模化考验。
    • Tumblr目前是用户倾注时间第二多的热门社交网络,其内容也极具吸引力。由于允许用户自由分享图片与视频,因此博文的体积不再以字节计算。尽管用户不一定总会发布体积庞大的内容,但网站保证每个人都在需要时具备丰富自己文章的能力。人们乐于撰写更为深刻的主题,这也让关注者们找到了阅读的乐趣,并持续花费大量时间访问Tumblr。
    • 用户之间构成一套完整的联络纽带,因此他们常常会尝试回溯Dashboard中数百页之前的内容。其它社交网络则往往只提供信息流,用户体验只停留在惊鸿一瞥的层面上。
    • 也就是说,由于用户数量之大、每位用户的平均阅读数量之多以及用户发起各类活动积极性之高,Tumblr需要处理的上传信息庞大到令人惊愕。
  • Tumblr运行于一套托管站点中。设计者们为网站留出了充分的地理分布空间,以应对未来的发展需求。
  • Tumblr平台由两大组件构成:Public Tumblelog与Dashboard系统。
    • Public Tumblelog 是一款面向公众的博客。由于动态特性较弱,因此缓存更易于打理。
    • Dashboard在功能上与Twitter的timeline颇为相近。用户将实时接收到自己关注对象的更新信息。
      • 在规模特性上与其它博客载体颇为不同。缓存在这里的作用不再明显,因为每条请求都各不相同,尤其是对于那些活跃的关注者而言。
      • 运行中必须保持高度的实时性与一致性,不应显示陈旧数据,且需要处理的数据量非常庞大。每天的博文内容本身只有50GB,但关注者列表更新信息则高达2.7TB。媒体文件全部存储于内存中。
  • 大多数用户将Tumblr作为内容型消费工具。每天页面浏览量超过5亿次,70%的浏览行为针对Dashboard系统。
  • Dashboard系统的可用性相当值得称道。Tumblelog则一直有所欠缺,因为其中的某套原有基础设施目前很难实施迁移。鉴于技术支持团队的规模太小,他们不得不在规模化进程中优先处理那些时间短、见效快的内容。

过去的Tumblr

  • Tumblr起初立足于Rackspace公司,后者为每个自定义域名博客创建一套A记录。到了2007年,他们已经拥有极为庞大的用户群体,为了实施整体迁移,他们开始尝试独立于Rackspace公司之外。这时他们的自定义域业务仍然由Rackspace负责,为了保持用户的访问方式,他们利用HAProxy与Varnish代理服务器将Rackspace域名转向自己的服务器空间。类似的历史遗留问题还有很多。
  • 一套传统的LAMP。
    • 一直使用PHP,几乎每位工程师都通过PHP处理编程工作。
    • 创立之初只拥有一台web服务器、一台数据库服务器以及一套PHP应用程序。
    • 为了完成规模化扩展,他们开始使用memcache,接着引入前端缓存,然后是将HAProxy置于缓存之前,最后采用MySQL分区。MySQL分区体系的加入使整体服务效果迈上新的台阶。
    • 力图将所有处理负载控制在一台服务器的承受能力之内。在过去的一年中,他们借助C语言开发出两款后端服务:ID生成器Staircar,Dashboard通知功能则利用Redis实现。
  • Dashboard采用分散-集中式处理方案,当用户访问Dashboard时事件将自动予以显示。而让用户关注对象的新事件以推送形式显示又花了技术团队六个月的时间。由于数据以时间为标准排序,因此分区设计方案的表现并不尽如人意。

如今的Tumblr

  • 出于提高租用及开发速度的考量,如今采用JVM中央方案。
  • 目标是将所有存在于PHP应用中的内容迁移至服务项目中,并将PHP应用本身作为新建的层置于服务之上,用于负责请求验证及介绍说明等工作。
  • 选择使用Scala与Finagle。
    • 公司内部拥有大量擅长Ruby及PHP开发工作的成员,因此Scala的推广也就更为轻松。
    • Finagle的使用也是他们选择Scala的重要原因之一。这是一套来自Twitter的库,能够处理大多数由分布式设施带来的技术难题,包括分布式跟踪、服务项目搜索以及服务项目注册等。当然这些功能我们也不必全部采用,根据实际需求选择即可,反正都是免费的。
    • 一旦与JVM环境相结合,Finagle能够提供他们所需要的一切基本要素(例如Thrift、ZooKeeper等等)。
    • Foursquare及Twitter一直在使用Finagle,Scala也始终效力于Meetup网站。
    • 与Thrift应用程序接口一样,Finagle也带来了相当优异的性能表现。
    • 希望得到像Netty那样的运行效果,又不想涉及Java,因此Scala是最好的选择。
    • 采用Finagle是因为它功能强劲、所需知识并不冷门,使用中不涉及过多网络代码而且能为分布式系统提供一切所需功能。
    • Node.js没有入选的原因在于,它在JVM环境下对于技术团队的规模要求比较高。Node.js在开发方面缺乏标准化及最佳实践选项,测试用代码也相对较少。而Scala允许我们使用任何现有Java代码。而且在不要求过多知识储备的基础上,Scala能够轻松应对未来可能出现的扩展性要求,同时保障5毫秒响应时间、49秒双机集群切换以及平均每秒四万次、峰值四十万次的请求处理。同时Java体系中的大量资源也可为我们所用。
  • 内部服务项目正由以C语言/libevent函式库为基础向Scala/Finagle为基础转变。
  • 采用更新的HBase以及Redis等非关系类数据存储机制,但目前大多数数据存储在一套高度分区下的MySQL架构中。尚没有用HBase彻底替代MySQL。
  • HBase凭借数以亿计的URL以及全部历史数据与分析结果支持自身的URL简写功能,运行表现一直稳固可靠。HBase主要用于处理高写入请求情况,例如每秒上百万次写入动作的Dashboard重置操作。HBase没有被用来替代MySQL的原因在于,Tumblr目前的技术支持团队尚无法在HBase上完成全部业务需求,因此他们最终决定先在规模较小的非关键性项目上进行试用,尽量积累使用经验。
  • 以MySQL及分区机制为基础,将按时间排序的所有数据纳入同一个分区的过程始终麻烦不断。读取及复制操作也由于子集群写入动作的同时发生而常常出现滞后现象。
  • 创建出一套通用型服务框架。
    • 事先花费大量时间制订方案,用以解决分布式系统在管理时出现的操作问题。
    • 创建一套用于服务项目的Rails桥架,作为引导内部服务的模板使用。
    • 所有服务项目从运行的角度来看都完全一致。各服务的状态检查、监控、启用以及中止都以同样的方式进行。
    • 创建过程中使用的工具为SBT(一款Scala创建工具),同时用到的还有其它一些插件及辅助内容,旨在为包括git项目标注、仓库信息发布等公共活动提供支持。大多数开发人员不必深入了解系统的创建过程。
  • 前端层使用HAProxy,Varnish则服务于公共博客,二者共计占用40台设备。
  • Apache及各类PHP应用程序由500台网络服务器予以支持。
  • 数据库服务器共有200台。大部分数据库服务器用于提高整体可用性。由于使用标准化硬件配置,因此平均无故障工作时间相当令人满意。硬件设备的损耗大大超出预期,因此技术人员准备了大量后备物资以应对不时之需。
  • 六项用于支持PHP应用程序的后端服务。一个专项小组专门负责开发此类后端服务。每隔两到三周都会有一款新服务推出,例如Dashboard通知、Dashboard辅助索引、URL简写工具以及用于分区处理的缓存代理器等。
  • 在MySQL分区方面投入大量时间以及人力物力。尽管MongoDB目前在纽约(Tumblr的总部所在地)风靡一时,但他们仍然采用了扩展性更好的MySQL。
  • Gearman,一款作业队列系统,被用于处理运行时间较长且无人照看的工作内容。
  • 可用性评估以实际使用效果为标准。用户能够正常访问自定义域名或是Dashboard吗?另外故障率也是评估中的一项因素。
  • 就长期运行状况来看,具备最高优先级的项目必须首先得到修复。目前故障模式已经得到有效的分析与系统性解决,其目的是同时从用户及应用程序的角度来评估整体运行状态。如果一条请求中的某部分没有得到充分响应,那么这套评估机制必须迅速查明原因。
  • 最初的角色模式是由Finagle负责支持的,但后来这种方式被弃之不用,取而代之的是一套无需照看的作业队列。另外,Twitter的实用库中包含一套名为Futures的服务实施方案。当某个线程池需要被调用时,Futures服务将立即建立一个future池,这时所有待处理内容都将被提交至future池中以进行异步执行。
  • 由于自身特性的原因,Scala并不适合处理共享状态。Finagle则可以默认为适合处理此类情况,因为Twitter已经将付诸实际应用。在Scala及Finagle中都应尽量避免可变状态调用架构的情况。不能让设备长期处于运行状态。状态信息采集自数据库,并在使用后重新写入数据库。这么做的优势是,开发人员们不必担心线程或者锁定问题。
  • 22台Redis服务器。每台服务器运行8到32个实例,也就是说共计有数百个Redis实例用于生产流程。
    • 后端存储机制用于为Dashboard通知功能提供支持。
    • 通知功能本身类似于关注我们博文的某位用户。通知会显示在用户的Dashboard中,这样我们就能及时了解其它用户的最新动态。
    • 极高的写入频率使得MySQL有些力不从心。
    • 通知内容无需长期存在,因此即使用户掉线也不会出现突然涌入大量提示消息的窘境,这样一来Redis就成为实现通知功能的选择之一。
    • 尽量为技术人员创造机会,让他们学习Redis的相关知识并熟悉其工作原理。
    • 由于Redis拥有强大的社区体系,因此无论遇上什么问题都能在这里找到解决方法。
    • 为Redis创建一个以Scala futures为基础的接口,这项功能现在正逐渐转到Cell架构当中。
    • URL简写工具将Redis作为一级缓存,并把HBase当成长效存储机制。
    • Dashboard的辅助索引围绕Redis进行创建。
    • Redis作为Gearman的持久化层存在,并用到了由Finagle创建的缓存代理器。
    • 慢慢由缓存向Redis迁移。希望能够以一套快取服务作为最终方案,其性能表现应与缓存方案一致。

内部传输线

内部应用程序需要访问活动流。每个活动流的内容都与用户行为相关,例如创建、删除博文或者喜欢、反感某些博文等。挑战在于如何将这样规模的数据实时加以分散。要达到这一目的,需要足以支持大规模内部扩展的工具以及拥有可靠生态系统辅助的应用程序。此外还要确立分布式系统的中心点。

  • 之前信息的分布化由Scribe/Hadoop负责。服务项目要首先登入Scribe并开始追踪,然后将数据传输至应用程序端。这种模式让可扩展性成为空谈,尤其是在用户每秒创建上千篇博文的峰值时段。应该尽量避免用户追踪文件并进行打印。
  • 创建一套类似于信息公交车这样的内部传输线,服务项目与应用程序通过Thrift与传输线进行交互。
  • 利用来自LinkedIn网站的Kafka来存储消息。内部用户使用HTTP流直接从传输线上阅读内容。不使用MySQL的原因在于,分区工作本身就过于频繁,因此不适合让其承担大量数据流。
  • Tumblr的传输线模式灵活性极强,Twitter所使用的传输线则相形见绌,其中的数据常常面临丢失。
    • 传输线流能够及时进行回溯,它会保存一周以内的所有数据。在连接时,它可以正确找回最后一次阅读的位置。
    • 允许同时连入多个客户端,而且每个客户端所看到的内容都各不相同。每个客户端拥有独立的客户端ID,这要归功于Kafka所支持的用户组概念。用户组中的每一个用户不仅会看到与自己相关的消息,并且消息内容绝不重复。可以利用同一个用户ID创建多个客户端,这些客户端所看到的内容同样不会重复。也就是说数据以独立且并行的方式进行处理。Kafka通过ZooKeeper定期为用户设置检查点,以记录用户的当前阅读进度。

Dashboard收件箱的Cell设计

  • 目前为Dashboard功能提供支持的分散-集中模式存在着一定局限性,不久之后就会转而采用更先进的方案。
    • 解决方案是让收件箱采用以Cell为基础的新型架构,这与Facebook的Messages功能颇为相似。
    • 收件箱可以说是分散-集中模式的对立面。由关注者的博文及近期动态所构成的Dashboard版面,按时间顺序及逻辑方式存储在一起。
    • 由于收件箱的功能特性,分散-集中模式带来的问题在这里不攻自破。我们只会询问收件箱中保存着哪些内容,这完全不涉及关注者、用户好友之类乱七八糟的关系。这样的情况将持续很长一段时间。
  • 对Dashboard内容进行重写是相当困难的。虽然数据拥有分布式特性,但它同时也拥有交互式特性,因此用户无法实现局部更新功能。
    • 数据总量之大简直超乎想象。每一条消息平均要发送给成百上千位不同用户,这比Facebook的工作负担更重。大量数据加上高分布率再加上多个数据中心协同运作,整个流程的复杂程度由此可见一斑。
    • 每秒百万次写入操作及五万次读取操作,这么高强度的交互活动带来了高达2.7TB的数据集增长量,还不算复制或是压缩等处理工作。由24个字节构成的百万次写入操作给收件箱带来海量信息。
    • 以上所有工作由一套应用程序负责,因此保证程序的正常运作就显得至关重要。
  • Cell单元。
    • 每个Cell单元都是一套独立的装置,其中包含了大量用户的全部相关数据。用户Dashboard版面所需要的一切数据都由Cell单元提供。
    • 用户以映射的方式与Cell单元连通,每个数据中心都运行着大量Cell单元。
    • 每个Cell单元都拥有自己的一套HBase集群、服务集群以及Redis缓存集群。
    • 用户与Cell单元相对应,所有Cell单元都通过传输线中的上传数据调用博客信息。
    • 每个Cell单元都以Finagle为基础,并通过传输线以及Thrift上的服务请求构成HBase数据信息。
    • 当某位用户进入Dashboard版面,就会从特定Cell单元中调出多个相关用户的信息;服务器节点通过HBase读取相关用户的Dashboard内容并将数据传回当前登录用户。
    • 后台任务从传输线中获取信息,并生成对应列表及处理请求。
    • Cell单元中的博客信息会调用Redis缓存层。
  • 请求指令流:当某位用户发布博文,该篇博文即会被写入传输线;所有Cell单元从中读取博文内容并将其转写入文章数据库中;接着Cell单元会检查该文用户的关注者中有哪些处于自身单元内部,最终将寻获的关注者收件箱以及博文ID共同进行上传。
  • Cell单元设计的优势所在:
    • 请求指令的大量同时出现势必对并行处理能力要求极高,这就使得设备组件必须彼此独立,然而独立性也会导致交互过程无法完成。Cell单元设计使并行处理工作成为一个独立体系内部的事务,并能够在用户群体不断增长的情况下随时保持强大的可调节能力。
    • Cell单元天然具备故障隔离能力。某个Cell单元出错不会对其它单元造成任何严重影响。
    • Cell单元使更新内容测试、信息发布以及软件版本测试工作得以有条不紊地进行。
  • 容易被大家忽略的关键性环节是:所有文章都会被复制到每一个Cell单元中去。
    • 每个Cell单元都存储着一套独立的全局文章副本。每个Cell单元都能够为Dashboard版面提供令人满意的内容。应用程序并不会查询所有文章ID,它只会为登录ID查询相关文章,这样一来用户将能够在自己的Dashboard版面中看到所有信息。每一个Cell单元都拥有填充Dashboard所必需的全部数据,因此不必进行什么跨单元通讯。
    • 共使用了两套HBase列表:一套用于存储文章副本,而另一套则为Cell单元中的每个用户保存博文ID,列表之间的内容基本无甚关联。第二套列表的作用是为用户的Dashboard版面提供显示内容,也就是说不必追踪该用户所关注的每位其它用户。另外,利用这种机制,如果我们在另一台设备上阅读或浏览某篇文章,系统将不会认为我们是在重复读取同样的内容。无论通过何种方式,我们的阅读进度都将保存在收件箱模块的状态一项中。
    • 文章不会被直接置于收件箱中,因为这么多文章累积起来容量实在惊人。因此只将ID放入收件箱,而文章内容则由Cell单元保存。这种方式大幅度降低了所需存储空间,并让用户收件箱中的内容按时间顺序变得非常简便。这么做的缺点是每个Cell单元都需要包含完整的文章副本。但令人惊讶的是,文章本身的体积总量远远小于映射所需的存储空间。每天每个Cell单元中的文章内容增量约为50GB,但收件箱内容的增量却高达每天2.7TB。由此可见,用户的阅读量比写入量大得多。
    • 用户的Dashboard中并不显示文章内容,只包含基本的文章ID;因此数据增量的主体是不断膨胀的ID。
    • 即使用户的关注者名单发生变更,这种设计仍然完全应付得来,因为所有文章都已经存在于Cell单元中。如果Cell单元中只保存来自关注者的文章,那么一旦关注者名单有所变动,单元中的数据将不足以及时做出反应,同时将引发一系列不可避免的信息填充活动。
    • 另有一套备选方案,利用一套独立的文章集群存储博文内容。这种设计的缺点在于,一旦这套集群出现故障,那么整个网站都将陷入瘫痪。相比之下,采用Cell单元设计、将所有文章复制到每一个单元当中的做法使整个架构牢固而可靠。
  • 对于那些关注人数以百万计且相当活跃的用户,会根据他们的访问模式获得特定的用户服务。
    • 不同的用户往往使用不同的访问模式以及与个人习惯相符的分布模式。Tumblr为用户准备了两种不同的分布模式:一种适合人气超高的热门用户、另一种则适合任何类型的用户。
    • 数据的处理方式也根据用户类型的变化而有所不同。来自活跃用户的文章实际上不会真正予以发布,而只是有选择地呈现给其他用户。
    • Tumblr在处理大量关注其他使用者的用户时,采用的方法与处理拥有大量关注者的用户非常类似。
  • 每个Cell单元的大小很难确定。单元的大小会影响到网站的故障机率,而单元中所包含用户的数量则是最关键的因素。需要在用户的使用期望与支撑这种期望的成本支出之间找到一个平衡点。
  • 从传输线中读取信息是网络问题的核心内容。在Cell单元内部,网络流量始终处于可管理的状态。
  • 由于Cell单元的数量日益增加,最终Cell单元组的概念被添加进来。这是一套分层复制规划,同时也有利于将数据信息迁移到多个数据中心当中。

成为一颗立足于纽约的耀眼新星

  • 纽约的环境背景相当特殊,其中充斥着大量财务与广告因素。作为一家缺乏经验的新兴企业,Tumblr在人才招聘及设备租用方面都面临着挑战。
  • 在过去几年中,纽约市一直致力于扶植新兴企业。纽约大学与哥伦比亚大学制订了完善的计划,鼓励在校学生到新兴企业中去实习,而不是一头扎进华尔街。Bloomberg市长也将支持科技发展作为纽约市的一项基本战略。

团队构成

  • 团队:基础设施、平台、SRE(即系统调整及修复)、产品、网络运行以及服务支持。
  • 基础设施:5层及以下。IP地址及以下、DNS、硬件供应。
  • 平台:核心应用程序开发、SQL分区、服务、网络运行。
  • SRE: 存在于服务团队与网络运行团队之间,致力于解决迫在眉睫的系统可靠性及可扩展性问题。
  • 服务团队:致力于发展战略层面的问题,处理周期一般为一到两个月。
  • 网络运行:负责问题检测与响应以及相关调整工作。

软件开发

  • 一切工作以一套专门将PHP应用程序分布到各处的rsync脚本集合为基础。一旦设备总数达到200台,系统就会发生故障——部署流程无比缓慢、设备自身也停滞在各种各样的配置状态中。
  • 在此之后,Tumblr决定将部署流程(包括开发、启用及生产等环节)利用Capistrano创建在服务堆栈中。这在数十台设备协作的情况下没有问题,但通过SSH让数百台设备彼此连接后,问题再一次出现。
  • 现在所有设备上都运行着一套调整软件,这套软件以红帽Func为基础,本质上是一个用于将指令分配到各主机处的轻量型API。规模化要素也被部署在Func内部。
  • 开发工作在Func层面上进行,并采用“在某个主机组上执行某操作”的直观表述,这就成功回避了对SSH的依赖。例如我们希望在A组中部署软件,那么管理员只需选定目标节点集合并运行部署指令,即可完成任务。
  • 部署指令通过Capistrano进行实施,并能够以git检查或者仓库输出的形式生效。扩展性方面也有所保障,因为指令面向的交互对象为HTTP。之所以采用Capistrano,是因为它能在良好的版本控制之下支持简单目录,这种特性使其与PHP应用程序之间的配合更为默契。以版本控制更新活动使得每个目录都包含安全散列算法,这样技术人员也能够方便地核对当前版本是否正确。
  • Func API的作用是回馈状态,通知系统哪些设备正在运行哪些版本的软件。
  • 任何服务项目都能够安全地加以重启,因为默认状态下项目将首先逐渐断开连接、之后才实施重启动作。
  • 每项功能在投付使用之前,都会在独立环境下进行测试。

开发工作

  • Tumblr所秉承的理论是让每位用户都能使用自己想要的工具,但随着用户群体的激增,这种想法实在难以为继。招聘精明强干的技术人员不是件容易的事,因此他们开始对堆栈进行标准化改造,旨在让技术工作更好上手、团队培养更加高效、产品问题的处理更加迅速并在上述内容的基础上建立业务运作。
  • 整个开发过程与Scrum比较相似。选择的是工作量较小的轻量级模式。
  • 每位开发人员都拥有一台经过预先配置的开发专用设备。设备更新工作则通过Puppet实现。
  • 开发用设备可以随时回收并进行变更及测试,接着重新投入使用并最终执行生产任务。
  • 开发人员们常用的文本编辑器是Vim和Textmate。
  • PHP应用程序的测试以代码审核的方式进行。
  • 他们在服务项目端部署了一套测试用基础设施,其中包括hooks、Jenkins以及连续性集成与通行创建系统。

招聘流程

  • 面试阶段一般不会涉及数学、分析以及脑力测验。提出的问题主要围绕着求职者所申请的职位展开。他们是否聪慧?能否顺利完成份内的工作?但评估求职者能否“顺利完成份内工作”有一定难度。总之面试的目的是找出身负才能的新人,而不是有意排除一定比例的求职者。
  • 编码能力是考核的一大重点。他们会针对示例代码提出问题,在电话面试的过程中也常常利用Collabedit考验求职者的共享代码编写能力。
  • 面试本身并不具有对抗性,他们只是在尝试发现优秀的人才。求职者们可以在面试中使用像谷歌这样的辅助工具来解决问题,因为Tumblr相信善于使用外界助力的开发人员才是能够独当一面的上上之选,所以在考核中并不禁止使用辅助手段。
  • 鉴于Tumblr所要应对的数据流量相当巨大,因此招徕在规模化业务方面具备丰富经验的人才正是当务之急。事实上在全球范围内,还没有几家企业需要处理如此规模的日常工作。
    • 举例来说,他们需要一款新的ID生成器,要求服务运行环境为JVM,在每秒一万条请求的使用频率下保证响应时间低于1毫秒,并且要在内存限定为500MB的前提下保证高可用性。结果在招聘过程中,他们发现了几位牛人,不仅严格按照给定条件执行、还将响应延迟降低到新的水平。这也最终使得Tumblr愿意花费大量时间对JVM运行环境进行调整。
  • 在Tumblr的工程博客中,他们专门发表文章对Dennis Ritchie与John McCarthy表示敬意及纪念,这正是公司极客氛围的实际体现。

经验教训

  • 自动化流程无处不在。
  • MySQL(与分区机制)具备可扩展性,而应用程序本身则不行。
  • Redis功能惊人。
  • Scala应用程序的性能表现令人赞叹。
  • 在不确定某个项目能否起效时,果断加以废除。
  • 不要过分在意那些在垃圾技术领域残喘多年积累到的所谓经验。真正重要的是他们是否适合自己的团队、是否能胜任新的工作岗位。
  • 选择一套能帮你雇用到所需人才的招聘机制。
  • 根据技术团队的实际状况定制招聘标准。
  • 尽量多读些技术论文以及博客文章。像Cell单元架构以及选择性呈现这样的好点子往往并非原创。
  • 多与同事们交流。他们中肯定有人会与来自Facebook、Twitter、LinkedIn等网站的工程师们探讨工作经历并学习新知识。我们自己可能还没有达到同样的高度,但处处留心绝对有利无弊。
  • 另外,别让新人直接负责技术工作。在接触实际生产流程之前,他们需要在试验性项目组或者工作压力较小的职位上好好拿出时间学习HBase以及Redis。

在这里我要向Blake表示感谢,也正是由于他的耐心配合,这篇汇总型文章才会与大家见面。采访过程中他表现出令人称道的慷慨心态,并且不厌其烦地向我们解释工作流程中的具体细节。

原文:Tumblr Architecture – 15 Billion Page Views a Month and Harder to Scale than Twitter