《淘宝技术这十年》读书笔记 (四). 分布式时代和中间件

一. 分布式时代


1.服务化

2.一种常见的编码错误

        虽然个别架构师具备了“代码洁癖”,但淘宝前台系统的业务量和代码量还是呈爆炸式的增长。
        业务方总在后面催,开发人员不够就继续招人,招来的人根本看不懂原来的业务,只好摸索着在“合适的地方”加上一些“合适的代码”,看看运行起来像那么回事后,就发布上线。
        在这样的恶性循环中,系统越来越肿,业务的耦合性越来越高(高内聚、低耦合),开发的效率越来越低。借用当时较流行的一句话:“你写一段代码,编译一下能通过,半个小时过去了;编译一下没通过,半天就过去了。”在这种情况下,系统出错的概率也逐步增长,这让开发人员苦不堪言。感觉现在很多公司招实习生都是这种感觉。
        2007年年底的时候,研发部空降了一位从硅谷来的高管——空闻大师。他是一位温厚的长者,他告诉我们一切要以稳定为中心,所有影响系统稳定的因素都要解决掉。例如:每做一个日常修改,都必须对整个系统回归测试一遍;多个日常修改如果放在一个版本中,要是一个功能没有测试通过,整个系统都不能发布。我们把这个叫做“火车模型”,即任何一个乘客没有上车,都不许发车。这样做最直接的后果就是火车一直晚点,新功能上线更慢,我们能明显感觉到业务放的不满,压力非常大。
        现在回过头来看,其实我们并没有理解背后的思路。正是在这种要求下,我们不得不开始改变些东西,例如:把回归测试日常化,每天晚上都跑一遍整个系统的回归。
        另外,在这种要求下,我们不得不对这个超级复杂的系统做
肢解和重构,其中复用性最高的一个模块:用户信息模块开始拆分出来,我们叫它UIC(User Information Center)。在UIC中,它只处理最基础的用户信息操作,例如getUserById、getUserByName等。
        在另一方面,还有两个新兴的业务对系统基础功能的拆分也提出了要求。在那时候,我们做了淘宝旅行(trip.taobao.com)和淘宝彩票(caipiao.taobao.com)两个新业务,这两个新业务在商品的展示和交易的流程上都跟主站的业务不一样,机票是按照航班信息展示的,彩票是按照双色球、数字和足球的赛程来展示的。但用到的会员功能和交易功能是与主站差不多的,当时做起来很纠结,因为如果在主站中做,会有一大半跟主站无关的东西,如果重新做一个,会有很多重复建设。
        最终我们决定不再给主站添乱了,就另起炉灶做了两个新的业务系统,从查询商品、购买商品、评价反馈、查看订单这一整个流程都重新写了一套。现在在“我的淘宝”中查看交易记录,还能发现“已买到的宝贝”中把机票和彩票另外列出来了,他们没加入到普通订单中。
        当时如果已经把会员、交易、商品、评价这些模块都拆分出来,就不用什么都重做一遍了。

        其中,UIC和Forest在上文已说过,TC、IC、SC分别是交易中心(Trade Center)、商品中心(Item Center)、店铺中心(Shop Center),这些中心级别的服务只提供原子级的业务逻辑,如根据ID查找商品、创建交易、减少库存等操作。
        再往上一次是业务系统TM(Trade Manager,交易业务)、IM(Item Manager,商品业务)、SM(Shop Manager,后来改名叫SS,即Shop System,店铺业务)、Detail(商品详情)。
        拆分之后,系统之间的交互关系变得非常复杂。
        系统这么拆分的好处显而易见,拆分之后每个系统可以单独部署,业务简单,方便扩容;有大量可重用的模块便于开发新的业务;能够做到专人专事,让技术人员更加专注于某一个领域。
        这样要解决的问题也很明显,拆分后,系统之间还是必须要打交道的,越往底层的系统,调用它的客户越多,这要求底层系统必须具有超大规模的容量和非常高的可用性。
        另外,拆分之后的系统如何通信里需要两种中间件系统,一种是实时调用的中间件(淘宝的HSF,高性能服务框架),一种是异步消息通知的中间件(淘宝的Notify)。另外,一个需要解决的问题是用户在A系统登录后,到B系统的时候,用户的登录信息怎么保存又设计一个Session框架。再者,还有一个软件工程方面的问题,这么多层的一套系统,怎么去测试它br>

