数据加载中……

置顶随笔

[置顶]MemCached Cache Java Client封装优化历程

     摘要:   Author:文初 Email: wenchu.cenwc@alibaba-inc.com Blog: http://blog.csdn.net/cenwenchu79/            MemCached Cache在大型网站被应用得越来越广泛,不同语言的客户端也都在官方网站上...  阅读全文

posted @ 2008-09-25 16:34 岑文初 阅读(1144) | 评论 (3)编辑 收藏

2008年10月7日

“开放”的一些感想

         从去年到今年,开放这个词也在互联网上炒得火热,自己一年多的工作也让自己对开放这个词有了自己的一些理解和认识。

开放的平台

         去年到今年自己的工作也随着公司的战略改变不断的发生着变化。最早公司定位致力于为中小企业提供商务管理软件,让中小企业能够通过使用在线软件轻松搞定电子商务贸易管理。随后公司又致力于提供开放的在线软件运营平台,为众多ISV和中小企业建立一个软件交易平台,中小企业可以随需定制管理软件。到今年年初,提出了服务集成平台,ISV的应用开发不再是封闭的开发模式,可以基于ISP提供的服务定制出更加丰富的应用。其实这种转变也是对平台的开放的思想不断成熟的一个过程。

         独自实现在线管理软件和传统软件其实没有太大的差别,唯一的差别就是把应用由客户的机器拉到了软件提供商的服务器上,对于维护,更新和商业模式可能有部分的变化,但是根本上来说软件的封闭性还是和传统软件一样。互联网软件的最大特点就是个性化需求强烈以及需求变更周期短,要适应行业客户的需求,仅仅靠一个公司的几杆枪几号人的创意远远不够。Web2.0的热潮其实能够给开发人员最大的启示就是参与才是力量的源泉,其实软件开发也是一样,如果能够集合互联网上众多ISV的思想和创意,那么满足用户需求并不是一件难事,同时及时响应用户需求也不再是火烧屁股的事情。同时,看看互联网应用开发的今天,国外Open API前几年就已经兴起,Amazon,Google,Yahoo,FaceBook,MySpace等等,将自己的数据,存储,计算通过API的方式提供给第三方,让第三方开发者能够通过使用这些服务有机会实践自己的创新和创意,互联网应用的开发也有了新的开放式开发模式。服务集成平台其实就是为ISV提供了创建应用的一个资源平台,ISV可以通过服务集成平台获取到各个ISP(例如淘宝)API,在其基础上开发出在线应用,然后直接挂接到应用运营平台为终端用户提供应用服务。这很类似于传统行业的产业链,服务集成平台就好比原料交易市场,应用运营平台就好比商品交易市场。回过头来看,阿里系的各个子公司,其实都是在以这种思路做事,从加入公司到现在,给我印象最深刻的一句话就是:“凡事不要先想着如何赚到别人的钱,让别人先赚到钱,别人自然很乐意的和你分享”,这种双赢的思想在开放中能够得到最好的实践。

开放的框架

         一个公司技术是需要积累的,如果纯粹让每一个开发人员根据自己的能力去合作开发企业的产品和平台,对于企业,对于产品都是不利的。Java吸引人就在于它的开源世界,每一个开发人员可以去获得自己想要的,或者去贡献给他人自己创造的。现在很多公司应聘的过程就是一个开源知识问答,其实是否用过能说明什么问题呢,关键是没用过如何去学习和了解并且快速上手,如果能力再强一点,那就知道如何定制和扩展,我想这样的才可以叫做企业需要的人才。

         从公司成立那时起,内部就有一个应用开发框架,作用就是为了快速开发应用,尽最大可能降低开发者对于开发技术的学习,集中精力致力于业务开发。(当然看到这里估计98%的开发人员都会皱起眉头)。我也为此贡献了自己2Q的工作时间,当时我主要负责后台重构,需要建立起一个服务框架,开始参考了OSGI(因为它的模块化和动态载入机制),发现并不是很合适,然后接触了SCA框架(可扩展,模块化,SOA的支持),最后决定在开源项目Tuscany0.91版本的基础上再次开发和封装,实现了内部的ASF(应用服务框架)ASF作为我们开发框架的后台基础框架被广泛使用在了我们的多条产品线以及基础平台上,但是ASF的质疑就一直没有停过,性能,学习成本,调试困难度等等。虽然自己竭力去写了厚厚的一套文档,一组单元测试工具,一系列的问题查找工具,作了多次的压力测试,学习普及,但是还是得不到一些架构师的支持。

         其实,自己在后面也做过一些思考,其实对于ASF来说,它的可扩展性没有什么好怀疑,他不像其他开源项目,我可以封装Hessian组件,REST组件等等,随需载入,开发者只需要配置一下标签,即可使用,因此这样的框架下,不会随着技术的发展和自己的封闭而腐烂。但是,有一点就导致推广产生了那么多问题,那就是参与。我记忆很深的就是我们的首席架构师在今年招开会议评估ASF的问题时地邮件中说的:“ASF不是岑文初一个人的ASF,也不是平台一部的ASF,而是大家的ASF”。其实那时候我已经不再专职负责ASF,当今年因为一个项目进度由于开发受到影响时再次提出ASF的质疑地时候,我自己真的觉得比较沮丧,很多架构师和开发者从来就没有看过文档,没有用过调试工具,没有看过Q&A,一出问题就觉得无所适从,要找人解决框架问题,我曾经说是否Spring用的时候出现问题,第一想法就是去找Spring的开发者,还是先会看看文档,调试一下。我想这应该是两方面的原因,但如果能够让每个人都参与进来,那么就不会是今天一人独挡的局面。

         因此未来自己的工作中,不论是内部的基础组件还是基础平台都会多邀请一些参与者,毕竟自己的肩膀有限,蚂蚁就算在大力也需要有伙伴的支持。

