HFile存储格式
HBase中的所有数据文件都存储在Hadoop HDFS文件系统上,主要包括两种文件类型: 1. HFile, HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile做了轻量级包装,即StoreFile底层就是HFile 2. HLog File,HBase中WAL(Write Ahead Log) 的存储格式,物理上是Hadoop的Sequence File 下面主要通过代码理解一下HFile的存储格式。 HFile 下图是HFile的存储格式: HFile由6部分组成的,其中数据KeyValue保存在Block 0 … N中,其他部分的功能有:确定Block Index的起始位置;确定某个key所在的Block位置(如block index);判断一个key是否在这个HFile中(如Meta Block保存了Bloom Filter信息)。具体代码是在HFile.java中实现的,HFile内容是按照从上到下的顺序写入的(Data Block、Meta Block、File Info、Data Block Index、Meta Block Index、Fixed File Trailer)。 KeyValue: HFile里面的每个KeyValue对就是一个简单的byte数组。但是这个byte数组里面包含了很多项,并且有固定的结构。我们来看看里面的具体结构: 开始是两个固定长度的数值,分别表示Key的长度和Value的长度。紧接着是Key,开始是固定长度的数值,表示RowKey的长度,紧接着是 RowKey,然后是固定长度的数值,表示Family的长度,然后是Family,接着是Qualifier,然后是两个固定长度的数值,表示Time Stamp和Key Type(Put/Delete)。Value部分没有这么复杂的结构,就是纯粹的二进制数据了。 Data Block:由DATABLOCKMAGIC和若干个record组成,其中record就是一个KeyValue(key length, value length, key, value),默认大小是64k,小的数据块有利于随机读操作,而大的数据块则有利于scan操作,这是因为读KeyValue的时候,HBase会将查询到的data block全部读到Lru Block Cache中去,而不是仅仅将这个record读到cache中去。 private void append(final byte [] key, final int koffset, […]
支持配额的共享线程池
用了几个小时动手实现了一个简陋支持配额的共享线程池. 基本思路与放翁相同, 区别在于引入了两种线程分配策略: 悲观策略 简单的共享一个线程池, 最容易出现的问题就是不同类型任务(或事件)在随机争抢线程资源时, 可能出现”饿死”现象(即抢不到线程). 因此, 悲观策略的宗旨是绝对的保证每种任务都会被分配到预留的(reserve)配额, 这种做法本质上和多个线程池的做法一样. 如总共100个线程, A任务可用50个线程, B任务可用30个线程, C任务可用20个, 三者互不占用, 一旦任意谁的任务实例超过配额, 将被迫等待直至先前的任务实例结束释放了线程. 统一到一个共享的池中, 好处自然是归一化管理, 容易从全局上比较不同任务的优先级, 做出合理的资源分配; 坏处可能就是需要去实现这样一个支持配额的共享线程池. 当然, 若不觉得多个线程池有什么不好, 悲观策略其实意义不大:(. 乐观策略 无论是使用悲观策略的共享线程池, 还是精心规划多个线程池, 由于都是预定义, 难免在环境变化过程中出现线程资源不足或闲置的情况. 要是可以这样, 某个时段当A任务较少时, 它所闲置的线程能协调给负载较高的B任务, 那就完美了! 故, 共享线程池的乐观策略就是在保证每种任务预留最低资源的情况下, 允许任务依据一个弹性(elastic)配额去争抢线程资源, 达到线程利用率的最大化. 如有100个线程的池, A任务大部分的时候负载较高, 则给予50个的预留配额, 30个的弹性配额; 而B任务是偶尔某个时段复杂较高, 则给予20个线程的预留配额, 30个的弹性配额, 这样留了一个30个线程的资源空间, 让AB去合理竞争. 很多实现的细节, 还请参见源代码. 源代码 CentralExecutor.java CentralExecutorTest.java
逻辑划分线程池
现在很多系统中,特别是事件驱动的系统中,对于线程池的维护很多时候根据业务处理类型的不同做划分和管理,但分开维护会带来下面两个问题: 1. 到处线程池,每个线程池都有上限设置,但是所有线程池到达上限的时候也许系统已经无法承受了,所以局部设计和限制无法达到全局限制的目标。 2. 合理的利用线程池的资源,当线程池逻辑上真实隔离后,就无法将空闲的线程资源借调给繁忙的任务处理使用。 设计中关注的: 虚拟隔离线程池需要有模型可以保证对于一些处理的保护,对于一些处理的降级。 设计思路: 简单的两种配置模式:保留,限制。 举个例子: 默认线程池大小设置为100。 A类任务设置为保留10,B类任务设置为限制50。 假设有A,B,C三种任务进入。 A最大可以使用100个线程,其中10个是它独占的(通过配置可以选择优先使用公有的还是私有的) B最大可以使用50个线程,当公有线程(100-10=90)被消耗后剩余总数小于50,那么B消耗的数量就会小于50,假如公有90个线程都没有被消耗,此时B最多也只能消耗50个线程。总结来说,B消耗公有的线程资源,同时最多只能消耗他的设置(当然他设置如果超过公有线程,则以公有线程池最大作为上限) C最大可以使用90个线程,也就是所有的公有线程。 当任何一种请求没有线程资源可以被使用的时候,将会被放入队列,等待线程可用,队列不区分任务类型。 第一版简单的Java代码参看:http://www.rayfile.com/zh-cn/files/66a89e61-4357-11e0-9ad5-0015c55db73d/ 这里只是探讨一种简单的设计思路,以最小代价来全局化管理维护线程池或者资源池。
分布式文件系统Ceph调研1 – RADOS
Ceph是加州大学Santa Cruz分校的Sage Weil(DreamHost的联合创始人)专为博士论文设计的新一代自由软件分布式文件系统。自2007年毕业之后,Sage开始全职投入到Ceph开 发之中,使其能适用于生产环境。Ceph的主要目标是设计成基于POSIX的没有单点故障的分布式文件系统,使数据能容错和无缝的复制。2010年3 月,Linus Torvalds将Ceph client合并到内 核2.6.34中。 Ceph中有很多在分布式系统领域非常新颖的技术点,对解决分布式文件系统中一些常见的问题的研究非常有指导意义。所以值得研究。 RADOS简介 1 RADOS概述 RADOS (Reliable, Autonomic Distributed Object Store) 是Ceph的核心之一,作为Ceph分布式文件系统的一个子项目,特别为Ceph的需求设计,能够在动态变化和异质结构的存储设备机群之上提供一种稳定、可扩展、高性能的单一逻辑对象(Object)存储接口和能够实现节点的自适应和自管理的存储系统。事实上,RADOS也可以单独作为一种分布式数据存储系统,给适合相应需求的分布式文件系统提供数据存储服务。 2 RADOS架构简介 RADOS系统主要由两个部分组成(如图1所示): 1.由数目可变的大规模OSDs(Object Storage Devices)组成的机群,负责存储所有的Objects数据; 2.由少量Monitors组成的强耦合、小规模机群,负责管理Cluster Map,其中Cluster Map是整个RADOS系统的关键数据结构,管理机群中的所有成员、关系、属性等信息以及数据的分发。 图1 RADOS系统架构图示 对于RADOS系统,节点组织管理和数据分发策略均有内部的Monitors全权负责,所以,从Clients角度设计相对比较简单,它给应用提供的仅为简单的存储接口。 3 RADOS详细介绍 3.1 扩展机群 1.Cluster Map 存储机群的管理,唯一的途径是Cluster Map通过对Monitor Cluster操作完成。Cluster Map是整个RADOS系统的核心数据结构,其中指定了机群中的OSDs信息和所有数据的分布情况。所有涉及到RADOS系统的Storage节点和Clients都有最新epoch的Cluster Map副本。因为Cluster Map的特殊性,Client向上提供了非常简单的接口实现将整个存储机群抽象为单一的逻辑对象存储结构。 Cluster Map的更新由OSD的状态变化或者其他事件造成数据层的变化驱动,每一次Cluster Map更新都需要将map epoch增加,map epoch使Cluster Map在所有节点上的副本都保持同步,同时,map epoch可以使一些过期的Cluster Map能够通过通信对等节点及时更新。 在大规模的分布式系统中,OSDs的failures/recoveries是常见的,所以,Cluster Map的更新就比较频繁,如果将整个Cluster Map进行分发或广播显然会造成资源的浪费,RADOS采用分发incremental map的策略避免资源浪费,其中incremental […]
MongoDB 1.8 版本发布
MongoDB 1.8.0版本发布了!最大的显著改变是增加了一个日志存储引擎,可以快速安全地恢复崩溃系统。还包括许多内部改进,极大地提高了效率。 MongoDB是一个基于分布式文件存储的数据库开源项目,由C++语言编写。旨在为WEB应用提供可护展的高性能数据存储解决方案。常用于高流量网站,在线游戏网站和搜索引擎的大规模数据管理和分类。 该版本主要新亮点: * Journaling * Sharding performance improvements * Replica set enhancements, including support for authentication * Spherical geo search * Covered and sparse indexes * B-tree index self-compaction * New map/reduce options for incremental updates * Tab completion in the shell * mongostat –discover 详细更新日志: http://jira.mongodb.org/secure/IssueNavigator.jspa?requestId=10128 下载地址: http://www.mongodb.org/downloads
Linux 2.6.38 User-space interface for Crypto API
Linux内核里面自带非常多的加密模块,这是模块经过调优性能非常高, 而且现在又很多硬件本身支持加密功能,比如intel的CPU支持AES加密指令,那些内核的那帮人知道更好如何利用这些硬件更快的完成加密功能的, 他们写的这些硬件的驱动在drivers/crypto目录里. 所以如果我们能在用户空间的应用程序中用到这些加密库有二个好处: 1. 无须再造轮子. 2. 性能高. 幸运的是2.6.38的内核给我们带来了这些功能. 这些功能是通过socket方式暴露的,思路非常独特优雅,同时由于支持gather write, scatter read, 无须拷贝数据,性能应该非常高. 具体可以参考底下材料: User-space interface for Crypto API : 这里, 这里 在ubuntu10.10下安装新的内核2.6.38, 参考这里 安装完了系统,我们可以演示下如何使用新的API调用: $ uname -r 2.6.38-yufeng $ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=10.10 DISTRIB_CODENAME=maverick DISTRIB_DESCRIPTION=”Ubuntu 10.10″ $ cat > example.c #include <stdio.h> #include <sys/socket.h> #include <linux/if_alg.h> #ifndef AF_ALG #define AF_ALG 38 #define SOL_ALG 279 #endif […]
mongodb小结
用了一阵子mongodb,作一些小结,作为将来的参考。按照以往的习惯,先作一个总览,然后再挑出一些自己比较关注的几个点,作为珠玑,加以串联阐述。 mongodb由C++写就,其名字来自humongous这个单词的中间部分,从名字可见其野心所在就是海量数据的处理。关于它的一个最简洁描述为:scalable, high-performance, open source, schema-free, document-oriented database。我对于文档型数据库有一些个人的偏好,这种偏好是从半年前研究couchdb而来的,因为我觉得用它来描述一个具有个性化特征的实体对象正合适,比如网站上的用户或商品书籍之类的条目。 一些概念: 跟mysqld一样,一个mongod服务可以有建立多个数据库,每个数据库可以有多张表,这里的表名叫collection,每个collection可以存放多个文档(document),每个文档都以BSON(binary json)的形式存放于硬盘中。跟关系型数据库不一样的地方是,它是的以单文档为单位存储的,你可以任意给一个或一批文档新增或删除字段,而不会对其它文档造成影响,这就是所谓的schema-free,这也是文档型数据库最主要的优点。跟一般的key-value数据库不一样的是,它的value中存储了结构信息,所以你又可以像关系型数据库那样对某些域进行读写、统计等操作。可以说是兼备了key-value数据库的方便高效与关系型数据库的强大功能。 索引 跟关系型数据库类似,mongodb可以对某个字段建立索引,可以建立组合索引、唯一索引,也可以删除索引。当然建立索引就意味着增加空间开销,我的建议是,如果你能把一个文档作为一个对象的来考虑,在线上应用中,你通常只要对对象ID建立一个索引即可,根据ID取出对象某些数据放在memcache即可。如果是后台的分析需要,响应要求不高,查询非索引的字段即便直接扫表也费不了太多时间。如果还受不了,就再建一个索引得了。 默认情况下每个表都会有一个唯一索引:_id,如果插入数据时没有指定_id,服务会自动生成一个_id,为了充分利用已有索引,减少空间开销,最好是自己指定一个unique的key为_id,通常用对象的ID比较合适,比如商品的ID。 capped collection capped collection是一种特殊的表,它的建表命令为: db.createCollection(“mycoll”, {capped:true, size:100000}) 允许在建表之初就指定一定的空间大小,接下来的插入操作会不断地按顺序APPEND数据在这个预分配好空间的文件中,如果已经超出空间大小,则回到文件头覆盖原来的数据继续插入。这种结构保证了插入和查询的高效性,它不允许删除单个记录,更新的也有限制:不能超过原有记录的大小。这种表效率很高,它适用于一些暂时保存数据的场合,比如网站中登录用户的session信息,又比如一些程序的监控日志,都是属于过了一定的时间就可以被覆盖的数据。 复制与分片 mongodb的复制架构跟mysql也很类似,除了包括master-slave构型和master-master构型之外,还有一个Replica pairs构型,这种构型在平常可以像master-slave那样工作,一但master出现问题,应用会自动了连接slave。要做复制也很简单,我自己使用过master-slave构型,只要在某一个服务启动时加上–master参数,而另一个服务加上–slave与–source参数,即可实现同步。 分片是个很头疼的问题,数据量大了肯定要分片,mysql下的分片正是成为无数DBA的噩梦。在mongodb下,文档数据库类似key-value数据库那样的易分布特性就显现出来了,无论构造分片服务,新增节点还是删除节点都非常容易实现。但mongodb在这方面做还不足够成熟,现在分片的工作还只做到alpha2版本(mongodb v1.1),估计还有很多问题要解决,所以只能期待,就不多说了。 性能 在我的使用场合下,千万级别的文档对象,近10G的数据,对有索引的ID的查询不会比mysql慢,而对非索引字段的查询,则是全面胜出。mysql实际无法胜任大数据量下任意字段的查询,而mongodb的查询性能实在让我惊讶。写入性能同样很令人满意,同样写入百万级别的数据,mongodb比我以前试用过的couchdb要快得多,基本10分钟以下可以解决。补上一句,观察过程中mongodb都远算不上是CPU杀手。 GridFS gridfs是mongodb一个很有趣的类似文件系统的东西,它可以用一大块文件空间来存放大量的小文件,这个对于存储web2.0网站中常见的大量小文件(如大量的用户头像)特别有效。使用起来也很方便,基本上跟一般的文件系统类似。 用合适的数据库做适合的事情 mongodb的文档里提到的user case包括实时分析、logging、全文搜索,国内也有人使用mongodb来存储分析网站日志,但我认为mongodb用来处理有一定规模的网站日志其实并不合适,最主要的就是它占空间过于虚高,原来1G的日志数据它可以存成几个G,如此下去,一个硬盘也存不了几天的日志。另一方面,数据量大了肯定要考虑sharding,而mongodb的sharding到现在为止仍不太成熟。由于日志的不可更新性的,往往只需APPEND即可,又因为对日志的操作往往只集中于一两列,所以最合适作为日志分析的还是列存储型的数据库,特别是像infobright那样的为数据仓库而设计的列存储数据库。 由于mongodb不支持事务操作,所以事务要求严格的系统(如果银行系统)肯定不能用它。 mongodb占用空间过大的原因,在官方的FAQ中,提到有如下几个方面: 1、空间的预分配:为避免形成过多的硬盘碎片,mongodb每次空间不足时都会申请生成一大块的硬盘空间,而且申请的量从64M、128M、256M那样的指数递增,直到2G为单个文件的最大体积。随着数据量的增加,你可以在其数据目录里看到这些整块生成容量不断递增的文件。 2、字段名所占用的空间:为了保持每个记录内的结构信息用于查询,mongodb需要把每个字段的key-value都以BSON的形式存储,如果value域相对于key域并不大,比如存放数值型的数据,则数据的overhead是最大的。一种减少空间占用的方法是把字段名尽量取短一些,这样占用空间就小了,但这就要求在易读性与空间占用上作为权衡了。我曾建议作者把字段名作个index,每个字段名用一个字节表示,这样就不用担心字段名取多长了。但作者的担忧也不无道理,这种索引方式需要每次查询得到结果后把索引值跟原值作一个替换,再发送到客户端,这个替换也是挺耗费时间的。现在的实现算是拿空间来换取时间吧。 3、删除记录不释放空间:这很容易理解,为避免记录删除后的数据的大规模挪动,原记录空间不删除,只标记“已删除”即可,以后还可以重复利用。 4、可以定期运行db.repairDatabase()来整理记录,但这个过程会比较缓慢。 因为官方文档中对各方面的内容已经有很详细的叙述,所以我并没有再过多的引用原文与代码,只是结合自己的使用归纳一些心得,有兴趣的朋友不妨直接去翻文档中自己感兴趣的问题,超群的博客上有一个很好的入门介绍。 最后总结一句,文档型数据库有点像波粒二象性,总能在适当的时候表现出它作为关系型数据库或key-value数据库的优势来。 实战案例: 昨天我访问mongodb的python程序开始出错,经常抛出AssertionError异常,经查证只是master查询异常,slave正常,可判断为master的数据出了问题。 修复过程: 1、在master做db.repairDatabase(),不起作用; 2、停止slave的同步; 3、对slave作mongodump,备份数据; 4、对master作mongostore,把备份数据恢复,使用–drop参数可以先把原表删除。 5、恢复slave的同步。
To solve the problem between JAXB2.1 and JDK1.6/6.0
Scenario 1 1.8. Using JAX-WS 2.1 with JavaSE6 JavaSE6 ships with JAX-WS 2.0 API in rt.jar, which causes some trouble when you try to run applications that use JAX-WS 2.1 API. This document collects information about how to solve this issue. 1.8.1. Endorsed directory One way to fix this is to copy jaxws-api.jar and jaxb-api.jar […]
Oracle分页查询语句比较 rownum 与 between
这篇文章通过例子说明分页查询使用的NESTED LOOP操作,在分页查询翻到最后几页时的性能问题: SQL> CREATE TABLE T AS SELECT * FROM DBA_USERS; 表已创建。 SQL> CREATE TABLE T1 AS SELECT * FROM DBA_SOURCE; 表已创建。 SQL> ALTER TABLE T ADD CONSTRAINT PK_T PRIMARY KEY (USERNAME); 表已更改。 SQL> ALTER TABLE T1 ADD CONSTRAINT FK_T1_OWNER FOREIGN KEY (OWNER) 2 REFERENCES T(USERNAME); 表已更改。 SQL> CREATE INDEX IND_T1_OWNER ON T1(NAME); 索引已创建。 SQL> […]
在CentOS 5.4上安装CouchDB
CouchDB一种半结构化面向文档的分布式,高容错的数据库系统,具体的可以参见其网站上的文档,以及这里的一篇技术简介的翻译。CouchDB在Ubuntu下安装非常方便,只需要使用sudo apt-get install couchdb即可,我以为在CentOS中也会比较容易,没想到却遇到了比较多的问题。主要包括: CentOS的安装源里不包含CouchDB CouchDB需要Erlang的运行时支持,CentOS的安装源里也没有Erlang OK,我们一步一步来搞定在CentOS下安装CouchDB。首先需要安装Erlang,却Erlang的官方网站下载源码,然后在本地编译安装:具体的脚本为: 1: wget http://www.erlang.org/download/otp_src_R13B02-1.tar.gz 2: tar–xzvf otp_src_R13B02-1.tar.gz 3: cd otp_src_R13B02-1 4: ./configure 5: make && make install 中途有可能会遇到一些依赖的问题,比如缺少icu、ncurses、wxWindows等,前面几个大略都可以从yum时行安装,wxWindows可以不问,如果你之后不准备使用Erlang进行UI编程的话,这些也足够用了。 Erlang安装完成之后,测试一下在bash里erl和erlc能否使用,若能,则这一步就完成了。 接着是安装CouchDB,由于CouchDB里用到了JavaScript,所以其依赖于SpiderMonkey,需要先安装libmozjs这个库,步骤为: 1: wget ftp://ftp.mozilla.org/pub/mozilla.org/js/js-1.8.0-rc1.tar.gz 2: tar–xzvf js-1.8.0-rc1.tar.gz 3: cd js/src 4: make BUILD_OPT=1–f Makefile.ref 编译应该不会出什么问题,如果你的机器没有配置编译环境,你可以参考这篇文章进行配置。 可以当我执行make –f Makefile.ref install的时候傻了,没有这个target,好吧,我们自己写脚本安装这个库。代码如下: 1: #!/bin/bash 2: mkdir -p /usr/include/mozjs/ -v 3: cp *.{h,tbl} 4: […]