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次扩展开发,就可以方便的实现该后端平台的需求,其可以方便的水平扩展,机高的可用性,调用方便,实现真正的离线任务分布式化。