开放的心态

         这点其实是做人的基本要素,有一个宽阔的胸怀才会有更多的机会,才会成长的更快。但是自己这点的却做得很不够。开发人员都有一个相同的特点就是热衷于技术钻研,今天搞一个东西比你快一点,明天做一个东西比他功能多一点,总是在技术方面去寻找满足。其实老大一直和我们也在说,现在公司内部的架构师并不是一个“全专”,也不一定是一个写代码高手,但是在某一个领域会有深入的研究,同时接触其他领域也能够胜任。没有什么技术人员是绝对的高手,其实随着工作重心的不断变化,所接触的领域也会不断发生变化,因此不可能有所谓的“全才”。

         有时候自己也会用技术的眼光去看待人或者事,其实这样只会让自己看不到自己的不足,也忽略了别人的优点,更重要的就是失去了一次进步的机会。其实经常给自己换换思路会对自己有很大的帮助,就好比最近忙于写了一阵子代码,那么就给自己一个机会去看看一些关于搜索领域的知识。开发了一个阶段的服务集成平台,去了解一下所有的国外网站Open API的风格,结构,流程。用惯了Java后,去学习学习Php,Ruby等等。这样换换脑子对自己来说会有新的收获。

         开放的心态理解容易,但是要让他不仅仅写在MSNtitle中,而写在心里却需要不断地督促和付出。不过知道自己有问题好过觉得自己没有问题。

         写了那么些,其实思路比较乱,我想从随笔里面也看得出来,但是还是想记录一下自己的一些思考,起码以后回过头来可以看到自己成长的过程。

posted @ 2008-10-07 13:24 岑文初 阅读(950) | 评论 (3)编辑 收藏

2008年9月26日

关于Memcached Cache是集中式还是分布式的一点补充

    昨天贴了这个帖子以后,有同学说我是不是写错了,Memcached Cache应该是分布式的Cache,怎么变成集中式了。

    这里把我另外一部分的内容贴出来。

    Memcached是一种集中式Cache,支持分布式横向扩展。这里需要有点说明,很多开发者觉得Memcached是一种分布式Cache,但是其实Memcached服务端本身是单实例的,只是在客户端实现过程中可以根据存储的主键作分区存储,而这个区就是Memcached服务端的一个或者多个实例,如果将客户端也囊括到Memcached中,那么可以部分概念上说是集中式的。其实回顾一下集中式的构架,无非两种情况:1.节点均衡的网状(JBoss Tree Cache),利用JGroup的多播通信机制来同步数据。2.Master-Slaves模式(分布式文件系统),由Master来管理Slave,如何选择Slave,如何迁移数据,都是由Master来完成,但是Master本身也存在单点问题。