二. 中间件


1.HSF

        其实互联 站发展过程类似于超市经营(此处省略超市销售收银的例子,可以想象下沃尔玛排队购物付款的场景吧),只是在技术层面用其他名词来表达而已,例如:有集群、分工、负载均衡、根据QoS分配资源等。
        集群:所有收银员提供的都是收银功能,每个收银员都可以完成收款,可以认为所有的收银员构成了一个集群。互联 集群会受限于调度、数据库、机房等。
        分工:收银员和打扫卫生的人分开,这种分工容易解决,而这种分工在互联 中是一项重要而复杂的技术,涉及的主要有按功能和数据库的不同拆分系统等。如何拆分和拆分后如何交互是需要面临的两个挑战。隐藏会有高性能通信框架、SOA平台、消息中间件、分布式数据层等基础产品的诞生。
        负载均衡:让每个收银台排队差不多长,设立小件通道、团购通道、VIP通道等,这些都可认为是集群带来的负载均衡的问题,从技术层面上实现自然比生活中复杂得多。
        根据QoS(Quality of Service,服务质量)分配资源:部分员工仅在晚上加班的机制在生活中不难实现,但对互联 应用而言,就是一件复杂而且极具挑战的事。

        而且生活中面对用户增长的情况下,想出这些招应该不难。不过要掌握以上四点涉及的技术就相当复杂了,而且互联 中涉及的其他很多技术还没有在这个例子中展现出来。例如缓存、CDN等优化手段;运转状况监测、功能降级、资源劣化、流控等可用性手段;自建机房、硬件组装等成本控制手段。因此,构建一个互联 站确实是不容易的,技术含量十足,当然,经营一家超市也不简单。
        服务拆分之后,如何取得我需要的服务呢br>         在“电视机”上,把每个集群能提供的服务显示出来。你不需要关心哪个人为你服务,当你有需要的时候,头顶的电视机会告诉你哪个服务在哪个区域。当你去到这个区域时,系统会给你找到一个最快的服务通道。

        HSF框架以SAR包的方式部署到Jboss、Jetty或Tomcat下,在应用启动时,HSF(High-Speed Service Framework,在开发团队内部有一些人称HSF为“好舒服”)服务随机启用。HSF旨在为淘宝的应用提供一个分布式的服务框架,HSF从分布式应用层面以及统一的发布/调用方式层面为大家提供支持,更容易地开发分布式应用或使用公用功能模块,而不用考虑分布式领域中的各种细节技术,例如:远程通讯、性能损耗、调用的透明化、同步异步调用的问题。

        HSF是一个分布式的标准Service方式的RPC(RemoteProcedure Call Protocol,远程过程调用协议)框架。Service的定义基于OSGI的方式,通讯层采用TCP/IP协议。         参考:毕玄的分布式服务框架理论博         http://www.blogjava.net/BlueDavy/archive/2008/01/24/177533.html         HSF系统目前每天承担300亿次以上的服务调用,一些读者可能会疑问:既然淘宝的服务化是渐进式的,那么在HSF出现之前,系统之间的调用采用什么方式呢/span>         这个有点“五花八门”。对于类目的调用方式是Forest打包成一个JAR包,在应用启动时装载到内存中,仅这个JAR包所占用的内存就有800MB之多(因为淘宝的类目数据庞大),对于当时一般只有2GB内存的开发机来说,加载完类目信息后,机器运行速度就非常慢。对于用户信息(UIC)来说,一开始调用方式是Hessian接口,还有一些系统是通过WebService、Socket甚至是HTTP请求来相互调用的。        每种调用方式都涉及各种超时、信息的加解/密、参数的定义等问题,由此可见,在没有HSF之前,系统之间的调用是错综复杂的。而随着系统拆分得越来越多,必须由一个统一的中间层来处理这种问题,HSF就是在这种背景下诞生的。

