Think2Go戈登营首期review

2013-09-14

Go语言在CDN下载系统中的应用

今天去参加了Go语言上海的线下活动,这里做个简单的review。只是个人理解,可能有误,拍砖轻点。

首先是谢大闪亮登场,为我们分享他用Go语言在盛大的CDN系统中的应用,大家鼓掌。

我觉得讲的主要内容上可以分两大块来看,一部分是从中心结点到IDC的文件分发过程,另一部分是用户请求到达之后的调度设计。

主要应用场景像什么游戏客户端的分发之类的。先说中心结点服务器到IDC服务器的分发过程。

大家知道,国内的网络环境各种奇葩,最远的距离不是城市到城市的物理距离,而是我用电信,你用联通,或者他是教育网等等。IDC机房是离各大运营商的网络都是比较通畅的,这样的结点大概是有6个(不记得是不是了)。有一个中心结点服务器。整个过程是内部把要分发的文件,先通过ftp上传到中心服务器,接着中心服务器将文件分发到各个IDC,然后就是IDC再往下面一层分发。

先说他们以前的方案和问题吧。以前他们给要分发的文件制作种子,用ctorrent。让IDC的服务器从中心服务器去下,然后bt的方式各个服务器可以相互之间下载。但是这样有两个主要问题。

第一个问题是,从中心服务器到IDC机房,以及各个IDC机房之间,这个网络流量是要算钱的,而bt协议是分布式的,内部机制不可控,比如没法控制它的tracker,也没法阻止一个IDC的服务器跑到另一个IDC去请求数据,这些流量都是额外的钱啊...而同一个IDC内部的服务器之间,都是内部的,这个流量不用钱的。所以bt的方式比较坑。

第二个问题是,ctorrent有bug,经常文件传到99%就死掉。这个不好解决,据后面韩拓讲,目前开源的bt算法实现大多都存在这个问题。所以谢大开始自己做这一块。

从中心结点到IDC的分发过程,分成两层传输过程设计,第一层是由中心服务器,将文件分块之后,将各个块传到一个IDC内的不同服务器上,这样在一个IDC内部就有了所有的文件数据分片。

第二层是由IDC内部的服务器之间,相互交换数据,直到IDC的每个服务器都拥有了完整的文件。比如,中心服务器将一个文件分成四块,A,B,C,D,然后分别传给IDC中的服务器S1,S2,S3,S4...接着由S1,S2,S3,S4之间相互交换数据,最终每台机器都拥有一个完整的文件了。好处就是IDC内部服务器之间传数据,流量不要钱的,光冲这一点,我觉得盛大应该给谢大多发点奖金,呵呵。

里面有些小的细节,比如说第一层传输与第二层传输可以是同步进行的,不必要等到整个文件都传到IDC完成,才进行第二步的相互交换。中心服务器是控制结点,每个IDC服务器接收完一块数据之后,给服务器发送消息。服务器可以给它返回消息让它执行第二层传输。中心服务器是主从的,如果down掉了就切换备用的。

IDC服务器那边对每一个文件块都记了md5校验信息,并且本地缓存了一个.astaxie文件,记录下已经完成的块。这样当任务失败重传时,只需要传输失败了的那些块而不用全部重传。

文件分块的大小是以8M为单位的,这是运维那边给出的一个经验值,以前是4M。为什么是经验值呢?网络波动,断链,各种问题会经常遇到。分块大了,失败之后重传损失就比较大。而如果分块太小,传输次数以及通信次数就会增加,传一个文件的耗时就会变长了,所以这个是一个经验值。然后是超时重传,设置的超时时间是10分钟。比如说差某一个块没有从中心服务器传到IDC服务器,超时之后就会重新传输(换一台服务器?)。

谢大在讲这些东西时还给我们展示了一下代码,很赞!

上一部分的内容基本是内部传输部分,从中心服务器分发到IDC。接下来是另一部分,调度器的设计部分。

调度器设计就是要考虑,根据网络情况,地理位置,当前各个服务器负载等等,来一个下载请求,决定取哪一台机器给用户提供下载服务。