总结几个它的特点来理解一下它的优点和限制。

         Memory:内存存储,不言而喻,速度快,对于内存的要求高,不指出的话所缓存的内容非持久化。对于CPU要求很低,所以常常采用将Memcached服务端和一些CPU高消耗Memory低消耗应用部属在一起。(作为我们AEP正好有这样的环境,我们的接口服务器有多台,接口服务器对于CPU要求很高(由于WS-Security),但是对于Memory要求很低,因此可以用作Memcached的服务端部属机器)

         集中式Cache:避开了分布式Cache的传播问题,但是需要非单点保证其可靠性,这个就是后面集成中所作的cluster的工作,可以将多个Memcached作为一个虚拟的cluster,同时对于cluster的读写和普通的memcached的读写性能没有差别。

         分布式扩展:Memcached的很突出一个优点,就是采用了可分布式扩展的模式。可以将部属在一台机器上的多个Memcached服务端或者部署在多个机器上的Memcached服务端组成一个虚拟的服务端,对于调用者来说完全屏蔽和透明。提高的单机器的内存利用率,也提供了scale out的方式。

         Socket通信:传输内容的大小以及序列化的问题需要注意,虽然Memcached通常会被放置到内网作为Cache,Socket传输速率应该比较高(当前支持Tcp和udp两种模式,同时根据客户端的不同可以选择使用nio的同步或者异步调用方式),但是序列化成本和带宽成本还是需要注意。这里也提一下序列化,对于对象序列化的性能往往让大家头痛,但是如果对于同一类的Class对象序列化传输,第一次序列化时间比较长,后续就会优化,其实也就是说序列化最大的消耗不是对象序列化,而是类的序列化。如果穿过去的只是字符串,那么是最好的,省去了序列化的操作,因此在Memcached中保存的往往是较小的内容。

         特殊的内存分配机制:首先要说明的是Memcached支持最大的存储对象为1M。它的内存分配比较特殊,但是这样的分配方式其实也是对于性能考虑的,简单的分配机制可以更容易回收再分配,节省对于CPU的使用。这里用一个酒窖比喻来说明这种内存分配机制,首先在Memcached起来的时候可以通过参数设置使用的总共的Memory,这个就是建造一个酒窖,然后在有酒进入的时候,首先申请(通常是1M)的空间,用来建酒架,酒架根据这个酒瓶的大小分割酒架为多个小格子安放酒瓶,将同样大小范围内的酒瓶都放置在一类酒架上面。例如20cm半径的酒瓶放置在可以容纳20-25cm的酒架A上,30cm半径的酒瓶就放置在容纳25-30cm的酒架B上。回收机制也很简单,首先新酒入库,看看酒架是否有可以回收的地方,如果有直接使用,如果没有申请新的地方,如果申请不到,采用配置的过期策略。这个特点来看,如果要放的内容大小十分离散,同时大小比例相差梯度很明显,那么可能对于使用空间来说不好,可能在酒架A上就放了一瓶酒,但占用掉了一个酒架的位置。

         Cache机制简单:有时候很多开源的项目做的面面俱到,但是最后也就是因为过于注重一些非必要性的功能而拖累了性能,这里要提到的就是Memcached的简单性。首先它没有什么同步,消息分发,两阶段提交等等,它就是一个很简单的Cache,把东西放进去,然后可以取出来,如果发现所提供的Key没有命中,那么就很直白的告诉你,你这个key没有任何对应的东西在缓存里,去数据库或者其他地方取,当你在外部数据源取到的时候,可以直接将内容置入到Cache中,这样下次就可以命中了。这里会提到怎么去同步这些数据,两种方式,一种就是在你修改了以后立刻更新Cache内容,这样就会即时生效。另一种是说容许有失效时间,到了失效时间,自然就会将内容删除,此时再去去的时候就会命中不了,然后再次将内容置入Cache,用来更新内容。后者用在一些时时性要求不高,写入不频繁的情况。

         客户端的重要性:Memcached是用C写的一个服务端,客户端没有规定,反正是Socket传输,只要语言支持Socket通信,通过Command的简单协议就可以通信,但是客户端设计的合理十分重要,同时也给使用者提供了很大的空间去扩展和设计客户端来满足各种场景的需要,包括容错,权重,效率,特殊的功能性需求,嵌入框架等等。

         几个应用点:小对象的缓存(用户的token,权限信息,资源信息)。小的静态资源缓存。Sql结果的缓存(这部分用的好,性能提高相当大,同时由于Memcached自身提供scale out,那么对于db scale out的老大难问题无疑是一剂好药)。ESB消息缓存。

posted @ 2008-09-26 11:45 岑文初 阅读(1274) | 评论 (2)编辑 收藏

2008年9月25日

MemCached Cache Java Client封装优化历程

     摘要:   Author:文初 Email: wenchu.cenwc@alibaba-inc.com Blog: http://blog.csdn.net/cenwenchu79/            MemCached Cache在大型网站被应用得越来越广泛,不同语言的客户端也都在官方网站上...  阅读全文

posted @ 2008-09-25 16:34 岑文初 阅读(1144) | 评论 (3)编辑 收藏

2008年9月18日

Memory Leak分析分享

越是忙,杂七杂八的事情越多,最近正在优化Memcache的客户端代码,这时候SIP突然出现OOM的问题(Out of Memory),作开发最头痛就是这种问题,压力测试都作过,早期的几个版本都没有出现这样的问题,因此怀疑可能是最近一次发布修改引起的。借助JProfiler在测试环境搭了一套系统,开始做压力测试,来分析Memory到底流到了哪里去了。

问题一:连接池泄漏

       看到这个问题,我想很多人都说,都什么年代了,使用开源的现成连接池,怎么还会有这样的问题,又不是那些使用jdbc的年代了。那来看看现象吧。

场景:测试部用loadRunner往死里压,发现很多业务对象不断增长,但是按照业务场景来说,这些业务对象处理以后就自动释放了。(在本地的开发环境验证了是会自动释放的)