2.Notify

       HSF解决了服务调用的问题,我们再提出一个很早就说过的问题:用户在银行的 关付钱后,银行需要通知到支付宝,但银行的系统不一定能发出通知;如果通知发出了,不一定能通知到;如果通知到了,不一定不重复通知一遍。
        这个状况在支付宝持续了很长时间,非常痛苦。支付宝从淘宝剥离出来时,淘宝和支付宝之间的通信也面临同样的问题,支付宝架构师鲁肃提出用MQ(Message Queue)的方式来解决这个问题,我负责淘宝这边读取消息的模块。但消息数量上来后,常常造成拥堵,消息的顺序也会出错,系统挂掉消息也会挂掉。
        然后鲁肃提出做一个系统框架上的解决方案,把要发出的通知存到数据库中,如果实时发送失败,再用一个时间程序来周期性地发送这些通知,系统记录下消息中间状态和时间戳,这样就保证了消息一定能发出,也一定能通知到,且通知带有时间顺序,甚至可以实现失去性的操作。
       (PS:这个技术感觉以前做Android类似微信的随手拍软件时非常适用)
        在“千岛湖”项目和“五彩石”项目后,淘宝系统拆分成了很多个,他们之间也需要类似的通知。例如,拍下一件商品,在交易管理系统中完成时,它需要通知商品管理系统减少库存,同时旺旺服务系统发送旺旺提醒,通知物流系统上门取货,通知SNS系统分享订单,通知公安局的系统这是骗子等等。
        用户一次请求,在底层系统可能产生10次的消息通知。这一大堆的通知信息是异步调用的(如果同步,系统耦合在一起就达不到拆分的目的),这些消息通知需要一个强大的系统提供支持,从消息的数量级上看,比支付宝和淘宝之间的消息量又上了一个层次,于是按照类似的思路,一个更加强大的消息中间件系统就诞生了,它的名字叫做Notify。
        Notify是一个分布式的消息中间件系统,支持消息的订阅、发送和消费,其架构图如下所示:

3.TDDL

        有了HSF和Notify的支持,在应用级别中,整个淘宝 的系统可以拆分了,还有一个制约系统规模的更重要的因素就是数据库,也必须拆分。
        前面讲过淘宝很早就对数据进行过分库的处理,上层系统连接多个数据库,中间有一个叫做DBRoute的路由来对数据进行统一访问。DBRoute对数据进行多库的操作、数据的整合,让上层系统像操作一个数据库一样操作多个库。随着数据量的增长,对于库表的分发有了更高的要求。例如,你的商品数据到了百亿级别时,任何一个库都无法存放了,于是分成2个、4个…1024个、2048个。分成这么多,数据能存放了,那怎么查询它br>         这时候,数据查询的中间件就要能够承担这个重任了,它对上层来说,必须像查询一个数据库一样来查询数据,还要想查询一个数据库一样快(每条查询在几毫秒内完成),TDDL就承担了这样一个工作。
        另外,加上数据的备份、复制、主备切换等功能,这一套系统都在TDDL中完成。在外面有些系统也用DAL(数据访问层)这个概念来命名这个中间件。TDDL实现了下面三个主要的特性:
        1).数据访问路由——将针对数据的读写请求发送到最适合的地方
        2).数据的多向非对称复制——一次写入,多点读取
        3).数据存储的自由扩展——不再受限于单台机器的容量瓶颈与速度瓶颈,平滑迁移
        下图展示了TDDL所处的位置:

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2015年5月7日
下一篇 2015年5月8日

相关推荐