OneCoder


  • 首页

  • 归档

  • 标签

  • 关于

  • 搜索

HBase“扫描器”scanner使用和优化

发表于 2013-04-03

HBase在扫描数据的时候,使用scanner表扫描器。HTable通过一个Scan实例,调用getScanner(scan)来获取扫描器。可以配置扫描起止位,以及其他的过滤条件。通过迭代器返回查询结果,使用起来虽然不是很方便,不过并不复杂。但是这里有一点可能被忽略的地方,就是返回的scanner迭代器,每次调用next的获取下一条记录的时候,默认配置下会访问一次RegionServer。这在网络不是很好的情况下,对性能的影响是很大的。测试中,未配置前,一个业务的消耗时间为:

Cost time: 159941

通过:

scan.setCaching(10000);

指定一次取出10000条记录后,该业务的消耗时间为:

Cost time: 64845

因为该 业务访问数据次数很多,所以效果很明显。

也有说可通过修改配置项hbase.client.scanner.caching的值,来使该配置生效。不过,OneCoder这里在hbase-site.xml中增加了该配置却没有生效。

阅读全文 »

《HighPerformance MySQL》概译 隔离等级

发表于 2013-04-02

隔离等级

隔离其实比它看起来复杂。SQL标准定义了四种隔离级别,决定了数据变化在事务内外可见或不可见。低级别的隔离等级会有更好的并发支持和更低的资源消耗。

     每种存储引擎都有其独特的隔离等级实现方式。你应该从你使用的存储引擎的手册中获取更详细的信息。

下面让我们来看下四种隔离等级:

未提交读(READ UNCOMMITED)

允许事物读取未提交的事物的结果。也就是允许脏读。这个级别在实际环境中很少使用,因为它可能会带来很多问题,并且性能比其他级别并没有好多少。未提交读,也被称为脏读。

提交读(READ COMMITED)

大多数数据库的默认隔离级别(但不是MySQL的!)它满足之前提到的隔离定义:事物仅可以看到其它事务已经提交的数据。它自身的数据也只有在提交后才能被读到。也被成为不重复读(nonrepeatable read)。意味着,你运行同一个查询两次,可能读到不同的数据。

重复读(REPEATABLE READ)

解决了不提交读的问题。事务读取到的行在同一事务内部其他查询读取的时候都是一样的。不过,这也带来其他问题:幻象读。(phantom reads)。当你正在读取一些行的时候,另外的事务插入了数据,你再次读取的时候,会读到新插入的行。就好像“幻象”行一样。InnoDB和XtraDB通过多版本并发管理解决了幻象读的问题,后续我们会介绍。

重复读是MySQL事务的默认隔离级别。

串行读(SERIALIZABLE)

最高级别的隔离。串行读强制要求事务顺序执行,从而避免了冲突解决上述问题。从内部来看,串行读给每个读取的行加了锁。在该级别下,会发生很多的超时和锁竞争。很少见到有人使用该级别,不过这取决与你的业务需求是否苛刻。

下表列出不同隔离级别的概要和缺点

Table 1-1. ANSI SQL 隔离级别

隔离级别

是否允许脏读

是否允许不重复读

是否允许幻象读

读锁

未提交读

是

是

是

否

提交读

否

是

是

否

重复读

否

否

是

否

串行读

否

否

否

是

 

阅读全文 »

《HighPerformance MySQL》概译 事务

发表于 2013-04-01

事务

事务是一组被看做一个整体的SQL请求。该组SQL被看成是原子的。如果所有的SQL都正常执行则数据确认请求,如果其中的任何一个失效,则所有的SQL都不生效。也就是说要么全成功,要么全失效。

本节并不是针对MySQL的,如果你已经事务的ACID特性了解,那么可以直接了解MySQL的事务特性。

银行系统是一个典型的需要事务特性的例子。假设系统有两张表支票账户和储蓄表。从Jane的支票账户转义200美元到她的储蓄账户需要至少三步:

1、校验支票账户有超过200的可用额。
2、从支票账户划掉200
3、给储蓄账户增加200

所有操作需要封装到一个事务中,一旦其中一个步骤失败,整个操作可以回滚。

用START TRANSACTION开启事务。用COMMIT提交事务,或者用ROLLBACK回滚事务。因此,整个SQL形如:

START TRANSACTION;
SELECT balance FROM checking WHERE customer_id = 10233276;
UPDATE checking SET balance = balance - 200.00 WHERE customer_id = 10233276;
UPDATE savings SET balance = balance + 200.00 WHERE customer_id = 10233276;
COMMIT;