JProfiler截图:

       上图中可以看到有很多业务对象已经累积占用了不少内存,在让测试部同学停掉压力测试以后,等待了一会儿,然后用JProfiler主动发起垃圾回收,也看到了Jboss后台有GC回收的记录输出以后,发现这些对象依然存在,也就是说这些对象成为了Memory泄漏的诱因之一。但是就如我所说的,在本地测试以及白盒测试来看,这些对象在一次请求以后,处理完毕一定会被释放,没有被其他MapReference,然后通过JProfiler看了看这些对象的Allocation Call Tree,就是我们处理请求的Servlet作为源头的,但为什么Servlet没有被清理掉呢?接着来看看后面二张图

       既然知道对象存在并且被Hold了,那么就去看看线程运行的状况,这一看发现有很多线程都处于Wait的状态(其实在serverdump也可以看到),这张图上就可以看到,我选择了其中一个wait的线程它处于等待状态的原因就是在ibatisThrottleincrement的时候处于等待状态,看了看ibatis的代码,这部分代码其实是ibatis连接池的一段代码,在连接池被占满以后,处于等待释放的状态,也就是说程序把连接池耗尽了。

       为了验证是否是耗尽了,让DBA老大光辉给我看了看MySql(这部分当天的日志数据都保存在MySql中)的连接情况,发现只有8个连接,看来不是真的耗尽,应该是连接池泄露了。光辉告诉我,这八个连接都在做同一个查询,就是统计某一个API的访问记录次数和流量。在当前的业务流程中对于MySql主要做了两类操作:

       1.访问控制计数器创建的统计查询。

由于要对Open API访问控制,采用了Memcache计数器方式来实现。当发现此类API没有创建过计数器,那么就分析MySql中的数据,创建计数器,后续的访问记录除了插入数据库以外还需要累加计数器,这样访问控制可以高效使用集中式计数器而不需要查询数据库。

2.日志批量异步写入。

对于Open API的记录采用了线程池中每一个线程维护一个内存分页,当页满或者到了刷新间隔时,一次性批量写入数据库,缓解数据库写入压力,这里采用了事务来批量提交。

       对于第一种操作,由于设计中MySql就只会保留当天的数据量,因此只有系统启动的时候做一次统计,对于数据库压力和Sql执行来说应该没有太大的压力,但是由于压力测试是从昨天下午就开始做的,里面的数据已经有上千万,因此这次重新启动开始做压力测试,导致了这个创建计数器的Sql执行很慢。同时日志的批量写入采用的是事务方式来提交,对于MySql其实自己还不是很深入,但是感觉上来说,问题应该出现在这里,由于查询的缓慢在加上事务批量的提交,可能会造成事务失败,同时没有正确的将释放资源的信号传递给ibatis,导致了看起来的连接资源耗尽。

       我将数据库中的记录全部删除,然后重新启动,开始压力测试,问题不存在了,对象都及时得到回收。后续还会去跟进这个问题,在ibatis早期版本,同样是这个类出现了死锁的问题,后来升级得到了解决,但是也看到很多国外的朋友说道2.22.3其实还是有死锁的问题,不过我个人觉得可能还是和数据库也有一定关系。

疑问:

       这个问题的背后我还有一点疑问,对于我们来说,如果一个普通的http请求,当超时以后肯定就会自动中断,但是在这个场景中,我足足等了1个小时还是没有释放,也就是说客户端其实已经断开了,但是JBoss好像并不会释放这些处理请求的事务,导致资源被卡。

问题二:LinkedBlockingQueue惹祸

       自从Jdk1.5以后concurrent包为大家提供了很多便利高效的开发新模式,我在不少地方用到了LinkedBlockingQueue,作为消费者和生产者之间的数据通道,消费者们等待在LinkedBlockingQueue门口守候生产者提供数据,获取数据后就开始并行处理。这里我会采用queue.poll(100,TimeUnit.MILLISECONDS)这种方式来半阻塞的获取数据。其实在昨天已经听说LinkedBlockingQueue可能存在着内存泄露的问题,看了看很多网上的人也都提到了这个问题,在1.5种没有得到解决,在1.6中会去fix这个问题,但是没有证据,也不好乱加断定。在问题一搞好以后,然后继续查找潜在bug,这时候不经意的发现有一个对象随着时间的推移始终在增加,但是由于单个对象占的内存不大,因此没有很明显的体现出来,但是对象实例的增加却是很明显的,看看下面两张图:

      

这两张图的间隔时间2小时左右,可以发现这个对象的instance已经有了很大的增长,同时内存也吃了不少,看了看创建这个对象的Tree,发现就是poll这个方法,也就是我线程池中线程周期性扫描的结果。这期间没有任何访问,仅仅就是放着不动,就有如此大量的增长。我尝试将poll(100,TimeUnit.MILLISECONDS)换成poll()全阻塞方式,对象增长依旧。因此可以看出来服务器的Memory Leak很大程度上由这部分引起,早先没有发现,因为是SIP上线不久,没有太多用户,而这阵子用户越来越多,加上API中的更新类请求比较吃内存,就容易发现此类问题。

       那么是否1.6就解决了这个问题呢,开始使用机器上1.6_01的版本,发现问题依旧,去sun下载了最新的1.6_07,发现的却会回收,但是回收和增长都存在,具体数据描述举例如下:

1.       1000 instance   31k

2.       200 instance    6k (回收了一部分)

3.       1500 instance   46k(发现增长的比以前还多)

4.       300 instance    9k (回收了一部分)

5.       2000 instance   62k (发现增长的比以前还多)