CDN的基本技术,就是通过用户的IP段,查找他属于哪个网络,电信,网通?然后分配相应网络的服务器给用户提供下载。他们以前的做法是,只要找到同网络的服务器后,随机分配一台给用户提供服务。随机分配存在的问题是,服务器的负载不均衡,可能有的机器忙不过来了,而另一些却闲着。

盛大有个IP库,记录了各个IP段所处的网络,对应的分配服务器。这个在代码中谢大是用treap数据结构体存的,treap是一个kv数据结构,通过二叉树进行查找,通过一个随机权值保证树的平衡。我尚不明白这里为什么选用treap数据结构。使用treap数据结构的结点权值,和服务器负载之间是否有关系?不是吧(期间我去WC了,这里漏了一些内容)。

现在添加了负载分配的部分,会给服务器加上状态。比如优先挑选同网络服务器上负荷较低的机器,如果各个机器负荷都是中等的,则随机挑选一个。如果都到满负荷了,这时则不局限于同网络了,从全局服务器中随机挑一个,总不至于给用户返回404吧。

据谢大称,用Go语言实现以后,目前的系统相比以前的传输速度大大提升,传大文件速度是几乎原来的十倍了,小文件的提升也有30%。用户下载也明显变快了。最后谈到了下阶段可做的优化。其中有一点就是处理上行和下载之间的带宽。有时候几十G的文件任务啪一下就过来了,目前是没有限制的,这样会占用大量带宽,对已在进行中的用户服务造成影响。

我提问了一下,他们cdn的服务器是否独立的。因为服务器如果跑着其它服务,那么刚才提到的优化仅仅是控制自己系统内部的上行下载带宽是无意义的,因为其它服务不一定会合作限制自己的传输带宽。谢大的回答大概是,它们的cdn服务器是独立了,只是运行相关的服务。然后我又问了一下关于文件分片传输时,可能某片就是不能成功,是否有考虑过将一片数据文件同时传多个服务器,有一个服务器最先返回成功就算成功,然后取消这一块的其它传输任务。谢大的解释是这块不做,会使系统复杂化,现在只是简单的做超时处理。

时间有限,我才提一两个问题就被锅巴GG禁言了。是不是觉得我提的问题太没水平啊...有木有?

其实问第一个问题,某个服务器跑哪类服务,有两种处理。一个趋势就是专门订制的硬件来单一跑这种服务。以前在百度时看他们的分享,他们数据中心都有专门选择的硬件,像这种CPU要求不高,主要是网络IO和磁盘IO,直接是用arm的cpu,刀片服务器。然后有些场景可能还会使用SSD硬盘。他们的优化真是要榨干硬件的极限,甚至为了节省成本,内存都不是买内存条的,直接采购内存颗粒。我不知道盛大是否有做到对不同的服务专门去选购硬件这种程度。另一个趋势就是均衡型的硬件,然后优化软件这边,让一个服务器中同时跑各种CPU型和IO型的任务,尽量不让其中一种成为瓶颈。google那边的虚拟化就是偏这边的。显然CDN的应用场景下,cpu不是问题。据谢大讲,瓶颈是在硬盘上面。至于另一个问题,我记得gfs的论文中,分片后好像是传多份的,上面提到由于不同服务器之间硬件不同,网络环境不同,会有一些传输时间格外长,所以它会同时传到多个,其中一个返回成功后就取消其它任务。不过也分应用场景,不深究了。

扯远了...好吧,这么精彩的分享...再次鼓掌吧。

Go在微博数据分析中的应用

接着是邵天宇带来的分享。其实我个人觉得他分享的内容跟Go语言的主题并不算太搭,个人觉得他项目中做的很多事情选择别的语言,别的开源库可能会做得更好,并没有突出Go语言的优势,选择Go只是他强烈的个人偏好而已,这个我持保留态度。这是这位同学第一次做这种分享,不管怎么样,即然使用了Go也算是Go语言的实践了,并且内容方面我认为还是比较精彩的。

微博数据分析中,我觉得可以分以下部分看吧,先是数据源的获取,接着是数据存储,然后是数据分析。