不过事务不是全部,试想一下,如果在执行第四行的时候数据崩溃了会怎样。很可能用户丢失了200元。

事务不是保证正确性的全部,系统必须满足ACID特性。ACID是指:原子性、一致性、隔离性、持久性。

原子性:事务必须作为一个不可分割的整体。整个事务全部生效或者回滚。不存在部分执行的事务。

一致性:
数据库必须从一个一致性状态变为另一个。在我们例子中,一致性保证了发生在第三和第四行之间的数据库损坏不会造成账户中200元的丢失。因为,在事务提交前,事务中任何的修改都不会反应在数据库中。

隔离性:一个事务的结果对另外的事务通常是不可见的,直到该事务完成。这保证了银行的账户汇总程序运行在第三行和第四行之间的时候,仍然可以看到支票账户中的200元。当我们讨论隔离性的时候,你将会明白我们所说的"通常不可见"的含义。

持久性:
一旦提交了事务,那么数据将会永久的改变。这意味着数据必须持久化起来,并且不会因为数据库的崩溃而丢失。持久性是一个有些模糊的概念,分很多等级。某些持久化的策略比其他的更有安全性保证,不过没有100%的安全。

ACID事务保证了银行系统不会弄丢你的钱。这在我们应用的逻辑中很难也几乎不可能保证的。一个满足ACID规则的数据库必须做很多复杂的工作以提供ACID特性。

跟提高锁的精确范围一样,更高的安全的的负面影响就是数据库要做更多的工作。提供ACID特性的数据库需要更多的CPU、内存利用率和磁盘空间。这是MySQL存储引擎架构提供的特性。你可以决定你的应用是否需要事务。如果你不需要,你可以选择性能更高的无事务的存储引擎。你可以选择锁表的策略在无事务的情况下提供你想要的保护。这都取决于你。

阅读全文 »

《HighPerformance MySQL》概译 锁的粒度

发表于 2013-03-30

一种提高共享资源并发效率的方式是合理的规划锁的范围。仅仅锁住你要修改的部分当然比全表锁住要好。所以,我们尽可能的最小化锁的范围,因为不相干的部分,本身也互不干扰。

不过,也要考虑到,锁是消耗资源的。每种锁的操作都有消耗,例如:获得锁,检查锁是否可用,释放锁等。如果系统花了过多的资源在锁的操作上,那么并发的性能就会受到影响。

锁的策略就是在锁的消耗和数据安全之间寻求一种平衡,这种平衡会影响到性能。大部分商业数据库没有给你选择的机会,一般都采用人们所熟知的行锁,并通过内部一系列复杂的机制保持效率。

MySQL给了你选择的权力。它的存储引擎可以选择自己锁策略和粒度。因此,锁的设计对于存储引擎的实现来说是非常重要的。不同的存储引擎,可以根据不同应用场景设计出特定的高效的锁策略。下面,我们来看下两种熟知的锁策略。

表锁

MySQL中最基本的锁策略,也是消耗最低的锁。表锁跟之前提到的邮箱的锁类似,它锁住整张表。当客户端想要写表(insert,delete,updata)的时候,它获得写锁。此时所有其他的读写操作都被阻止。当没有人写的时候,读操作可以获得锁,并且不和其他的读锁互斥。

表锁针对特定的场景有很多变种,以提供更好的性能。比如,READ LOCAL 表锁,允许一些类型并发写操作。写锁比读锁有更高的优先级。也就是说,即使读请求早于写请求排在队列中,写请求也可以有先获得锁。

尽管存储引擎本身可以管理锁。MySQL自身也拥有很多表级的锁用于一些特定的场合。比如,对于ALTER Table操作,MySQL就用了表级锁,而不管你选择了何种存储引擎。

行锁

这种锁的类型提供了最好的并发效率同时也消耗最多的资源。行级锁在InnoDB和XtraDB存储引擎中提供。行级锁在存储引擎层而不是服务器实现。服务层完全不关心存储引擎层锁的实现方式,在本章后面的部分以及本书中,都将看到各种存储引擎有其自己的锁的实现方式。

阅读全文 »

HBase 利用Coprocessor实现聚合函数

发表于 2013-03-29

HBase默认不支持聚合函数(sum,avg等)。可利用HBase的coprocessor特性实现。这样做的好处是利用regionserver在服务端进行运算。效率高,避免客户端取回大量数据,占用网络带宽,消耗大量内存等。