也就是说,回收时有发生,但是总体趋势还是在上升,这个真的还需要好好测试,有兴趣的同学也可以试验一下我的测试方式,就仅仅只需要使用一个LinkedBlockingQueue,然后定时的去pool1.5绝对增长的不小。

       对于这个问题,我只能再去验证,如果发现真的暂时不可避免,那么只有考虑替代方案了。

这是今天作了Memory Leak的一些分享,希望也能给其他遇到或者将会遇到问题的同学一个分享,说一句,如果有条件的话用JProfiler去分析性能绝对是不错的,没有条件么就dump,gc输出来查找问题。
   刚刚作了测试现在的场景可以用take来替换poll,原来是看中了poll的timeout方式,take完全没有问题,看来如果要在1.5版本用,还是老老实实用take。

posted @ 2008-09-18 22:14 岑文初 阅读(1091) | 评论 (4)编辑 收藏

2008年8月14日

Memcache Hash算法值得探索的内容

 

       集团内部很多团队都使用Memcache来提高应用性能,最近的一次工作汇报中提及了MemcacheHash算法需要研究来满足一些需求,同时提高Memcache的利用效率。讨论了一下最后自己总结了这么几点是对Hash算法需要着重考虑的。

问题:

1.       存储数据如何均匀分散。如何把数据尽可能的散开存储,这样对于Memcache的可扩展性才会有充分利用,试想如果算法每次都会把数据定向到某几台机器,那么就会导致集群机器之间利用率的不均衡,无法发挥出集群效应。

2.       增减机器减小对原有数据存取的影响。由于业务量的增长势必需要对后端的服务器有所扩容,但是增加或者减少机器如何尽可能小的影响已有的缓存数据,这点直接影响业务处理以及应用的效率。

3.       提高Memcache效率。Memcache在压力测试下也会暴露出对于网络资源的消耗问题,毕竟也是网络间的Socket数据交互。

解决的一些思路和方法:

1.       Consistent Hashing是一种比较好的解决思路。可以参看一下:http://tech.idv2.com/2008/07/24/memcached-004/ 其中主要两个亮点就是稀释节点以及环状分区段管理。稀释节点就是将原来的节点再复制几十倍,使得离散度更高,数据更加分散。环状分区段管理,就能够将数据分区管理,在加入和减少节点时对数据产生影响最低,最好的类比就是解放前的地下工作者单线联系,如果被捕不会涉及到所有的地下党同志。

2.       集群的机器使用Memcache最好结合本地Cache,这里我们自己写了一个本地的类似于Memcache有超时时间Cache,两者结合一起使用缓存信息,在压力测试下提高了20%左右的性能。这里和我们的系统也有关系,我们对于Memcache有比较大的依赖,虽然已经对于每一个请求处理都防止重复获取信息,将必要信息放在线程上下文中,但是在运行期间还是会有不少的请求。

存储到Memcache中的数据类型:

1. 一次写入多次读,很少更新。这种数据系统启动以后构建,在非命中情况下不采用从后备数据源中获取数据来填充Memcache。(也是提高效率,同时防止一些攻击性的请求)

2. 多次写入多次读取。这类数据往往是在运行期被构建,非命中下会从后备数据源中获取,或者是某一种计算结果的缓存。

对于第一类数据来说,增加机器需要重新构建,如果采用分区分段,那么只需要构建某一部分的数据,或者是移动数据。对于第二类数据,增加机器如果采用简单的Hash算法也问题不大,最多存储多份,命中率降低,但是如果采用分区,也可以降低命中率下降的情况。

       这里只是抛出问题,后续如何解决请各位看官各抒己见了。当然这里自己也会考虑这方面的实现和设计。

posted @ 2008-08-14 10:36 岑文初 阅读(1378) | 评论 (1)编辑 收藏

2008年8月13日

Hadoop基本流程与应用开发——分布式计算开源框架Hadoop入门实践(三)

这是我最后一部分在InfoQ上连载的文章,测试部分其实很有启发
http://www.infoq.com/cn/articles/hadoop-process-develop

posted @ 2008-08-13 23:06 岑文初 阅读(280) | 评论 (0)编辑 收藏

2008年8月8日

HBASE松散数据存储设计初识

 

最近关注Hadoop,因此也顺便关注了一下Hadoop相关的项目。HBASE就是基于Hadoop的一个开源项目,也是对GoogleBigTable的一种实现。

       BigTable是什么?GooglePaper对其作了充分的说明。字面上看就是一张大表,其实和我们想象的传统数据库的表还是有些差别的。松散数据可以说是介于Map Entrykey & value)和DB Row之间的一种数据。在我使用Memcache的时候,有时候的需求是需要存储的不仅仅是简单的一个key对应一个value,可能我需要类似于数据库表结构中多属性的存储,但是又不会有传统数据库表结构中那么多关联关系的需求,其实这类数据就是所谓的松散数据。BigTable最浅显来看就是一张很大的表,表的属性可以根据需求去动态增加,但是又没有表与表之间关联查询的需求。

       互联网应用有一个最大的特点,就是速度,功能再强大,速度慢,还是会被舍弃。因此在大访问量的网站都采取前后的缓存来提升性能和响应时间。对于Map Entry类型的数据,集中式分布式Cache都有很多选择,对于传统的关系型数据,从MySQLOracle都给了很好的支持,唯有松散数据这类数据,采用前后两种解决方案都不能最大化它的处理能力。因此BigTable才有了它用武之地。

       HBASE作为Apache的开源项目,也是出于起步阶段,因为其实它所依赖的Hadoop也不能说已经到了成熟阶段,所以都有很大的发展空间,这也为我们这些开源爱好者提供了更多空间去贡献。这里主要会谈到HBASE的框架设计方面的知识和它的一些特点,不论是否采用HBASE去解决工作中的问题,一种好的流程设计总会给开发者和架构设计者带来一些思想上的火花。