他先给我们介绍了他的开源库的选型。数据源的获取中,他是自己写的爬虫抓取微博的数据,给我们展示了Go的interface在这里的使用,一个url加一个handler。分词和索引方面之前他尝试用wukong的Go语言开源库,但是这个库有个问题是不做持久化,数据全部存放在内存的。内存占用量非常大,在与作者沟通并没得到满意的解决之后,转而使用Es..search(名字记不清了)。列举了好多的开源项目,相信他是做了不少的调研工作。

还提到了他们以前系统是用php做的,硬件用的16核CPU,32G内存,而现在改用Go语言之后只用普通的PC机就能跑了。他还列举了好多数据,微博的活跃用户数啦,抓取的记录数啦,各种...反正是用数据说话,不明觉历啊,呵呵。

数据存储部分是用的leveldb,他觉得不信任mysql的性能并且当前的应用场景只是一些简单的存储和查询,leveldb更合适。他们现在抓取到的数据有700G,记录条数我忘记了。后面锅巴出来澄清,并不能说mysql在这里不适合,mysql是一个存储框架,至于具体使用什么样的存储引擎可以根据需求去选择。

数据分析部分,使用的是标签传播算法,这个应该算是一个很基础的机器学习的算法了。比如说微博用户可能给自己加了各种标签,比如IT,80后等等。标签传播算法通过已有用户标签和用户之间的关系来学习一个用户是属于哪个圈子。这个算法有点领域倾向,没有基础的同学不一定听懂了。不过还好,听不懂学到的东西才多嘛。这个算法也是用Go语言自己实现的,并没有去找数据挖掘的一些库使用。

标签传播算法的训练大概要花一天时间,不过后面再来数据时就是增量训练了,这算算法本身是很难做实时的,都是来一波数据后增量计算的。他们主要是面向内部用户,所以查询有个1秒的耗时其实都无所谓。

后面提问环节要饭狗同学争论抓取微博数据有限制,并且新浪6月份改api后,抓取权限之类的问题。现在都小心冀冀地怕抓多了会被封号。还有另一个同学提问是问他的开源库选型,以及leveldb合并时不可写的问题。

记得邵天宇开头很紧张,谦虚地说只是做了一个月,没有太多可以给大家分享的...一个月就这么牛了,这小伙子很有前途...好,我们鼓掌欢迎下一位吧。

golang与高强度在线服务

由韩拓给我们分享的,标题临时换了一下,他坦承"golang与高强度在线服务"这个标题有点太装B了。这个分享就比较高度抽象了,没有谈具体的项目,算是一些Go的使用经验吧。

中间有很多,我能记得的包括他们公司的panic是不能抛到进程级别的,必须在goroutine捕获。

像内存使用方面,不使用Go做大内存(大于1G)的服务。合适的东西做合适的事,这是我的感触,比如Go+memcached。主要是Go的垃圾回收不算完善,大量内存分配,回收时会卡。而C语言写的像memcached什么,肯定更专业。

http作为最基本的通信协议。

cgo是尽量避免不要使用的,即使像音频视频转码这类的,只有C的库,他们的做法是用C程序写成服务了让Go去调。

还有什么内存对齐,大多都是七牛公司踩过坑之后约定的一些使用习惯。给我印象比较深的是他们的log处理,他们重写了log的包,提供程序log和事务log两类日志。

程序log中加了行号,函数等信息。比较牛B的是他们的事务log,几乎所有函数头一个参数都是log.Instance,一层函数调用就加一层记录,他们追踪了所有的日志记录。日志可以用于定位bug,用于审计,甚至客户付费等等。从一条请求进来,就给分配了一个类似sessonId的东西,所有的log.*的函数中都会包含这个sessonId。这些日志最后会被收集起来,提供搜索,这样就可以追踪一条请求的所有记录了。

类似地还有error,也是改过了的。

太晚了,就写到这里吧。最后帮锅巴打个广告:大牛带小牛,小牛带蜗牛...下次参加活动的记住这个口号,可以领书的哦~

golangcdn微博数据分析