实现方式:

利用HBase提供的endPoint类型的AggregateImplementation Coprocess,配合AggregationClient访问客户端实现RegionServer端的集合计算。AggregationClient访问代码如下:

aggregationClient.avg(Bytes. toBytes("TableName"), ci, scan);

scan即为要计算列的查询条件。这里有一个ColumnInterperter类型的参数ci。即列解释器,用于解析列中的值。HBase默认提供了LongColumnInterpreter。而我要处理的值是double类型的,所以先实现了一个DoubleColumnInterpreter。(从JIRA上看Doulbe类型的解释器好像正在开发中)。ColumnInterpreter接口的实现会在AggregateImplementation

/**
* Double类型的列解释器实现
*
 * @author OneCoder
*/
public class DoubleColumnInterpreter implements
           ColumnInterpreter<Double, Double> {

     @Override
     public void write(DataOutput out) throws IOException {


     }

     @Override
     public void readFields(DataInput in) throws IOException {


     }

     @Override
     public Double getValue( byte[] colFamily, byte[] colQualifier, KeyValue kv)
                 throws IOException {
            if (kv == null)
                 return null;
            // 临时解决方案,如果采用Bytes.toDouble(kv.getValue())会报错,偏移量大于总长度。
            // toDouble(getBuffer(), getValueOffset),偏移量也不对。
            return Double. valueOf(new String(kv.getValue()));
     }


     @Override
     public Double add(Double l1, Double l2) {
            if (l1 == null ^ l2 == null) {
                 return l1 == null ? l2 : l1;
           } else if (l1 == null) {
                 return null;
           }
            return l1 + l2;
     }

     @Override
     public Double getMaxValue() {
            // TODO Auto-generated method stub
            return null;
     }


     @Override
     public Double getMinValue() {
            // TODO Auto-generated method stub
            return null;
     }

     @Override
     public Double multiply(Double o1, Double o2) {
            if (o1 == null ^ o2 == null) {
                 return o1 == null ? o2 : o1;
           } else if (o1 == null) {
                 return null;
           }
            return o1 * o2;
     }


     @Override
     public Double increment(Double o) {
            // TODO Auto-generated method stub
            return null;
     }

     @Override
     public Double castToReturnType(Double o) {
            return o.doubleValue();
     }


     @Override
     public int compare(Double l1, Double l2) {
            if (l1 == null ^ l2 == null) {
                 return l1 == null ? -1 : 1; // either of one is null.
           } else if (l1 == null)
                 return 0; // both are null
            return l1.compareTo(l2); // natural ordering.
     }


     @Override
     public double divideForAvg(Double o, Long l) {
            return (o == null || l == null) ? Double. NaN : (o.doubleValue() / l
                     .doubleValue());
     }
}

导出jar包上传到HBase Region节点的lib下。然后配置RegionServer的Coprocessor。在服务端hbase-site.xml中,增加

<property>
            <name >hbase.coprocessor.region.classes </name >
           <value >org.apache.hadoop.hbase.coprocessor.AggregateImplementation </value >
 </property >    

重启服务,使配置和jar生效。然后调用AggregationClient中提供的avg, max等聚合函数,即可在region端计算出结果,返回。

阅读全文 »

《High Performance MySQL》概译 读/写锁

发表于 2013-03-28

今天在微博看到消息该书的中文版已经翻译完成即将发售,所以OneCoder不再进行全文翻译,只会以类似读书笔记的方式记录文章大意和自己的理解。每天阅读的不会太多,因为只是休息的时候阅读,学习的重心最近在Hadoop上。

读写锁


多个用户同时读取邮件的时候不会有什么问题,以为没有人去修改文件。但是在有人正在的读的时候删除邮件就会产生问题。所以,出于安全考虑,读也应该特别关注。

这里的邮箱其实就跟数据库中的表类似。每个邮件就是一行数据。修改数据库中的行数据,就相当于修改邮箱中某个邮件的信息。

解决这个问题思路很简单,就是加锁。读写操作就实现了锁系统。有两种锁,共享锁和排它锁,或者叫做读锁和写锁。

不关心锁的技术细节,我们这样描述锁的原理。读锁是共享的或者说互助不堵塞的。客户端之间可以共同读取资源。写锁是排他的,同一时间只有获得锁的客户端可以操作,其他读、写请求均被堵塞。因为只有这样才是安全的。

在数据库系统中,锁随处可见。MySQL也必须避免在有人读取数据的时候,数据被他人修改。其内部实现了锁系统,并且对外部是透明的。