HBASE设计介绍

数据模型

       HBASE中的每一张表,就是所谓的BigTableBigTable会存储一系列的行记录,行记录有三个基本类型的定义:Row Key,Time Stamp,ColumnRow Key是行在BigTable中的唯一标识,Time Stamp是每次数据操作对应关联的时间戳,可以看作类似于SVN的版本,Column定义为:<family>:<label>,通过这两部分可以唯一的指定一个数据的存储列,family的定义和修改需要对HBASE作类似于DBDDL操作,而对于label的使用,则不需要定义直接可以使用,这也为动态定制列提供了一种手段。family另一个作用其实在于物理存储优化读写操作,同family的数据物理上保存的会比较临近,因此在业务设计的过程中可以利用这个特性。

看一下逻辑数据模型:

Row Key

Time Stamp

Column "contents:"

Column "anchor:"

Column "mime:"

"com.cnn.www"

t9

"anchor:cnnsi.com"

"CNN"

t8

"anchor:my.look.ca"

"CNN.com"

t6

"<html>..."

"text/html"

t5

"<html>..."

t3

"<html>..."

上表中有一列,列的唯一标识为com.cnn.www,每一次逻辑修改都有一个timestamp关联对应,一共有四个列定义:<contents:>,<anchor:cnnsi.com>,<anchor:my.look.ca>,<mime:>。如果用传统的概念来将BigTable作解释,那么BigTable可以看作一个DB Schema,每一个Row就是一个表,Row key就是表名,这个表根据列的不同可以划分为多个版本,同时每个版本的操作都会有时间戳关联到操作的行。

再看一下HBASE的物理数据模型:

Row Key

Time Stamp

Column "contents:"

"com.cnn.www"

t6

"<html>..."

t5

"<html>..."

t3

"<html>..."

Row Key

Time Stamp

Column "anchor:"

"com.cnn.www"

t9

"anchor:cnnsi.com"

"CNN"

t8

"anchor:my.look.ca"

"CNN.com"

Row Key

Time Stamp

Column "mime:"

"com.cnn.www"

t6

"text/html"

物理数据模型其实就是将逻辑模型中的一个Row分割成为根据Column family存储的物理模型。

对于BigTable的数据模型操作的时候,会锁定Row,并保证Row的原子操作。

框架结构及流程


1 框架结构图

       HBASE依托于HadoopHDFS作为存储基础,因此结构也很类似于HadoopMaster-Slave模式,Hbase Master Server 负责管理所有的HRegion Server,但Hbase Master Server本身并不存储HBASE中的任何数据。HBASE逻辑上的Table被定义成为一个Region存储在某一台HRegion Server上,HRegion Server Region的对应关系是一对多的关系。每一个HRegion在物理上会被分为三个部分:HmemcacheHlogHStore,分别代表了缓存,日志,持久层。通过一次更新流程来看一下这三部分的作用:


2 提交更新以及刷新Cache流程

       由流程可以看出,提交更新操作将会写入到两部分实体中,HMemcacheHlog中,HMemcache就是为了提高效率在内存中建立缓存,保证了部分最近操作过的数据能够快速的被读取和修改,Hlog是作为同步HmemcacheHstore的事务日志,在HRegion Server周期性的发起Flush Cache命令的时候,就会将Hmemcache中的数据持久化到Hstore中,同时会清空Hmemecache中的数据,这里采用的是比较简单的策略来做数据缓存和同步,复杂一些其实可以参照java的垃圾收集机制来做。

       在读取Region信息的时候,优先读取HMemcache中的内容,如果未取到再去读取Hstore中的数据。

几个细节:

1.              由于每一次Flash Cache,就会产生一个Hstore File,在Hstore中存储的文件会越来越多,对性能也会产生一定影响,因此达到设置文件数量阀值的时候就会Merge这些文件为一个大文件。

2.              Cache大小的设置以及flush的时间间隔设置需要考虑内存消耗以及对性能的影响。

3.              HRegion Server每次重新启动的时候会将Hlog中没有被FlushHstore中的数据再次载入到Hmemcache,因此Hmemcache过大对于启动的速度也有直接影响。

4.              Hstore File中存储数据采用B-tree的算法,因此也支持了前面提到对于ColumnFamily数据操作的快速定位获取。

5.              HRegion可以Merge也可以被Split,根据HRegion的大小决定。不过在做这些操作的时候HRegion都会被锁定不可使用。

6.              Hbase Master Server通过Meta-info Table来获取HRegion Server的信息以及Region的信息,Meta最顶部的一个Region是虚拟的一个叫做Root Region,通过Root Region可以找到下面各个实际的Region

7.              客户端通过Hbase Master Server获得了Region所在的Region Server,然后就直接和Region Server进行交互,而对于Region Server相互之间不通信,只和Hbase Master Server交互,受到Master Server的监控和管理。

后话

       HBase还没有怎么使用,仅仅只是看了wiki去了解了一下结构和作用,暂时还没有需要使用的场景,不过对于各种开源项目的设计有所了解,对自己的框架结构设计也会有很多帮助,因此分享一下。

posted @ 2008-08-08 11:37 岑文初 阅读(1350) | 评论 (0)编辑 收藏
Hadoop中的集群配置和使用技巧——分布式计算开源框架Hadoop入门实践(二)

这部分内容是分布式计算开源框架Hadoop入门实践的第二部分,讲述了关于实际使用配置的内容.第三部分是对于集群配置的测试结果分析的部分,下周三应该会在InfoQ刊登.

http://www.infoq.com/cn/articles/hadoop-config-tip

posted @ 2008-08-08 08:47 岑文初 阅读(988) | 评论 (1)编辑 收藏

2008年8月4日

分布式计算开源框架Hadoop入门实践(一)

分布式计算开源框架Hadoop入门实践(一)
第一部分已经在InfoQ.cn上刊登了第一部分

http://www.infoq.com/cn/articles/hadoop-intro

posted @ 2008-08-04 17:52 岑文初 阅读(1281) | 评论 (1)编辑 收藏

2008年6月30日

理解Load Average做好压力测试

 

SIP的第四期结束了,因为控制策略的丰富,早先的的压力测试结果已经无法反映在高并发和高压力下SIP的运行状况,因此需要重新作压力测试。跟在测试人员后面做了快一周的压力测试,压力测试的报告也正式出炉,本来也就算是告一段落,但第二天测试人员说要修改报告,由于这次作压力测试的同学是第一次作,有一个指标没有注意,因此需要修改几个测试结果。那个没有注意的指标就是load average,他和我一样开始只是注意了CPU,内存的使用状况,而没有太注意这个指标,这个指标与他们通常的限制(10左右)有差别。重新测试的结果由于这个指标被要求压低,最后的报告显然不如原来的好看。自己也没有深入过压力测试,但是觉得不搞明白对将来机器配置和扩容都会有影响,因此去问了DBASA,得到的结果相差很大,看来不得不自己去找找问题的根本所在了。

       通过下面的几个部分的了解,可以一步一步的找出Load Average在压力测试中真正的作用。

CPU时间片

       为了提高程序执行效率,大家在很多应用中都采用了多线程模式,这样可以将原来的序列化执行变为并行执行,任务的分解以及并行执行能够极大地提高程序的运行效率。但这都是代码级别的表现,而硬件是如何支持的呢?那就要靠CPU的时间片模式来说明这一切。程序的任何指令的执行往往都会要竞争CPU这个最宝贵的资源,不论你的程序分成了多少个线程去执行不同的任务,他们都必须排队等待获取这个资源来计算和处理命令。先看看单CPU的情况。下面两图描述了时间片模式和非时间片模式下的线程执行的情况:


1 非时间片线程执行情况


2 非时间片线程执行情况

       在图一中可以看到,任何线程如果都排队等待CPU资源的获取,那么所谓的多线程就没有任何实际意义。图二中的CPU Manager只是我虚拟的一个角色,由它来分配和管理CPU的使用状况,此时多线程将会在运行过程中都有机会得到CPU资源,也真正实现了在单CPU的情况下实现多线程并行处理。

       CPU的情况只是单CPU的扩展,当所有的CPU都满负荷运作的时候,就会对每一个CPU采用时间片的方式来提高效率。

       Linux的内核处理过程中,每一个进程默认会有一个固定的时间片来执行命令(默认为1/100秒),这段时间内进程被分配到CPU,然后独占使用。如果使用完,同时未到时间片的规定时间,那么就主动放弃CPU的占用,如果到时间片尚未完成工作,那么CPU的使用权也会被收回,进程将会被中断挂起等待下一个时间片。

CPU利用率和Load Average的区别

       压力测试不仅需要对业务场景的并发用户等压力参数作模拟,同时也需要在压力测试过程中随时关注机器的性能情况,来确保压力测试的有效性。当服务器长期处于一种超负荷的情况下运行,所能接收的压力并不是我们所认为的可接受的压力。就好比项目经理在给一个人估工作量的时候,每天都让这个人工作12个小时,那么所制定的项目计划就不是一个合理的计划,那个人迟早会垮掉,而影响整体的项目进度。