阅读全文 »

《High Performance MySQL》翻译(3) 第一章 并发控制

发表于 2013-03-27


并发控制

任何时刻当不止一个请求想要同时修改数据时候就产生了并发控制问题。从本章我们的观点来看,MySQL需要在两层关注这个问题:服务层和存储引擎层。并发控制是一个大话题,有很多相关的理论文献发表。所以,我们仅简介一下MySQL处理并发读写的方式。你将在本章的接下来的部分看到相关信息。

我们以Unix系统上的电子邮箱为例。传统的邮箱文件格式非常简单。邮箱中的所有信息是一个接一个的连接在一起的。因此读取和解析邮件信息都非常简单。邮件发送也非常简单:仅仅是在文件结尾加上新的信息。

但是当两个进程同时给同一个邮箱发送邮件的时候将会发生什么?很显然这回损坏邮箱,在邮箱文件结尾产生两个交错的信息。好的邮件收发系统采用锁的方式避免这种损坏。当一个客户端在邮箱锁住的时候试图发送信息,则它必须等待直到它获取锁。

这种结构在实践的时候运行良好,但是却没有提供任何并发的支持。因为同一时刻只有一个进程可以修改邮箱,在大规模邮箱的情况下这会带来问题。

阅读全文 »

《High Performance MySQL》翻译(2) 连接管理和安全 优化和执行

发表于 2013-03-26

接上篇,第一章 MySQL架构和历史

连接管理和安全


每个客户连接在服务内部都有一个独立的线程处理。查询在这个单独的线程内运行,线程轮流在CPU或核心上运行。线程在服务端被缓存,所以不必针对每个新来线程进行创建和销毁。(注2)。
当客户端(应用)连接到MySQL服务的时候,服务端需要进行认证。认证是基于用户名,来访主机和密码的。X.509认证也可用于通过SSL(安全套接层)进行的连接。当客户端已经连接的时候,服务端会对每个请求校验该客户端是否具有操作权限。(例如:校验该客户端是否具有在wolrd数据库的Country表执行SELECT操作的权限。)

优化和执行

MySQL解析查询请求,生成内部结构(解析树),然后执行多种优化。包括重写查询,决定读取表的顺序,选择要使用的索引等等。你可以在查询中通过特殊的关键字给优化器指示,以引导其决定操作步骤。你也可以向服务端询问各种优化的方向。这会让你知道服务端进行了如何的决策,这对你重构查询和表结构以及优化设定以使服务高效运行给出了可参考的点。我们将在第六章讨论优化的细节。

优化器并不真正关心表所使用的存储引擎,但是存储引擎影响服务端对查询的优化方式。优化器向存储引擎询问其某些功能特性以及特定操作的耗时和表数据的统计。例如,一些存储引擎支持索引,可以有效支持的查询。你可以在第四和第五章了解到更多关于索引和表结构优化的信息。

在解析查询之前,服务端先检查查询缓存,查询缓存仅保存SELECT语句及其结果。如果某个查询请求与缓存中某条信息一致,那么服务端无需在解析,优化或者执行查询,它可以直接返回存储结果。我们将在第七章进行详细的说明。


注2:MySQL5.5以后的版本支持线程池插件,一个小型的线程池可以提供很多连接。 

阅读全文 »

High Performance MySQL 翻译 第一章 MySQL架构和历史 - 逻辑架构

发表于 2013-03-25

《High Performance MySQL》是OneCoder正在阅读的书,利用茶余饭后时间进行的阅读和翻译,日积月累。

MySQL与其他数据库服务有很大的不同,它的架构特性使得它在广泛领域内成为一种实用而“廉价”的选择。MySQL并不是完美的,但是他足够灵活以适应特定的需求环境,如网络应用。同时,MySQL也可以支持嵌入式应用,数据仓库,内容索引和软件分发,高可用系统,联机事务处理等等。

为了充分的利用MySQL,你需要理解其设计,从而利用而不是抗拒它。MySQL在很多方面是灵活的。例如,它支持的硬件范围很广,你可以在各种硬件环境下配置和运行它,并且,它支持多种数据类型。然而,MySQL最不寻常和重要的特性是它的存储引擎,它在设计上将查询进程和其他服务任务与数据存储和检索分离。这种分离的特性让你可以据需选择数据的存储方式以及想要怎样的性能,特性和其他特征。