CPU利用率在过去常常被我们这些外行认为是判断机器是否已经到了满负荷的一个标准,看到50%-60%的使用率就认为机器就已经压到了临界了。CPU利用率,顾名思义就是对于CPU的使用状况,这是对一个时间段内CPU使用状况的统计,通过这个指标可以看出在某一个时间段内CPU被占用的情况,如果被占用时间很高,那么就需要考虑CPU是否已经处于超负荷运作,长期超负荷运作对于机器本身来说是一种损害,因此必须将CPU的利用率控制在一定的比例下,以保证机器的正常运作。

Load AverageCPULoad,它所包含的信息不是CPU的使用率状况,而是在一段时间内CPU正在处理以及等待CPU处理的进程数之和的统计信息,也就是CPU使用队列的长度的统计信息。为什么要统计这个信息,这个信息的对于压力测试的影响究竟是怎么样的,那就通过一个类比来解释CPU利用率和Load Average的区别以及对于压力测试的指导意义。

我们将CPU就类比为电话亭,每一个进程都是一个需要打电话的人。现在一共有4个电话亭(就好比我们的机器有4核),有10个人需要打电话。现在使用电话的规则是管理员会按照顺序给每一个人轮流分配1分钟的使用电话时间,如果使用者在1分钟内使用完毕,那么可以立刻将电话使用权返还给管理员,如果到了1分钟电话使用者还没有使用完毕,那么需要重新排队,等待再次分配使用。


3 电话使用场景

       上图中对于使用电话的用户又作了一次分类,1min的代表这些使用者占用电话时间小于等于1min2min表示使用者占用电话时间小于等于2min,以此类推。根据电话使用规则,1min的用户只需要得到一次分配即可完成通话,而其他两类用户需要排队两次到三次。

       电话的利用率 = sum (active use cpu time)/period

每一个分配到电话的使用者使用电话时间的总和去除以统计的时间段。这里需要注意的是是使用电话的时间总和(sum(active use cpu time)),这与占用时间的总和(sum(occupy cpu time))是有区别的。(例如一个用户得到了一分钟的使用权,在10秒钟内打了电话,然后去查询号码本花了20秒钟,再用剩下的30秒打了另一个电话,那么占用了电话1分钟,实际只是使用了40秒)

电话的Average Load体现的是在某一统计时间段内,所有使用电话的人加上等待电话分配的人一个平均统计。

电话利用率的统计能够反映的是电话被使用的情况,当电话长期处于被使用而没有的到足够的时间休息间歇,那么对于电话硬件来说是一种超负荷的运作,需要调整使用频度。而电话Average Load却从另一个角度来展现对于电话使用状态的描述,Average Load越高说明对于电话资源的竞争越激烈,电话资源比较短缺。对于资源的申请和维护其实也是需要很大的成本,所以在这种高Average Load的情况下电话资源的长期“热竞争”也是对于硬件的一种损害。

低利用率的情况下是否会有高Load Average的情况产生呢?理解占有时间和使用时间就可以知道,当分配时间片以后,是否使用完全取决于使用者,因此完全可能出现低利用率高Load Average的情况。由此来看,仅仅从CPU的使用率来判断CPU是否处于一种超负荷的工作状态还是不够的,必须结合Load Average来全局的看CPU的使用情况和申请情况。

所以回过头来再看测试部对于Load Average的要求,在我们机器为8CPU的情况下,控制在10 Load左右,也就是每一个CPU正在处理一个请求,同时还有2个在等待处理。看了看网上很多人的介绍一般来说Load简单的计算就是2* CPU个数减去1-2左右(这个只是网上看来的,未必是一个标准)。

补充几点:

1.对于CPU利用率和CPU Load Average的结果来判断性能问题。首先低CPU利用率不表明CPU不是瓶颈,竞争CPU的队列长期保持较长也是CPU超负荷的一种表现。对于应用来说可能会去花时间在I/O,Socket等方面,那么可以考虑是否后这些硬件的速度影响了整体的效率。

这里最好的样板范例就是我在测试中发现的一个现象:SIP当前在处理过程中,为了提高处理效率,将控制策略以及计数信息都放置在Memcached Cache里面,当我将Memcached Cache配置扩容一倍以后,CPU的利用率以及Load都有所下降,其实也就是在处理任务的过程中,等待Socket的返回对于CPU的竞争也产生了影响。

2.未来多CPU编程的重要性。现在服务器的CPU都是多CPU了,我们的服务器处理能力已经不再按照摩尔定律来发展。就我上面提到的电话亭场景来看,对于三种不同时间需求的用户来说,采用不同的分配顺序,我们可看到的Load Average就会有不同。假设我们统计Load的时间段为2分钟,如果将电话分配的顺序按照:1min的用户,2min的用户,3min的用户来分配,那么我们的Load Average将会最低,采用其他顺序将会有不同的结果。所以未来的多CPU编程可以更好的提高CPU的利用率,让程序跑的更快。

以上所提到的内容未必都是很准确或者正确,如果有任何的偏差也请大家指出,可以纠正一些不清楚的概念。

posted @ 2008-06-30 17:35 岑文初 阅读(1161) | 评论 (1)编辑 收藏
仅列出标题  下一页