本章概要介绍MySQL的架构,存储引擎的主要区别及其重要性。最后将介绍一些历史背景和基准数据。我们视图通过简化细节和展示样例的方式介绍了MySQL。这个讨论对于数据库新手和其他数据库的专家都非常有帮助。

MySQL 逻辑架构

一个好的展现MySQL各个组件如何协同工作的图会帮助你更好的理解MySQL。图1-1展示了MySQL的逻辑架构。

图1-1

最上层是业务层,不局限于MySQL。他们大多是基于网络的客服端/服务端工具或者服务,需要进行连接管理,权限认证,安全等等。

第二层开始变得“有趣”。MySQL大部分的“大脑”都在这层,包括查询解析代码,分析,优化,缓存以及所有内嵌函数(如,dates, times, math 和 encryption)。提供的所有访问存储引擎的函数都在该层,例如:存储过程, 触发器和视图。

第三层包括存储引擎。他们负责存储和检索存储在MySQL中的所有数据。就跟GNU/Linue的各种可用的文件系统一样,不同存储引擎也有其优缺点。服务端通过存储引擎接口(API)与其通信。该API屏蔽了不同存储引擎的区别,使他们对查询层是透明的。该API包含了大量的底层函数,执行诸如"开始一个事务"或者"查询包含该主键的行"等操作。存储引擎不解析SQL(注1)或者与彼此通信;他们只负责响应来自服务端的请求。

注1:一个例外是在InnoDB引擎解析外键定义,因为MySQL服务本身并没有实现该功能。

阅读全文 »

Gradle初试

发表于 2013-03-19

Gradle是什么就不多说了,跟Maven是同类型的工具。Spring和Hibernate都早已经迁移了过来。官网地址:http://www.gradle.org。最新稳定版为1.4

Gradle Eclipse Plugin是spring的sts支持的。安装之:

Installing Gradle Tooling from update site
Alternatively you can install from update sites. The following update sites are available:

   * http://dist.springsource.com/snapshot/TOOLS/nightly/gradle (latest development snapshot)
   * http://dist.springsource.com/milestone/TOOLS/gradle (latest milestone build.)
   * http://dist.springsource.com/release/TOOLS/gradle (latest release)

Gradle的配置文件脚本是groovy语法的,Eclipse插件也安装之

http://dist.springsource.org/release/GRECLIPSE/e4.2/

将工程转换为Gradle工程。

然后编辑,配置文件即可。Gradle吸引人的地方就是文档相当的完善,对于一般使用者,最常用的就是依赖管理功能,文档地址:http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html

根据文档,先配置Gradle环境,

PATH=D:\Develop Software\gradle-1.4\bin

这里是为了能够在命令行中使用gradle。对于Eclipse 插件来说,其默认下载是使用的是1.2版本,如果强制指定我们下载的1.4版本,在某些操作的时候会报错。

可编辑gradle.bat(.sh)文件,设置JVM参数。

我们就在Eclipse中尝试gradle,通过configure->convert to gradle project,将工程变为Gradle管理的工程。

然后编写build.gradle配置文件。

 

apply plugin: 'java'
group='onecoder'
version='1.0'
repositories {
mavenCentral()
mavenRepo url: "https://oss.sonatype.org/content/repositories/opensymphony-releases"
mavenRepo url: "http://dev.anyframejava.org/maven/repo"
}
sourceSets {
main
}
dependencies {
compile "io.netty:netty:3.6.3.Final"
compile "ch.qos.logback:logback-core:1.0.7"
compile "org.slf4j:slf4j-api:1.7.3"
compile "javax.mail:mail:1.4.4"
compile "org.apache.httpcomponents:httpclient:4.2.2"
compile "org.hyperic:sigar:1.6.4"
compile "net.sourceforge.groboutils:groboutils-core:5"
}


然后fresh all一下,即可自动下载依赖了。相对pom.xml来说,配置文件看起来确实清晰简单多了。这里有很多配置,OneCoder还没有弄清楚,这里只是简单的试用,并且把个人联系的工程迁移了过来。细节问题,留待以后使用中慢慢研究吧。
 

阅读全文 »
1 … 24 25 26 … 36
LiHongZhe

LiHongZhe

onecoder's blog.

352 日志
8 分类
RSS
Creative Commons
Links
  • 酷壳
  • 煮酒品茶
  • 小弟子的网络之路
  • 图表秀-在线图表制作
© 2012 - 2022 LiHongZhe
由 Jekyll 强力驱动
主题 - NexT.Muse
本站访客数 人次 本站总访问量 次