• [技术干货] 每日分享: HBase 2.0 中的 In-Memory Compaction
    原文地址 https://bbs.huaweicloud.com/blogs/175483 使用HBase的现代产品对其读写性能的期望值不断提高。理想情况下,HBase应用程序希望在不放弃可靠的持久存储保证的情况下享受内存数据库的速度。我们在HBase 2.0中引入了一种名为Accordion的新算法,它朝着这个目标迈出了重要的一步。    HBase将数据划分为由RegionServer群集控制的region。 RegionServer的纵向可伸缩性对于最终用户的性能以及整个系统的利用率至关重要。通过更好地使用RAM,accordion提高了RegionServer的可伸缩性。它可以在内存中容纳更多数据,并减少写入磁盘的频率。这样带来多个好处。首先,降低了HBase的磁盘占用率和写入放大率。其次,更多的读写操作落到RAM,更少的操作落到磁盘I/O,换句话说,HBase的性能得以提高。传统上,这些指标被认为是不一致的,并且需要彼此进行权衡。使用accordion,它们会同时得到改善。    accordion的灵感来自于HBase的内部存储结构Log-Structured-Merge(LSM)树。 HBase region被存储为一系列可搜索键值映射。最顶部是一个可变的内存存储,称为MemStore,它保存最近的写入(put)操作。其余的是不可变的HDFS文件,称为HFiles。 MemStore溢出后,被刷新到磁盘,创建一个新的HFile。 HBase采用了多版本并发控制,即MemStore将数据变化存储为单独的版本。因此,一个key的多个版本可以在MemStore和多个HFile中。读取(get)操作通过key检索值,该操作扫描BlockCache中的HFile数据,以查找最新版本。为了减少磁盘访问次数,多个HFiles在后台被合并。此过程称为压缩(compaction),将删除冗余的cell并创建更大的文件。    accordion将LSM原理重新应用于MemStore,以消除数据仍在RAM中时的冗余和其他开销。这样做可以减少刷新到HDFS的频率,从而减少写放大和整个磁盘占用空间。由于MemStore溢出而产生的刷新减少,因而写操作停顿的频率降低,最后提高了写性能。磁盘上较少的数据还意味着对块缓存的压力较小,命中率较高,并最终改善了读取响应时间。最后,较少的磁盘写入也意味着在后台发生较少的压缩,即,从生产(读取和写入)工作中窃取了较少的周期。总而言之,可以将内存压缩的效果设想为一种催化剂,使整个系统运行起来更快。    accordion目前提供两种级别的内存压缩basic和eager。前者适用于所有数据更新模式的通用优化。后者对于数据流失率较高的应用程序(如生产者-消费者队列,购物车,共享计数器等)最有用。所有这些用例均具有频繁更新相同key的功能,这些key会生成多个冗余版本,算法可利用这些冗余版本提供更多价值。另一方面,eager优化可能会导致计算开销(更多的内存副本和垃圾回收),这可能会影响密集写入负载下的响应时间。如果MemStore使用on-heap的 MemStore-Local Allocation Buffer (MSLAB),则开销很高。建议不要将这种配置与eager压缩相结合。    在下一部分中,将了解有关Accordion压缩算法的更多详细信息。如何使用    in-memory compaction可以全局配置,也可以按column family配置。 支持的级别为none(旧版实现),basic,eager。    默认情况下,所有表都应用basic in-memory compaction。 可以在hbase-site.xml中覆盖此全局配置,如下所示:<property>     <name>hbase.hregion.compacting.memstore.type</name>     <value><none | basic | eager></value> </property>    也可以在HBase Shell中按column family配置级别,如下所示:create ‘<tablename>’,  {NAME => ‘<cfname>’, IN_MEMORY_COMPACTION => ‘<NONE|BASIC|EAGER>’}性能提升    我们通过流行的Yahoo Cloud Service Benchmark(YCSB)对HBase进行了广泛的压力测试。我们的实验使用了100-200 GB的数据集,并行使了各种代表性的工作负载。结果表明,Accordion可带来显着的性能提升。    Heavy-tailed (Zipf) 分布。第一个实验执行了一个工作负载,其中key使用Zipf分布,遵循大多数现实场景。在这种情况下,当100%为写时,Accordion最多可将写入放大率降低30%,将写入吞吐量提高20%,并将GC降低22%。50%为读时,读延迟减少了12%。    Uniform 分布。第二个实验执行了另一个工作负载,其中所有key都同样热度的。在这种情况下,100%为写时,Accordion可将写入放大率降低多达25%,将写入吞吐量提高50%,并将GC降低36%。读延迟不受影响(这是意料之中的,因为完全缺乏局部性)Accordion是如何工作    高层设计。Accordion引入了CompactingMemStore一种内部应用压缩的MemStore实现。与默认的MemStore相比,后者将所有数据保持在一个整体的数据结构中,而Accordion将其作为一系列段进行管理。最年轻的部分称为活动部分,是可变的。它接受put操作。发生溢出时(默认情况下,为32MB-MemStore大小的25%),活动段将移动到内存管道中,并且变得不可变。我们称其为内存flush。 Get操作将扫描这些段和HFile(与HBase一样,可通过block cache访问后者)。    CompactingMemStore可能会不时在后台合并多个不可变的段,从而创建更大和更精简的段。因此,管道类似于“accordion bellows”(手风琴风箱),是“呼吸”(膨胀和收缩)的。    当RegionServer决定将一个或多个MemStore刷新到磁盘上以释放内存时,将会使用CompactingMemStore。这样做的理由是延长有效管理内存的MemStore的寿命,以减少总体I/O。当发生此类刷新时,所有管道段均移至复合snapshot,合并并流式传输到新的HFile。    段结构。 与默认的MemStore相似,CompactingMemStore在cell存储的顶部维护一个索引,以允许通过key快速搜索。 传统上,此索引被实现为Java跳表(ConcurrentSkipListMap)-动态但浪费的数据结构,用于管理许多小对象。 CompactingMemStore对不可变的段索引使用节省空间的扁平布局。 此通用优化可帮助所有压缩策略减少RAM开销,即使数据几乎没有冗余也是如此。 将段添加到管道后,索引被序列化为名为CellArrayMap的排序数组,该数组可以进行快速二分搜索。    CellArrayMap支持直接从Java堆分配cell,也支持从MSLAB的定制分配(堆上或堆外)。 通过从索引中引用的KeyValue对象可以抽象出实现上的差异。 CellArrayMap本身总是在堆上分配。    压缩算法。in-memory compaction 算法在流水线段的顶部维护单个扁平索引。这样可以节省空间,尤其是在数据项较小的情况下,因此可以更快的完成落盘操作。单个索引允许在一个位置进行搜索,因此控制住了读取延迟。    当活动段刷新到内存时,它进入到压缩管线队列中,并立即安排后台合并任务。后者同时扫描管道中的所有段(on-disk compaction),并将多个索引合并为一个。基本basic策略和eager压缩策略之间的差异体现在它们如何处理cell。basic压缩不会消除冗余数据版本,以避免物理复制。它只是重新排列对KeyValue对象的引用。相反,eager压缩会滤除重复项。这是以额外的计算和数据迁移为代价的-例如,使用MSLAB存储时,将尚存的cell复制到新创建的MSLAB。当数据高度冗余时,压缩的开销得到了回报。    压缩的未来实现可能会自动在basic和eager压缩策略之间进行选择。例如,该算法可能会尝试一次eager压缩,并根据收到的值(例如,被淘汰的部分数据)安排下一次压缩。这种方法可以减轻系统管理员的负担,并适应不断变化的访问模式。摘要    在这篇博客中,我们讨论了Accordion的基本原理,配置,性能提升以及内存压缩算法的一些细节。 下一篇文章将重点为HBase开发人员介绍系统的内部。    我们感谢Michael Stack,Anoop Sam John和Ramkrishna Vasudevan的持续支持,使该项目得以实现。
  • [技术干货] 每日分享:如何重命名一个HBase表
    利用snapshot特性,可以采用以下简单的方法进行表的Renamehbase shell> disable 'tableName' hbase shell> snapshot 'tableName', 'tableSnapshot' hbase shell> clone 'tableSnapshot', 'newTableName' hbase shell> delete_snapshot 'tableSnapshot'void rename(HBaseAdmin admin, String oldTableName, String newTableName) {        String snapshotName = randomName();     admin.snapshot(snapshotName, oldTableName);     admin.cloneSnapshot(snapshotName, newTableName);     admin.deleteSnapshot(snapshotName);     admin.deleteTable(oldTableName) }
  • [技术干货] 每日分享: HBase shell-status命令
    原文地址 https://bbs.huaweicloud.com/blogs/175386 HBase shell中有一个status命令,可以查看HBase集群的一些基本状态,例如:hbase(main):003:0> status3 servers, 0 dead, 2.3333 average load直接运行status命令,可以查看RegionServer的数量和基本的负载情况。 但是这样的结果是否太简单了呢?其实这个命令还可以输入参数,以便查看更多详细的信息的。查看status命令的帮助信息:(只能用help命令查看)hbase(main):001:0> help 'status'Show cluster status. Can be 'summary', 'simple', 'detailed', or 'replication'. Thedefault is 'summary'. Examples:   hbase> status  hbase> status 'simple'  hbase> status 'summary'  hbase> status 'detailed'  hbase> status 'replication'  hbase> status 'replication', 'source'  hbase> status 'replication', 'sink' 例如可以查看replication的基本信息,这些信息在判断replication运行的状态很有帮助,但是这些信息在其它地方比较难获取到(目前版本JMX中没有),只能通过这个命令进行获取。hbase(main):005:0> status 'replication'version 1.0.03 live servers    XXX-172-0-171:       SOURCE: PeerID=1, AgeOfLastShippedOp=0, SizeOfLogQueue=0, TimeStampsOfLastShippedOp=Wed Apr 06 11:00:19 CST 2016, Replication Lag=0       SINK  : AgeOfLastAppliedOp=0, TimeStampsOfLastAppliedOp=Fri Apr 01 12:17:12 CST 2016    XXX-172-0-173:       SOURCE: PeerID=1, AgeOfLastShippedOp=0, SizeOfLogQueue=0, TimeStampsOfLastShippedOp=Wed Apr 06 11:00:17 CST 2016, Replication Lag=0       SINK  : AgeOfLastAppliedOp=0, TimeStampsOfLastAppliedOp=Fri Apr 01 12:17:17 CST 2016    XXX-172-0-172:       SOURCE: PeerID=1, AgeOfLastShippedOp=0, SizeOfLogQueue=0, TimeStampsOfLastShippedOp=Wed Apr 06 11:00:18 CST 2016, Replication Lag=0       SINK  : AgeOfLastAppliedOp=0, TimeStampsOfLastAppliedOp=Mon Apr 04 03:53:53 CST 2016 另外在不方便查看HMaster页面的时候,也可以通过这个命令查看很多集群运行时的信息,很方便使用。 
  • [技术干货] 每日分享:HBase Quota的使用
    原文地址:https://bbs.huaweicloud.com/blogs/174641背景:多租户共享集群时,可以针对namespace,Table,User进行请求的限制,控制负载,避免请求过多导致集群受影响。启用Quota默认情况下,quota功能处于禁用状态。要启用quota,将“hbase-site.xml”文件中的参数“hbase.quota.enabled”的值改为“true”Quota缓存刷新配置默认情况下,quota设置缓存刷新周期“hbase.quota.refresh.period”设为5*60000(5分钟)。这就意味着,用户在更新quota设置后最多需要等待5分钟,这些设置才能生效。 设置Quota当由于用户数量或用户请求过多而导致集群工作负载增加时,系统需要按照优先顺序对用户或用户请求进行排列以实现平稳运行。可利用HBase quota功能,让管理员限制HBase系统中的表、分区或请求的数量。HBase提供以下三种类型的quota:·         Namespace quota:一个Namespace中可包含的表或分区的数量·         请求数量quota:某个用户或某些相同名字的用户可以在任意指定时间内在特定表上或Namespace中执行的请求的数量。·         请求大小quota:某个用户或某些相同名字的用户可以在任意指定时间内在特定表上或Namespace中执行的请求的大小。 下面介绍每一种Quota的用法1.  Namespace QuotaNamespace quota用于设置一个Namespace中可包含的表或分区的数量。以下是Namespace quota:设置Namespace中可包含的表的数量示例命令说明create_namespace 'namespace_name',   {'hbase.namespace.quota.maxtables'=>'5'}使用quota的maxtables来创建Namespace。describe_namespace 'namespace_name '显示Namespace的quota信息。alter_namespace 'namespace_name ', {METHOD =>   'set', 'hbase.namespace.quota.maxtables'=>'8'}修改现有的Namespace并设置quota的maxtables值。alter_namespace 'namespace_name ', {METHOD =>   'unset', NAME=> 'hbase.namespace.quota.maxtables'}删除Namespace中设置的quota的maxtables值。 设置Namespace中可包含的分区的数量示例命令说明create_namespace 'namespace_name', {'hbase.namespace.quota.maxregions'=>'10'}使用quota的maxregions来创建Namespace。describe_namespace 'namespace_name '显示Namespace的quota信息。alter_namespace 'namespace_name ', {METHOD =>   'set', 'hbase.namespace.quota.maxregions'=>'20'}修改现有的Namespace并设置quota的maxregions值。alter_namespace 'namespace_name ', {METHOD =>   'unset', NAME=> 'hbase.namespace.quota.maxregions'}删除Namespace中设置的quota的maxregions值。2.  请求数量Quota请求数量Quota保留某个用户或某些相同名字的用户可以在任意指定时间内在特定表上或Namespace中执行的请求数量。请求数量Quota在命令中使用时间单位。有效的时间单位为秒(sec)、分(min)、小时(hour)和天(day)。以下是五种设置请求数量Quota的示例: 设置用户在指定时间内可以执行的请求数量示例命令说明set_quota TYPE => THROTTLE, USER =>   'user_name', LIMIT => '10req/sec'对指定用户设置每秒10个请求的quota。list_quotas USER => 'user_name'显示指定用户的quota信息。set_quota TYPE => THROTTLE, USER => '   user_name ', LIMIT => NONE删除指定用户的quota。 设置用户在指定时间内在指定表上可以执行的请求数量示例命令说明set_quota TYPE => THROTTLE, USER => '   user_name ', TABLE => 't1', LIMIT => '10req/sec'对指定用户的特定表设置每秒10个请求的quota。list_quotas USER => 'user_name', TABLE => 't1'显示指定用户在特定表上的quota信息。set_quota TYPE => THROTTLE, USER => 'u1',   TABLE => 't1', LIMIT => NONE删除指定用户的特定表的quota。 设置用户在指定时间内在指定Namespace上可以执行的请求数量示例命令说明set_quota TYPE => THROTTLE, USER => '   user_name ', NAMESPACE => 'ns1', LIMIT => '10req/sec'对指定用户的特定Namespace设置每秒10个请求的quota。list_quotas USER => 'user_name', NAMESPACE =>   'ns.*'显示指定用户在特定Namespace上的quota信息。set_quota TYPE => THROTTLE, USER => 'u1',   NAMESPACE => 'ns1', LIMIT => NONE删除指定用户的特定Namespace的quota。 设置在指定时间内可以在表上执行的请求数量示例命令说明set_quota TYPE => THROTTLE, TABLE => 't1,   LIMIT => '10req/sec'针对特定表设置每秒10个请求的quota。list_quotas TABLE => 't1'显示特定表的quota信息。set_quota TYPE => THROTTLE, TABLE => 't1',   LIMIT => NONE删除特定表的quota。 设置在指定时间内可以在Namespace中执行的请求数量示例命令说明set_quota TYPE => THROTTLE, NAMESPACE =>   'ns1', LIMIT => '10req/sec'针对特定Namespace设置每秒10个请求的quota。list_quotas NAMESPACE => 'ns1'显示特定Namespace的quota信息。set_quota TYPE => THROTTLE, NAMESPACE =>   'ns1', LIMIT => NONE删除特定Namespace的quota。3.  请求大小Quota请求大小quota是指设置某个用户或某些相同名字的用户可以在任意指定时间内在特定表上或Namespace中执行的请求大小。请求大小quota在命令中使用时间和大小单位。有效的大小单位为B(字节)、K(千字节)、M(兆字节)、G(十亿字节)、T(兆兆字节)和P(千万亿字节)。以下是五种设置请求大小quota的示例: 设置用户在指定时间内可以执行的请求大小示例命令说明set_quota TYPE => THROTTLE, USER =>   'user_name', LIMIT => '5K/min'对指定用户设置每分钟5千字节的quota。list_quotas USER => 'user_name'显示指定用户的quota信息。set_quota TYPE => THROTTLE, USER => '   user_name ', LIMIT => NONE删除指定用户的quota。·          设置在指定时间内在指定表上可以执行的请求大小示例命令说明set_quota TYPE => THROTTLE, USER => 'u1',   TABLE => 'table_name', LIMIT => '5K/min'对指定用户的特定表设置每分钟5千字节的quota。list_quotas USER => 'bob.*', TABLE => 't1'显示指定用户在特定表上的quota信息。set_quota TYPE => THROTTLE, USER => 'u1',   TABLE => 't1', LIMIT => NONE删除指定用户的特定表的quota。·          设置用户在指定时间内在指定Namespace中可以执行的请求大小示例命令说明set_quota TYPE => THROTTLE, USER => 'u1',   NAMESPACE => 'ns1', LIMIT => '5K/min'对指定用户的特定Namespace设置每分钟5千字节的quota。list_quotas USER => 'bob.*', NAMESPACE =>   'ns.*'显示指定用户在特定Namespace上的quota信息。set_quota TYPE => THROTTLE, USER => 'u1',   NAMESPACE => 'ns1', LIMIT => NONE删除指定用户的特定Namespace的quota。 设置在指定时间内可以在表上执行的请求大小示例命令说明set_quota TYPE => THROTTLE, TABLE => 't1',   LIMIT => '5K/min'针对特定表设置每分钟5千字节的quota。list_quotas TABLE => 'myTable'显示特定表的quota信息。set_quota TYPE => THROTTLE, TABLE => 't1',   LIMIT => NONE删除特定表的quota。 设置在指定时间内可以在Namespace中执行的请求大小示例命令说明set_quota TYPE => THROTTLE, NAMESPACE =>   'ns1', LIMIT => '5K/min'针对特定Namespace设置每分钟5千字节的quota。list_quotas NAMESPACE => 'ns.*'显示特定Namespace的quota信息。set_quota TYPE => THROTTLE, NAMESPACE =>   'ns1', LIMIT => NONE删除特定Namespace的quota。 
  • [技术干货] 每日分享:HBase学习之:HBase RPC
    原文地址:https://bbs.huaweicloud.com/blogs/173527学习HBase的RPC可以为学HBase打好基础,因为RPC是HMaster,RegionServer和Client通信的纽带1.1      1 RPCRPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。    首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。交互过程如下图所示:1.2      HBase.ipc1.2.1        2.1 ServerRPC Server实现了一种抽象的RPC服务,同时提供Call队列。Ø  RPC Server结构 结构 (类)功能 HBaseServer.ListenerRPC Server的监听者,用来接收RPC Client的连接请求和数据,其中数据封装成Call后PUSH到Call队列。HBaseServer.HandlerRPC Server的Call处理者,和Server.Listener通过Call队列交互。HBaseServer.ResponderRPC Server的响应者。HBaseServer.Handler按照异步非阻塞的方式向RPC Client发送响应,如果有未发送出的数据,交由HBaseServer.Responder来完成。HBaseServer.ConnectionRPC Server数据接收者。提供接收数据,解析数据包的功能。HBaseServer.Call持有客户端的Call信息。 Ø  RPC Server主要流程 RPC Server作为服务提供者由两个部分组成:接收Call调用和处理Call调用。接收Call调用负责接收来自RPC Client的调用请求,编码成Call对象后放入到Call队列中。这一过程由Listener线程完成。具体步骤:1.   Listener线程监视RPC Client发送过来的数据。2.   当有数据可以接收时,Listener启动Reader线程,reader线程调用Connection的readAndProcess方法接收并处理数据。3.   Connection边接收边对数据进行处理,如果接收到一个完整的Call包,则构建一个Call对象PUSH到Call队列中,由Handler线程来处理Call队列中的所有Call。4.   Handler线程监听Call队列,如果Call队列非空,按FIFO规则从Call队列取出Call。5.   将Call交给RPC.Server处理。(在WritableRpcEngine.Server类中,该类是HBaseServer的子类)。6.   借助JDK提供的Method,完成对目标方法的调用,目标方法由具体的业务逻辑实现。7.   返回响应HBaseServer.Handler按照异步非阻塞的方式向RPC Client发送响应,如果有未发送出的数据,则交由Server.Responder来完成。1.2.2        ClientRPC Client是Client的实现和入口类。Ø  RPC Client结构 结构 功能 HBaseClient.ConnectionId到RPC Server对象连接的标识。HBaseClient.CallCall调用信息。HBaseClient.ParallelResultsCall响应。WritableRpcEngine.Invoker对InvocationHandler的实现,提供invoke方法,实现RPC Client对RPC Server对象的调用。Invocation用来序列化和反序列化RPC Client的调用信息。(主要应用JAVA的反射机制和InputStream/OutputStream)Ø  RPC Client主要流程 每一个Call都是由RPC Client发起。步骤说明:1.   RPC Client发起RPC Call,通过JAVA反射机制转化为对Client.call调用。2.   调用getConnection得到与RPC Server的连接。每一个RPC Client都维护一个HashMap结构的到RPC Server的连接池。具体建立连接的流程见下图。3.   通过Connection将序列化后的参数发送到RPC服务端。4.   阻塞方式等待RPC服务端返回响应。1.2.3        同步客户端发起的RPC调用是同步的,而服务端处理RPC调用是异步的。客户端调用线程以阻塞同步的方式发起RPC连接及RPC调用,将参数等信息发送给Listener,然后等待Connection接收响应返回。Listener负责接收RPC连接和RPC数据,当一个Call的数据接收完后,组装成Call,并将Call放入由Handler提供的Call队列中。Handler线程监听Call队列,如果Call队列不为空,则按FIFO方式取出Call,并转为实际调用,以非阻塞方式将响应发回给Connection,未发送完毕的响应交给Responder处理。
  • 时空索引Geomesa的运维内存优化
    在使用GeoMesa时,会经常遇到性能问题,Geomesa作为HBase的客户端程序,它的代码调用了许多HBase的接口,有些地方调用不好,就会造成HBase额外消耗资源,造成性能下降。之前程序员小哥就遇到过Geomesa频繁调用hbase:meta表造成meta表节点所在RS cpu偏高的情况,这次又遇到内存持续增长造成HBase节点重启的问题,遇到这情况就需要深入到Geomesa的代码里才能去发现问题解决问题。这篇Geomesa的内存优化博文,就处理了其中一个场景下的内存问题https://bbs.huaweicloud.com/blogs/173946
  • [教程指导] MRS:SparkStreaming对接安全kafka写入hbase样例
    MRS:SparkStreaming对接安全kafka写入hbase样例关键词: MRS官网样例 Kerberos认证 kafka SparkStreaming hbase摘要:MRS spark官网样例的补充,实现SparkStreaming对接安全kafka写入hbase前期准备:1.      创建MRS 1.9.0 混合集群,大数据组件至少包括Hadoop , Spark , Hive , HBase , Kafka,开启Kerberos认证2.      集群创建好之后,参照官网https://support.huaweicloud.com/devg-mrs/mrs_06_0154.html准备开发用户,作者创建的用户名为sparkuser ,然后下载keytab与krb5.conf文件待用3.      样例下载地址https://github.com/huaweicloud/huaweicloud-mrs-example/tree/mrs-1.9开发程序:1.      将huaweicloud-mrs-example/src/spark-examples/SparkStreamingKafka010JavaExample样例导入idea2.    删除掉com.huawei.bigdata.spark.examples包下面所有类,将 SparkOnStreamingToHbase.java和StreamingExampleProducer.java文件(见附件)复制到com.huawei.bigdata.spark.examples包下3.    将pom.xml文件替换掉原工程的pom文件场景说明:1.      假定某个业务Kafka每3秒就会收到5个用户的消费记录。Hbase的table1表存储用户历史消费的金额信息。现table1表有10条记录,表示有用户名分别为1-10的用户,他们的历史消费金额初始化都是0元。基于某些业务要求,开发的Spark应用程序实现如下功能:实时累加计算用户的消费金额信息:即用户总消费金额=用户的消费金额(kafka数据) + 用户历史消费金额(table1表的值),更新到table1表。2.      创建HBase表,并插入数据a.     通过HBase创建名为table1的表,命令如下:create 'table1', 'cf'b.     通过HBase执行如下命令,将数据插入table1表中put 'table1', '1', 'cf:cid', '0'put 'table1', '2', 'cf:cid', '0'put 'table1', '3', 'cf:cid', '0'put 'table1', '4', 'cf:cid', '0'put 'table1', '5', 'cf:cid', '0'put 'table1', '6', 'cf:cid', '0'put 'table1', '7', 'cf:cid', '0'put 'table1', '8', 'cf:cid', '0'put 'table1', '9', 'cf:cid', '0'put 'table1', '10', 'cf:cid', '0'c.     通过HBase执行scan 'table1'命令,3.      集群组件的配置a.      将kafka的Broker配置参数“allow.everyone.if.no.acl.found”的值修改为“true”b.      如果开启了kerberos认证,需要将客户端的配置文件“spark-defaults.conf”和sparkJDBC服务端中的配置项spark.yarn.security.credentials.hbase.enabled置为true。c.       需要修改程序SparkOnStreamingToHbase类中kerberos.domain.name的值为$KAFKA_HOME/config/consumer.properties文件中kerberos.domain.name配置项的值。d.      用户需要对接安全Kafka,创建jaas.conf文件待用,文件内容内容如下. 注意:在Spark on YARN模式下,jaas.conf和user.keytab通过YARN分发到Spark on YARN的container目录下,因此KafkaClient中对于“keyTab”的配置路径必须为相对jaas.conf的所在路径,例如“./user.keytab”。principal修改为自己创建的用户名。Client {com.sun.security.auth.module.Krb5LoginModule requireduseKeyTab=truekeyTab="./user.keytab"principal="sparkuser"useTicketCache=falsestoreKey=truedebug=true;};KafkaClient {com.sun.security.auth.module.Krb5LoginModule requireduseKeyTab=truekeyTab = "./user.keytab"principal="sparkuser"useTicketCache=falsestoreKey=truedebug=true;}; 调测程序:1.      在后台master节点创建/root/jars和/root/jars/conf文件夹,然后将程序打包上传至/root/jars下,再将jaas.conf,keytab,krb5.conf文件上传至/root/jars/conf下.在idea中将程序打包,上传至/root/jars目录下2.      创建Topic, 并且启动Kafka的Producer,向Kafka发送数据,{zkQuorum}表示ZooKeeper集群信息,格式为IP:port, JAR_PATH为程序jar包所在路径,BrokerList格式为brokerIp:9092, {Topic}为kafka的topic名称,作者为apple。 $KAFKA_HOME/bin/kafka-topics.sh --create --zookeeper {zkQuorum}/kafka --replication-factor 1 --partitions 3 --topic {Topic}作者命令:$KAFKA_HOME/bin/kafka-topics.sh --create --zookeeper 192.168.0.122:2181/kafka --replication-factor 2 --partitions 3 --topic apple java -cp $SPARK_HOME/jars/*:$SPARK_HOME/jars/streamingClient010/*:$KAFKA_HOME/libs/*:{JAR_PATH} com.huawei.bigdata.spark.examples.StreamingExampleProducer {BrokerList} {Topic}作者命令:java -cp $SPARK_HOME/jars/*:$SPARK_HOME/jars/streamingClient010/*:$KAFKA_HOME/libs/*:/root/jars/SparkStreamingKafka010JavaExample-1.0.jar com.huawei.bigdata.spark.examples.StreamingExampleProducer 192.168.0.106:9092 apple3.      在运行样例主程序时需要指定<checkpointDir> <brokers> <topic> <batchTime>,其中<checkPointDir>指应用程序结果备份到HDFS的路径,<brokers>指获取元数据的Kafka地址,安全集群格式为brokerIp:21007,<topic>指读取Kafka上的topic名称,<batchTime>指Streaming分批的处理间隔.切换目录到/root/jars下面a.     yarn-client模式下的运行命令:spark-submit --master yarn --deploy-mode client --files ./conf/jaas.conf,./conf/user.keytab --driver-java-options "-Djava.security.auth.login.config=./jaas.conf" --conf "spark.executor.extraJavaOptions=-Djava.security.auth.login.config=./jaas.conf" --jars $SPARK_HOME/jars/streamingClient010/kafka-clients-0.10.0.0.jar,$SPARK_HOME/jars/streamingClient010/kafka_2.10-0.10.0.0.jar,$SPARK_HOME/jars/streamingClient010/spark-streaming-kafka-0-10_2.11-2.1.0.jar --class com.huawei.bigdata.spark.examples.SparkOnStreamingToHbase /root/jars/SparkStreamingKafka010JavaExample-1.0.jar <checkpointDir> <brokers> <topic> <batchTime>作者命令:spark-submit --master yarn --deploy-mode client --files ./conf/jaas.conf,./conf/user.keytab --driver-java-options "-Djava.security.auth.login.config=./jaas.conf" --conf "spark.executor.extraJavaOptions=-Djava.security.auth.login.config=./jaas.conf" --jars $SPARK_HOME/jars/streamingClient010/kafka-clients-1.1.0-mrs-1.9.0.jar,$SPARK_HOME/jars/streamingClient010/kafka_2.11-1.1.0-mrs-1.9.0.jar,$SPARK_HOME/jars/streamingClient010/spark-streaming-kafka-0-10_2.11-2.2.2-mrs-1.9.0.jar --class com.huawei.bigdata.spark.examples.SparkOnStreamingToHbase /root/jars/SparkStreamingKafka010JavaExample-1.0.jar /tmp 192.168.0.106:21007 apple 6b.     yarn-cluster模式下,首先需要修改SparkOnStreamingToHbase.java文件中将代码”String filePath = System.getProperty("user.dir") + File.separator + "conf" + File.separator;””修改为”String filePath = System.getProperty("user.dir") + File.separator ;”,运行命令如下:spark-submit --master yarn --deploy-mode cluster --files ./conf/jaas.conf,./conf/user.keytab,./conf/krb5.conf --conf "spark.yarn.cluster.driver.extraJavaOptions=-Djava.security.auth.login.config=./jaas.conf" --conf "spark.executor.extraJavaOptions=-Djava.security.auth.login.config=./jaas.conf" --jars $SPARK_HOME/jars/streamingClient010/kafka-clients-0.10.0.0.jar,$SPARK_HOME/jars/streamingClient010/kafka_2.10-0.10.0.0.jar,$SPARK_HOME/jars/streamingClient010/spark-streaming-kafka-0-10_2.11-2.1.0.jar --class com.huawei.bigdata.spark.examples.SparkOnStreamingToHbase /root/jars/SparkStreamingKafka010JavaExample-1.0.jar <checkpointDir> <brokers> <topic> <batchTime> 作者命令:spark-submit --master yarn --deploy-mode cluster --files ./conf/jaas.conf,./conf/user.keytab,./conf/krb5.conf --conf "spark.yarn.cluster.driver.extraJavaOptions=-Djava.security.auth.login.config=./jaas.conf" --conf "spark.executor.extraJavaOptions=-Djava.security.auth.login.config=./jaas.conf" --jars $SPARK_HOME/jars/streamingClient010/kafka-clients-1.1.0-mrs-1.9.0.jar,$SPARK_HOME/jars/streamingClient010/kafka_2.11-1.1.0-mrs-1.9.0.jar,$SPARK_HOME/jars/streamingClient010/spark-streaming-kafka-0-10_2.11-2.2.2-mrs-1.9.0.jar --class com.huawei.bigdata.spark.examples.SparkOnStreamingToHbase /root/jars/SparkStreamingKafka010JavaExample-1.0.jar /tmp 192.168.0.106:21007 apple 6 4.     在hbase下面查看表scan ”table1”,验证成功
  • [教程] HBase技术学习贴
    本帖汇总HBase入门学习相关的资料,和大家一起学习和使用HBase,了解基础原理.定期更新...https://bbs.huaweicloud.com/blogs/173527  HBase学习之:HBase RPChttps://bbs.huaweicloud.com/forum/thread-54213-1-1.html  HBase RowKey思路https://bbs.huaweicloud.com/blogs/173943  HBase篇---Shell命令行和Rest APIhttps://bbs.huaweicloud.com/blogs/174641 HBase Quota的使用 https://bbs.huaweicloud.com/blogs/173946  HBase&&GeoMesa 内存优化https://bbs.huaweicloud.com/blogs/175255   大数据组件运维工具之HBasehttps://bbs.huaweicloud.com/blogs/175386  HBase shell-status命令https://bbs.huaweicloud.com/blogs/175483  HBase 2.0 中的 In-Memory Compactionhttps://bbs.huaweicloud.com/blogs/178986  opentsdb读写与查询命令整理https://bbs.huaweicloud.com/blogs/180585  hbase hbtop工具介绍https://bbs.huaweicloud.com/blogs/184848 HBase客户端代码书写规范https://bbs.huaweicloud.com/blogs/187173 分享一个HBaseCompaction引起的GC问题及其恢复https://bbs.huaweicloud.com/blogs/192853 HBase是怎样从HFile中找到某个rowkeyhttps://bbs.huaweicloud.com/blogs/193849 UserGroupInformation中的几种user介绍https://bbs.huaweicloud.com/blogs/198191 初学Flink-使用Flink读写HBasehttps://bbs.huaweicloud.com/blogs/199399  HBase实用技巧:一种全量+增量数据的迁移方法https://bbs.huaweicloud.com/blogs/199075  HBase 2.X版本的元数据修复及一种数据迁移方式
  • [技术干货] Spark任务读取HBase报错“had a not serializable result”
    问题Spark任务读取HBase报错,报错信息:Task 0.0 in stage 0.0 (TID 0) had a not serializable result: org.apache.hadoop.hbase.io.ImmutableBytesWritable,应该如何处理?回答可通过如下两种方式处理:在代码的SparkConf初始化之前执行以下两行代码:System.setProperty("spark.serializer", "org.apache.spark.serializer.KryoSerializer");System.setProperty("spark.kryo.registrator", "com.huawei.bigdata.spark.examples.MyRegistrator");在SparkConf对象使用set方法设置,代码如下:val conf = new SparkConf().setAppName("HbaseTest");conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");conf.set("spark.kryo.registrator", "com.huawei.bigdata.spark.examples.MyRegistrator");
  • [技术干货] 如何彻底删除hbase的数据?
        此方案会清空hbase的表数据,谨慎操作     此方案会清空hbase的表数据,谨慎操作     此方案会清空hbase的表数据,谨慎操作1:停止hbase服务           在mrs manager上停止hbase服务 2:删除 hbase 在hdfs 上目录    hdfs dfs  -rm -r /hbase3:清空hbase 在zk上的节点     rmr    /hbase 4:重新启动Hbase即可            在mrs manager上重启hbase服务                   
  • 使用Flume消费kafka topic数据并存储到HBase
    操作场景:    Flume消费kafka数据存储到HBase中。前提条件:    已创建混合集群或者流式和分析集群(集群间网络互通,如果开启kerberos,则需配置跨集群互信https://support.huaweicloud.com/usermanual-mrs/mrs_01_0354.html)。操作步骤:    1. 从HBase客户端拷贝配置文件hbase-site.xml到Flume server所在节点(流式core节点)的配置目录 "/opt/Bigdata/MRS_x.x.x/1_x_Flume/etc/" 下。通常可以在分析集群Master节点HBase客户端安装目录如“/opt/client/HBase/hbase/conf/”下找到hbase-site.xml文件。 拷贝完成后文件需要修改文件属组为omm:wheel。    2. 从HBase集群下载用户的认证凭据。a. 在MRS Manager,单击“系统设置”。b. 在“权限配置”区域,单击“用户管理”。c. 在用户列表中选择需要的用户,单击后面的“更多”下载用户凭据。d. 解压下载的用户凭据文件,获取krb5.conf和user.keytab文件。    3. 将上一步获得的krb5.conf和user.keytab拷贝到Flume server所在节点(流式core节点)的配置目录 "/opt/Bigdata/MRS_x.x.x/1_x_Flume/etc/" 下。文件属组需要修改为omm:wheel。    4. 修改配置文件jaas.conf,文件所在目录 "/opt/Bigdata/MRS_x.x.x/1_x_Flume/etc/" 。        修改参数“keyTab”定义的用户认证文件完整路径即步骤3中保存用户认证文件的目录。    5. 修改配置文件flume-env.sh,文件所在目录 "/opt/Bigdata/MRS_x.x.x/1_x_Flume/etc/" 。                在 “-XX:+UseCMSCompactAtFullCollection”后面,增加以下内容:-Djava.security.krb5.conf=/opt/Bigdata/MRS_x.x.x/1_x_Flume/etc/krb5.conf -Djava.security.auth.login.config=/opt/Bigdata/MRS_x.x.x/1_x_Flume/etc/jaas.conf -Dzookeeper.request.timeout=120000                例如:"-XX:+UseCMSCompactAtFullCollection -Djava.security.krb5.conf=/opt/Bigdata/MRS_2.1.0/1_6_Flume/etc/krb5.conf -Djava.security.auth.login.config=/opt/Bigdata/MRS_2.1.0/1_6_Flume/etc/jaas.conf -Dzookeeper.request.timeout=120000"                请根据实际情况,修改配置文件路径,然后保存并退出配置文件。    6. 将HBase集群的“/etc/hosts”文件中host匹配相关内容添加到Flume server节点的“/etc/hosts”文件。    7. 重启该节点的flume实例。    8. 修改Flume配置文件“properties.properties”。                vi /opt/Bigdata/MRS_x.x.x/1_x_Flume/etc/properties.properties                将以下内容保存到文件“properties.properties”中:             server.sources = kafka_source         server.channels = flume         server.sinks = hbase                         server.sources.kafka_source.channels = flume         server.sources.kafka_source.type = org.apache.flume.source.kafka.KafkaSource         server.sources.kafka_source.topics = flume_test         server.sources.kafka_source.groupId = flume_group         server.sources.kafka_source.batchSize = 1000         server.sources.kafka_source.kafka.security.protocol  = SASL_PLAINTEXT         server.sources.kafka_source.kafka.kerberos.domain.name = hadoop.XXX.com         server.sources.kafka_source.kafka.bootstrap.servers=XXX.XXX.XXX.XXX:21007,XXX.XXX.XXX.XXX:21007,XXX.XXX.XXX.XXX:21007                  server.channels.flume.type = memory         server.channels.flume.capacity=100000         server.channels.flume.transactionCapacity=10000         server.channels.flume.channelfullcount = 10         server.channels.flume.keep-alive = 3          server.channels.flume.byteCapacityBufferPercentage = 20                  server.sinks.hbase.channel = flume         server.sinks.hbase.type = hbase         server.sinks.hbase.table = hbase_name         server.sinks.hbase.columnFamily= info         server.sinks.hbase.batchSize = 1000         server.sinks.hbase.kerberosPrincipal = admin         server.sinks.hbase.kerberosKeytab = /opt/Bigdata/MRS_x.x.x/1_x_Flume/etc/user.keytab         请根据实际情况,修改以下参数,然后保存并退出。         kafka.bootstrap.servers         默认情况下,安全集群对应端口21007,普通集群对应端口9092。         kafka.security.protocol         安全集群请配置为SASL_PLAINTEXT,普通集群请配置为PLAINTEXT。         kafka.kerberos.domain.name         普通集群无需配置此参数。安全集群对应此参数的值为Kafka集群中“kerberos.domain.name”对应的值。具体可到Borker实例所在节点上查看“/opt/Bigdata/MRS_Current/1_X_Broker/etc/server.properties”文件中配置项“kerberos.domain.name”对应的值,仅安全集群需要配置,其中“X”为随机生成的数字,请根据实际情况修改。         kerberosPrincipal         安全集群需要配置,用户名         kerberosKeytab                安全集群需要配置,用户认证文件,需要写绝对路径。
  • [技术干货] HBase与AI/用户画像/推荐系统的结合:CloudTable标签索引特性介绍
    标签数据已经成为越来越普遍的一类数据,以用户画像场景最为典型,如在电商场景中,这类数据可被应用于精准营销推荐。常见的用户画像标签数据举例如下:基础信息:如性别,职业,收入,房产,车辆等。购买能力:消费水平、败家指数等。行为特征:活跃程度,购物类型,起居时间等。兴趣偏好:品牌偏好,颜色偏好,价格偏好等。如何高效的利用标签数据进行精准查询,在TB/PB级别标签数据规模下,达到ms级别的查询性能,请看CloudTable的标签索引特性https://bbs.huaweicloud.com/blogs/163489
  • [技术干货] HBase RowKey思路
    1       概述   Hbase是No SQL的列存储数据库,和关系型数据库不同,没有表连接操作,在操作上限制比较大。因此,如果Schema设计的不好,会大大降低数据访问的效率,无端增加系统的负载。Schema设计需要综合考虑业务的需求和Hbase存储、访问的特点。设计好的Schema,能够充分享用Hbase大容量存储的优势同时,又能够获取较高的访问效率。本文所阐述的原则基于Hbase的路由寻址原理和底层文件存储结构,因此对本文的理解需要首先掌握Hbase路由寻址原理和文件存储结构。本文阐述HbaseSchema设计的经验原则,但需要注意的是Schema设计是根据场景综合考虑的结果,没有哪个准则能够适应所有的场景,因此在应用中需要综合考虑多个准则,平衡多种因素,才能设计出最符合业务需求的Schema。设计任何HBase业务的schema,都综合要考虑如下问题:Ø  读数据o    业务读数据是否方便?业务逻辑尽量简单o    要读取的数据在存储上是否连续分布?连续分布的数据读取效率较高,系统IO的垃圾数据较少Ø  写数据o    一次RPC能够写入多少数据?IO是hbase的瓶颈之一,需要考虑一次RPC能够写入更多的数据。o    写数据是否能够均衡?一段时间之内写入的数据在分布上能够一定程度上分散开能够保证并发度,提高写数据速度。o    写数据是否相对集中?短时间内写入的数据太分散的话会导致容易达到写操作内存警戒线,影响性能。Ø  数据清理o    如何清理数据?Hbase没有提供高效的数据清理手段,数据如何清理(Delete/dorptable/TTL/Versions?)o    如何保证没有大量过小或者空的region?空region在HBase中占用负载和内存,而且hbase没有有效手段来清理或者合并这些region,如何避免?  2       Schema设计思路   2.1   总体思路   本节讲述Schema设计总体的思路,Rowkey、Column、Family、Value的设计为本节讲述的原则的具体实现。2.1.1   Denormalization——以空间换取效率HBase具有大容量的特点,摆脱了Normalization的限制,可以采用冗余的方法,将常用的计算结果存储在一张数据表中,不需要在查询的时候适时计算。例如,对于排名统计,受容量限制,传统数据库采用适时计算排序的方式。这样的做法在数据量比较大的时候,适时计算无法满足查询的性能要求。而在HBase中,可以将排名数据提前计算出来,存放在Hbase中。如下所示为topURL的Schema设计:2.1.2   业务需要同时访问的数据连续分布Hbase是排序过的列存储形式。数据访问按照数据块来进行。一次业务中需要的数据连续分布可以让系统读到的一个数据块包含更多的有用信息。另外,Hbase Scan的效率远高于random read,连续分布的业务数据可以使用scan操作。HBase数据在存储上先按照rowkey进行排序,rowkey相同的按照column排序,rowkey和column都相同的按照时间戳排序。HBase存储的格式是byte类型,按照ascii编码大小进行排序。如下图所示:2.1.3   减少系统瓶颈的压力Hbase系统性能的瓶颈在于IO,因此提高系统的性能关键在于减少IO上的压力。可以采用的方法有:Ø  能够同时存取的数据压缩在一个cell中,如使用protobufØ  能够同时存取的数据放在同一行的不同列中,减少RPC2.2   数据放在同一个cell中还是同一行的不同列中需要根据数据量的大小和枚举值的多少进行权衡。表设计   Hbase表可以定义一些表属性,这些属性的合理使用对业务有较大影响。这些属性包括TTL、Versions、compression、bloomfilter等。另外,建表的方法以及region划分对系统并发能力、数据清理能力有影响。2.2.1   按天建表按天建表的主要作用有两个:Ø  可以将数据以天为单位分开,这样当数据过期的时候,可以通过drop表的方法来清理。Ø  在存入数据的时候,只涉及到当天的数据表,数据相对集中,在数据量非常大的情况下会有更好的性能表现。按天建表是一个例子,实际应用中可以按照特定时间周期来建表,例如年、月等。建表选择时间周期的原则有两个:Ø  当数据过期以后,能够同时清理。Ø每张表的数据分配到每个regionserver上以后,能够划分成数目合适的region。每个regionserver的激活Region数大于1,小于(写操作内存/flushsize)为宜。如果激活region数过少,则系统并发度不好;否则如果过大,会导致写操作内存很容易达到警戒线,影响写操作性能。2.2.2   预分regionHBase0.90以后的版本提供了建表预分region的功能。建表预分region可以让region在开始阶段就能够均衡到各个regionserver之间。因此需要根据数据的分布,识别出可能会造成热点的key的区域,在这些区域设置splitkey,进行预分region。2.2.3   TTLTTL是另外一种数据清理的方法。设定数据的生命周期,在数据过期以后,hbase自动清理这些数据。和按天建表,过期后删表的方法相比,设置TTL的方法更为简单直观,但是也有一些缺点:Ø  过期的数据需要一定时间才能够清理掉,这时候如果查询到了过期的数据可能会长时间没有响应,影响查询的性能。Ø  使用TTL来清理数据主要是通过compact进行的,在特定场合下会增加compact的负担。因此,对TTL的使用需要根据业务需求、数据量来综合考虑。需要尽量避免查询到过期的数据,如果系统负荷非常大,不建议使用TTL。2.2.4   VersionsHbase是个多维的数据表。每行每列可以存放多个版本的数据。多个版本之间除了内容不同以外,唯一的区别是时间戳。时间戳相同的版本会被覆盖掉。Versions提供了查询历史版本的信息,但是版本个数是有限的,对于需要查询历史上不同时间段的内容的场景,可以通过设置多个版本来实现。Versions的个数有限,如果需要存放的历史版本数量非常巨大或者数量不能确定在一定范围之内的场景,不适合使用versions。另外,versions也是清理数据的一种方式。例如设置versions=3,如果在其中写入了4个版本的数据,则最老的版本数据会被清理掉。2.2.5   使用压缩创建表的时候,可以指定压缩算法。Hbase0.90系列版本支持lzo和gzip两种压缩方式。Lzo的压缩率低一些,能够压缩到原始数据的40%左右,但是压缩速度比较快,适合于对于存取速度要求比较高,但对空间要求略低的场景。Gzip的压缩率高,能够压缩到原始数据的30%以内,但是压缩速度比较慢,适合于存取速度要求低,但空间要求高的场景。压缩率和数据的结构有关系,如果是随机程度比较高的无序数据,压缩率会比较低一些,如果是比较有规律的数据(如日志数据),压缩率会比较高。另外,使用lzo需要用到具有gpl 授权的桥接程序,商用的化需要考虑授权的问题。2.2.6   BloomfilterHbase中,使用bloomfilter的列,写入数据的时候,要将该数据的key添加到bloomfilter中;读取数据之前,要使用该数据的key在bloomfilter中进行测试,确定该key是否添加到了bloomfilter中。因此,bloomfilter可以用来在读取一个精确的key之前,预判该key是否在文件中实际存在,进而减少读取文件的消耗。由于bloomfilter是根据多个hash函数hash出来的bit值进行判断,可能会有重复,因此bloomfilter可以准确判断出一个key的不存在,而不能准确判断出key的存在。BloomFilter的key指的是Hstorekey。HStorekey中包括row、column、timestamp成员变量。 在实际使用中,获取bloomfilterkey的返回值是Hstorekey的row。因此,hbase中,Bloomfilter真正使用的key是rowkey。bloomfilter的vectorsize、元素个数、hash函数个数之间的关系如下:M表示vectorsize,n表示元素个数,k表示hash函数个数,则:M = (k*n)/ln2在hbase中,hash函数个数默认为4,因此,m和n的关系为:M=5.77n。因此,假定有1M条记录要插入bloomfilter,则需要的向量的大小为5.7M bit,约0.7Mb。如果每条记录在磁盘上存储的大小是256个字节,如果有1T的数据,则有4G条记录,约耗费2.7G内存用于存储bloomfilter。如果每条记录在磁盘上的存储大小为2K,如果有1T的数据,则有500M条记录,约耗费350M内存用于存储bloomfilter。因此,存储的每条记录越大,bloomfilter的空间利用效率越高。 综上所述,适合使用bloomfilter的场景需要同时满足如下条件:Ø  访问数据使用精确的key。Ø  数据是小key,大value的模式。(即使这样,也要根据数据量来计算消耗的内存,综合判断) 2.3   Rowkey结构设计   在系统设计中,为了提高系统性能都需要考虑以下两个因素:1)  提高数据访问的速度2)  提高数据的利用率结合Hbase的存储访问特点,要做到以上两点,在hbase的rowkey设计时,一个总的原则是:需要同时访问的数据,rowkey尽量连续。原因如下:          i.            数据Scan操作必须使用Startrow和Endrow来指定范围,避免或减少使用filter才能提高访问速度。因为:Ø  在Hbase的regioninfo中,有region的startrow和endrow信息,因此指定了scan的rowkey范围的话,hbase能够快速定位出需要访问的数据在哪个region。Ø  Hbase在文件存储上是排序并有索引的存储。Hfile中keyvalue的排序优先考虑rowkey的排序。并且Hfile的索引使用storekey,在storekey中,rowkey处于最优先的位置。因此如果指定出startrow和endrow,hbase就能快速定位需要访问的数据在hfile中的位置。这样可以提高数据访问的速度。根据这个原则,如果需要访问的数据rowkey差异很大,则没有办法指定Startrow和endrow。访问可能会是一个全表扫描的过程,效率就非常低了。        ii.            需要访问的数据rowkey连续的话,scan到的有用数据比较多,利用率高,能够避免或减少反复内存倒换。 另外,rowkey的设计和数据的分布有很大关系,rowkey设计的时候需要保证数据入库时的并发度,但又不能过于分散。下面以MD业务和scmartcare业务的schema设计为例,讲述为了保证业务需要的数据rowkey连续以及保证数据良好分布的一些原则。2.3.1   可枚举属性值较少的属性放在rowkey前面在rowkey中,需要放入多个属性,这多个属性的先后次序和访问的效率有直接的关系。一个普遍的规则是:数量较少,可控的属性放在rowkey前面(如ServiceType,CPID等);反之放在后面(如url,mxid等)。这样做的原因是可控属性放在前面,对各种不同查询需求的平衡性强一些,反之平衡性较差。例如如下TraficGeo表rowkey的场景:模型一:ServiceType可枚举,并且数量较少,分为http和rtsp两种,放在前面;而cpid可能会比较多(假设有5个cp),因此放在后面。这样的设计能够适应如下两种需求,复杂度都比较小:1)  查询2010-10,所有cp的http数据。这种需求设置scan的startrow=‘2010-10,http,’,endrow=‘2010-10,http,z’,即可。2)  查询2010-10,cp001的所有协议的数据。这种需求下,根据scan rowkey连续的原则,需要将查询划分成两个scan,分别查询http,cp001的数据和rtsp,cp001的数据。但是,如果将cp放在前面,如下所示,适应性就差一些,如下所示模型二:1)  查询2010-10,cp001的所有协议的数据。这种需求下,设置scan的startrow=‘2010-10,cp001,’,endrow=‘2010-10,cp001,z’,即可。2)  查询2010-10,所有cp的http数据。这种需求下,根据scan的rowkey连续原则,需要将查询分成cp001,http;cp002,http;cp003,http;cp004,http;cp005,http五个查询进行,相对模型一复杂了一些。 2.3.2   业务访问中权重高的key放在前面例如URLRecords表的主要用途是用来计算当天的URL访问排名。根据业务需求,需要访问某天的所有URL,因此date是主键,权重更高,放在前面,而URL则放在后面。如下所示:但是在percontent表中,业务需求是LDS查询某个URL一个时间段内的访问数据,因此date需要放在URL后面,如下所示。 2.3.3   多业务共用rowkey导致数据访问矛盾采用折中取舍或冗余的方法解决同一种key,在满足不同需求的时候可能权重不同。例如3.1.1中讲述的cpid和ServiceType,在遇到不同需求的时候权重不同。但cpid和serviceType是可枚举,数量较少的属性,可以按照3.1.1的方法解决。在一些场景中,有些不可枚举,数量较大的key也存在类似的问题,本节给出几种解决思路。2.3.3.1         寻求折中兼顾的方案例如:Percontent业务,在LDS中,业务需要查询video001,guangdong从2010-10-5~2010-10-20的数据,则rowkey设计成如下形式更为方便:但是,在LDA中,需要聚合每个月的daily数据,声称monthly数据,按照上面的格式,则无法指定一个scan的范围,来启动MR程序将daily数据聚合。但是把时间属性放在前面的话,就非常容易了,如下所示:因此,将时间属性放在前面还是后面,是一对矛盾,在不同场景下,权重不同,各有其适用场景。但是将时间分段,分别放在前后,能够很好的解决这个矛盾,如下所示:2.3.3.2         构造冗余数据例如,percontent表的数据包含了URL Records的数据,URL Records的数据是冗余存储的,区别在于percontent的URL放在date前面,而URL Records表的URL放在date后面。这就是由于URL在满足不同需求的时候,权重不同,由于URL Records需要的数据量不大,因此采用冗余的机制解决该矛盾。2.3.3.3         权衡需求的重要性和系统忍受度选择一种方案当两种需求有矛盾,但其中一方属于次要需求,并且在系统忍受度范围之内的话,可以舍弃一种方案。优先满足需求更强的一方。2.3.4   时间属性在rowkey中的使用如果需要经常访问特定时间段的数据,将时间属性放在rowkey中是一个较好的选择。和利用时间戳来访问特定时间段的数据方法相比,将时间属性放在rowkey中具有可控性,容易将能够同时访问的数据相对集中存放的优点。时间属性放在rowkey中需要注意数据分布和并发度的问题:hbase数据是按照rowkey排序的,时间属性放在rowkey中容易造成数据总是在末尾写入的情况,这种情况下并发度很差。这种情况可以通过在时间属性前面增加prefix和提前预分region的方法解决。2.3.5   循环key使用如果rowkey中有时间属性,并且随着时间的增加,rowkey会不断的增大下去的话,会造成region数量不断地增加。如果使用TTL来控制数据的生命周期,一些老的数据就会过期,进而导致老的region数据量会逐渐减少甚至成为空的region。这样一方面region总数在不断增加,另外一方面老的region在不断的成为空的region,而空的region不会自动合并,进而造成过多空的region占用负载和内存消耗的情况。这种情况下,可以使用循环key的方法来解决。思路是根据数据的生命周期设定rowkey的循环周期,当一个周期过去以后,通过时间映射的方法,继续使用老的过期数据的rowkey。例如,key的格式如下:YY-MM-DD-URL。如果数据的生命周期是一年,则可以使用MM-DD-URL的格式。这样当前一年过去以后,数据已经老化,后一年的数据可以继续写入前一年的位置,使用前一年数据的rowkey。这样可以避免空的region占用资源的情况。根据hbase的原理,key的周期需要至少比TTL大2* hbase.hregion.majorcompaction(默认24小时)的时间,才能够保证过期的数据能够在key循环回来之前得到完全清理。按照时间周期进行建表的方式也可以解决空region的问题,和循环key方法相比较,循环key的优点如下:Ø  操作简单,不需要重复建表,系统自动处理同样,循环key具有如下劣势:Ø  需要使用TTL来老化数据,可能会增加compact负担Ø  需要保证查询操作不会查询到过期数据,否则会影响系统性能。根据以上对比,如果在系统压力不是特别大,需要长期运行,能够控制查询不会查询到过期数据的场景下,建议使用TTL+循环key的方式,否则建议使用按照时间周期进行建表的方式。 2.3.6   通过rowkey设计来控制并发度在相同业务模式下,不同的rowkey设计系统的并发度不一样。和按天建表的思路类似,通过rowkey控制并发度的原则是激活的region总数适中,每个regionserver的激活Region数大于1,小于(写操作内存/flushsize)为宜。为了实现这一点,可以将可枚举、数量有限的属性放在rowkey的前面,时间放在后面的方式来提高并发度;通过将大粒度的时间属性(如天、小时等)放在rowkey前面,数量很大的可枚举属性(如电话号码、URL等)放在后面的方法来控制激活的region数。2.4   Family&Column   2.4.1   可枚举数量少扩展性弱的属性作为Family,不可枚举数量多扩展性强的属性作为column由于Column Family的增、删、改都需要首先disable Table,影响其他Family的正常访问,因此作为Family的属性取值范围要尽量减少扩展。例如ServiceType,当前的取值只有两种http、rtsp,看似比较适合做为Family,但是ServiceType可能会扩展,并不局限于http、rtsp两种,当扩展的时候会影响系统的访问,因此并不推荐作为Family。而是放在rowkey中。而在userequipment表中,设备的纪录纬度为播放器、浏览器、终端三种,不需要扩展,因此适合作为family。如下所示:相对的,具体的浏览器类型、终端类型由于种类比较多,可枚举性差,所以适合放在column中。 2.4.2   对于hbase需求不同分表或者分family每个family有自己独立的属性,例如version和TTL。因此,如果数据对于这些属性需求不同的话,则可以放在不同的family中。例如,相同类型的数据,如trafic、percontent等,时间纬度不同,如daily数据、monthly数据需要保存的时间不一样,因此TTL不同。这种情况下,daily数据、monthly数据可以放在不同的family中或者不同的数据表中。2.4.3   尽量均衡各个store的大小如上一节所述,daily、monthly、hourly数据的TTL不同,可以放在不同的family中。但是这样做的话将会导致同一个reagion不同family的大小差异比较大,出现很多小的或者空的store,导致store数量无端增加。如下所示:由于hbase中,很多内部操作(如flush、compact)的执行单位是store,store的增加会影响系统性能,因此需要尽量避免由于不同family大小失衡导致的大量小store的出现。因此,daily、hourly、monthly数据推荐存放在不同的table中。2.4.4   需要同时读取但数量较多的数据放在同一行的不同column中有些数据,业务需要同时访问,但这些数据比较多,不适合全部打包存放的,可以放在同一个row和family的不同column中。例如,业务需要查询2010-10-10,URL001在中国所有省的访问情况。这种场景下,中国31个省的数据需要同时读取,但是31个省比较多,不适合打包在一个cell里面,可以放在同一行的不同column中,如下所示。这样做可以减少rpc,方便存取。2.5   Value   2.5.1   多数场景下同时存取的数据放在一个cell中一个table中,相同row、family、column的数据为一个cell。多数场景下都需要同时存取的数据可以放在一个cell中。例如,用户访问纪录数据中的属性request,delived,connection,duration等,在LDS端多数场景下需要同时访问,并且这些数据在存储时也是同时写入hbase,因此可以放在一个cell中。这样可以减少rowkey的存放,节省存储空间,提高访问效率。放入一个cell中的数据可以通过protobuf来进行压缩封装。Protobuf提供了数据压缩、存取的接口。例如percontent业务的数据protobuf如下:package com.huawei.ngcdn.md.lda.hbase.protobuf;option java_outer_classname =   "VisitorsInfoProtos";message Visitors {  optional int64 requests = 1;  optional int64   delivered  = 2;  optional int64   internal  = 3;  optional int64   duration  = 4;  optional int64   users  = 5 ;   enum ServiceType {    ALL = 0;    HTTP = 1;    RTSP = 2;  }  optional ServiceType type = 6   [default = ALL];}message VisitorsInfo {       repeated   Visitors visitor = 1;} Requests、delived、internal、duration、users、ServiceType等属性经过protobuf打包压缩后,在hbase中以Byte[]的形式存放,如下所示:                                                                                                                                                       本文转载自华为内部博客,作者:bijieshan
  • [技术干货] [大数据]hbase-shaded-netty-2.1.0.jar编译移植
    一、编译环境准备1.1 安装Openjdk下载并安装到指定目录(如/opt/tools/installed):wget  https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u191-b12/OpenJDK8U-jdk_aarch64_linux_hotspot_8u191b12.tar.gztar   -zxf OpenJDK8U-jdk_aarch64_linux_hotspot_8u191b12.tar.gzmv jdk8u191-b12   /opt/tools/installed/配置java环境变量,在/etc/profile文件末尾处增加下面的代码:JAVA_HOME=/opt/tools/installed/jdk8u191-b12PATH=$JAVA_HOME/bin:$PATHexport   JAVA_HOME PATH运行下面命令,使修改的环境变量生效:source   /etc/profile1.2 安装Maven下载并安装到指定目录(如/opt/tools/installed):wget   https://archive.apache.org/dist/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gztar   -zxf apache-maven-3.5.4-bin.tar.gzmv   apache-maven-3.5.4 /opt/tools/installed/修改maven环境变量,在/etc/profile文件末尾增加下面高亮代码:JAVA_HOME=/opt/tools/installed/jdk8u191-b12MAVEN_HOME=/opt/tools/installed/apache-maven-3.5.4PATH=$MAVEN_HOME/bin:$JAVA_HOME/bin:$PATHexport   MAVEN_HOME   JAVA_HOME PATH运行下面的命令,是修改的环境变量生效:source   /etc/profile修改maven配置文件中的:本地仓路径、远程仓等:<!--默认在“~/.m2/”目录下,修改成你自己想保存的目录--><localRepository>/path/to/local/repo</localRepository> <!--修改成自己搭建的maven仓库,ARM使能后的jar包替换到该仓库--><mirror></mirror> 二、软件移植分析--三、依赖库编译3.1 第三方依赖包3.1.1 编译netty-all-4.1.17.Final.jar请参考链接https://bbs.huaweicloud.com/forum/thread-22723-1-1.html 编译netty-all-4.1.17.Final.jar。四、Jar包编译从官网上下载源码并解压:wget https://github.com/apache/hbase-thirdparty/archive/2.0.0RC0.tar.gztar   -zxf 2.0.0RC0.tar.gzcd hbase-thirdparty-2.0.0RC0执行编译:mvn   install -DskipTests编译完成后在hbase-shaded-netty/target目录下生成jar包:五、参考信息--六、FAQQuestion1:无法执行“patch”Answer1:缺少patch,需手动安装yum -y install patchQuestion2:无法找到libnetty_transport_native_epoll_x86_64.soAnswer2:修改hbase-shaded-netty/pom.xml文件,将x86_64修改为aarch_64 【来自转载】
  • [技术干货] [大数据]CDH5.15.1(x86)--hbase相关组件的移植指南【中标麒麟】
    1 CDH简介CDH(Cloudera’s Distribution Including Apache Hadoop)是Cloudera的开源大数据平台,基于Web的用户界面,支持大多数Hadoop组件,包括HDFS、MapReduce、Hive、Pig、Hbase、Zookeeper、Sqoop,简化了大数据平台的安装、使用难度。本文主要是描述如何将CDH 5.15.1的x86版本中的hbase相关组件移植到TaiShan服务器上,包含编译部分。CDH的其他组件如果需要移植,也可以参考本文中描述的方法操作。官方链接:http://archive.cloudera.com/cdh5/cdh/5/hbase/类别:大数据语言: JAVA 2 软硬件环境类别子项版本获取地址(方法) 硬件CPUKunpeng 920iBMC网络Ethernet-10GEiBMC存储SATA 4TiBMC内存xxG   xxxMHziBMCOSNeoKylin7.5cat   /etc/neokylin-releaseKernel4.14.0cat   /proc/version 软件GCC4.8.5gcc -vMaven3.5.4参考下面安装说明JDK1.8.0_191参考下面安装说明Protoc2.5.0参考下面安装说明3 编译环境准备3.1 安装Openjdk下载并安装到指定目录(如/opt/tools/installed):wget  https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u191-b12/OpenJDK8U-jdk_aarch64_linux_hotspot_8u191b12.tar.gztar   -zxf OpenJDK8U-jdk_aarch64_linux_hotspot_8u191b12.tar.gzmv jdk8u191-b12   /opt/tools/installed/【注】:使用系统自带Openjdk软件包可以通过执行“yum -y install java-1.8.0*”进行安装然后参考如下步骤配置JAVA_HOME环境变量;配置java环境变量,在/etc/profile文件末尾处增加下面的代码:JAVA_HOME=/opt/tools/installed/jdk8u191-b12PATH=$JAVA_HOME/bin:$PATHexport   JAVA_HOME PATH运行下面命令,使修改的环境变量生效:source   /etc/profile3.2 安装GCC等依赖项挂载OS镜像:mount -o loop   /home/NeoKylin/nsV7Update5-adv-lic-build05-aarch64.iso /mnt/NeoKylin/修改/etc/yum.repos.d/ns7-adv.repo文件,配置yum本地源:[ns7-adv-os]name=NeoKylin Linux Advanced Server 7 - Osbaseurl= file:///mnt/NeoKylingpgcheck=0gpgkey=file:///mnt/NeoKylin/RPM-GPG-KEY-neokylin-releaseenabled=1        运行下面的命令,使yum源配置生效:yum clean allyum makecacheyum安装GCC等相关依赖:sudo yum install -y snappy snappy-devel autoconf automake libtool   git gcc gcc-c++ make cmake openssl openssl-devel ncurses-devel zlib zlib-devel   bzip2 bzip2-devel bzip2-libs readline readline-devel bison zip unzip tar tcl java-1.8.0*   bison* ncurses*3.3 安装Maven下载并安装到指定目录(如/opt/tools/installed):wget https://archive.apache.org/dist/maven/maven-3/3.5.4/binaries/apache-maven-3.5.4-bin.tar.gztar -zxf apache-maven-3.5.4-bin.tar.gzmv apache-maven-3.5.4 /opt/tools/installed/修改maven环境变量,在/etc/profile文件末尾增加下面高亮代码:JAVA_HOME=/opt/tools/installed/jdk8u191-b12M2_HOME=/opt/tools/installed/apache-maven-3.5.4PATH=$M2_HOME/bin:$JAVA_HOME/bin:$PATHexport M2_HOME   JAVA_HOME PATH运行下面的命令,是修改的环境变量生效:source /etc/profile修改maven配置文件中的:本地仓路径、远程仓等:配置文件路径:/opt/tools/installed/apache-maven-3.5.4/conf/settings.xml本地仓库配置:(可选,可保持默认)<!--默认在“~/.m2/”目录下,可以按下行格式修改成你自己想保存的目录--><localRepository>/path/to/local/repo</localRepository>远程仓库配置:(可选,默认用maven2官方远程仓但访问慢,建议用国内maven仓)<!--修改成自己搭建的maven仓库,如果没有,可以使用下面的华为开源maven仓 --><mirror>  <id> huaweimaven</id>  <name> huaweicloud maven</name>  <url> https://mirrors.huaweicloud.com/repository/maven/</url>  <mirrorOf>central</mirrorOf>   </mirror>配置代理:(可选,外网环境下不用配置maven的代理)  <proxies>   <proxy>        <id>optional</id>        <active>true</active>        <protocol>http</protocol>      <username>用户名</username>      <password>密码</password>      <host>代理服务器网址</host>      <port>代理服务器端口</port>        <nonProxyHosts>local.net|some.host.com</nonProxyHosts>    </proxy>  </proxies>3.4 对gcc、g++和c++增加-fsigned-char选项1、对gcc增加-fsigned-char选项1)使用which gcc命令寻找gcc所在路径(一般位于/usr/bin/gcc)which gcc2)、更改gcc的名字(比如改成gcc-arm)mv /usr/bin/gcc   /usr/bin/gcc-arm3)、进入gcc所在目录执行vi gcc,并填入如下内容保存:#! /bin/sh /usr/bin/gcc-arm -fsigned-char "$@"cd /usr/bin/vi gcc4)、执行chmod +x gcc给脚本添加执行权限chmod +x gcc2、对g++增加-fsigned-char选项1)使用which g++命令寻找g++所在路径(一般位于/usr/bin/g++)which g++2)、更改g++的名字(比如改成g++-arm)mv /usr/bin/g++   /usr/bin/g++-arm3)、进入g++所在目录执行vi g++,并填入如下内容保存:#! /bin/sh /usr/bin/g++-arm -fsigned-char "$@"cd /usr/bin/vi g++4)、执行chmod +x g++给脚本添加执行权限chmod +x g++3、对c++增加-fsigned-char选项1)使用which c++命令寻找g++所在路径(一般位于/usr/bin/c++)which c++2)、更改c++的名字(比如改成c++-arm)mv /usr/bin/c++   /usr/bin/c++-arm3)、进入c++所在目录执行vi c++,并填入如下内容保存:#! /bin/sh /usr/bin/c++-arm -fsigned-char "$@"cd /usr/bin/vi c++4)、执行chmod +x c++给脚本添加执行权限chmod +x c++3.5 安装Protoc下载并解压源码:wget   https://github.com/protocolbuffers/protobuf/releases/download/v2.5.0/protobuf-2.5.0.tar.gztar   -zxf protobuf-2.5.0.tar.gzcd   protobuf-2.5.0修改autogen.sh文件的第20-24行:vi   autogen.sh注释如下红框内注释内容并增加如下:curl -L   https://github.com/google/googletest/archive/release-1.5.0.tar.gz | tar zxmv googletest-release-1.5.0 gtest打ARM补丁:cp   protoc.patch ./src/google/protobuf/stubs/cd   ./src/google/protobuf/stubs/patch   -p1 < protoc.patchcd   -注:proctoc ARM补丁为protoc.patch.rar(从附件中解压获取);        编译并安装到系统默认目录:./autogen.sh   && ./configure CFLAGS='-fsigned-char' && make && make   install3.6 编译安装Snappy 1.1.3下载并解压源码:wget   https://github.com/google/snappy/releases/download/1.1.3/snappy-1.1.3.tar.gztar   zxvf snappy-1.1.3.tar.gzcd   snappy-1.1.3/执行./configure进行编译配置:./configure        执行make进行编译:make   -j32        执行make install编译安装:make   install查看编译后的结果:cd   /usr/local/lib3.7 编译安装Hadoop-Snappy通过git clone下载源码:git   clone https://github.com/electrum/hadoop-snappy.git修改src/main/native/Makefile.am文件:vi   src/main/native/Makefile.am根据如果红框内的内容进行修改         执行mvn package进行编译:mvn   package         查看编译后的jar文件:cd   target/hadoop-snappy-0.0.1-SNAPSHOT-tar/hadoop-snappy-0.0.1-SNAPSHOT/lib【注】:hadoop-snappy-0.0.1-SNAPSHOT.jar文件在hadoop-2.6.0-cdh5.15.1编译完成后,需将该文件拷贝到$HADOOP_HOME/lib库目录下;3.8 安装ant编译软件1、下载ant开源软件包wget   http://mirror.bit.edu.cn/apache//ant/binaries/apache-ant-1.9.14-bin.tar.gz        2、解压apache-ant-1.9.14-bin.tar.gztar zxvf apache-ant-1.9.14-bin.tar.gz3、进入解压路径cd apache-ant-1.9.14/4、将ANT_HOME配置到/etc/profile环境变量中vi /etc/proflile 文件最后增加如下内容export ANT_HOME=/home/ant/apache-ant-1.9.14export PATH=$PATH:$ANT_HOME/bin        5、使ANT_HOME环境变量生效source /etc/proflile  4 软件移植分析1、使用checkSo工具(获取地址:https://bbs.huaweicloud.com/forum/thread-22679-1-1.html)检查hbase-1.2.0-cdh5.15.1对应x86的安装包或源码包是否有依赖x86的so文件,通过检查hbase-1.2.0-cdh5.15.1的源码hbase-1.2.0-cdh5.15.1-src.tar.gz没有发现有依赖的x86架构的so文件。  5 依赖库编译5.1 编译snappy-java-1.0.4.1.jarSnappy是Google开源的压缩/解压缩库,snappy-java封装了其接口1)从github网站下载源码并解压wget https://codeload.github.com/xerial/snappy-java/tar.gz/snappy-java-1.0.4.1mv snappy-java-1.0.4.1   snappy-java-1.0.4.1.tar.gztar -xzvf snappy-java-1.0.4.1.tar.gzcd snappy-java-snappy-java-1.0.4.1        2)修改Makefile文件中snappy源码的下载路径:vi Makefile【注】因为默认的路径已经失效,需要如下使用新的下载路径:http://repository.timesys.com/buildsources/s/snappy/snappy-1.0.4/snappy-1.0.4.tar.gz3)安装libstdc++-static-4.8.5-28.el7.ns7.02.aarch64.rpm和glibc-static-2.17-222.el7.ns7.01.aarch64.rpmwget http://download.cs2c.com.cn/neokylin/desktop/everything/7.0/aarch64/os/Packages/libstdc++-static-4.8.5-28.el7.ns7.02.aarch64.rpmrpm -ivh   libstdc++-static-4.8.5-28.el7.ns7.02.aarch64.rpmwget http://download.cs2c.com.cn/neokylin/desktop/everything/7.0/aarch64/os/Packages/glibc-static-2.17-222.el7.ns7.01.aarch64.rpmrpm -ivh   glibc-static-2.17-222.el7.ns7.01.aarch64.rpm4)执行make编译并查看编译后的snappy-java-1.0.4.1.jarmakecd   target/5)将编译后的snappy-java-1.0.4.1.jar覆盖到本地maven仓对应路径cp   snappy-java-1.0.4.1.jar   /root/.m2/repository/org/xerial/snappy/snappy-java/1.0.4.1/5.2 编译leveldbjni-all-1.8.jarLeveldb是一个google实现的非常高效的kv数据库;官方链接:https://github.com/google/leveldb依据网上资料,编译leveldbjni-all-1.8.jar,需要先将leveldb和snappy编译成静态库,再将两个静态库编译进leveldbjni.so里面,最后生成leveldbjni-all-1.8.jar压缩包。注:如下编译snappy-1.1.3、leveldb-1.20和leveldbjni需要在同一个ssh窗口执行,切换ssh会导致如下临时定义的SNAPPY_HOME和LEVELDB_HOME变量失效,如发生ssh窗口异常,编译leveldbjni时需要先定义临时SNAPPY_HOME和LEVELDB_HOME变量(变量路径要正确);5.2.1 编译snappy-1.1.3wget https://github.com/google/snappy/archive/1.1.3.tar.gztar   -zxvf 1.1.3.tar.gzcd   snappy-1.1.3/./autogen.sh./configure   --with-picmake   -j20export   SNAPPY_HOME=`pwd`cp   .libs/libsnappy.a .5.2.2 编译leveldb-1.201)源码下载并解压wget https://github.com/google/leveldb/archive/v1.20.tar.gztar   -zxvf v1.20.tar.gzcd   leveldb-1.20        2)修改build_detect_platformvi   build_detect_platform 注释如下红框内的3行注释内容,并添加如下三行:echo   "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS $PLATFORM_SHARED_CFLAGS"   >> $OUTPUTecho   "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS $PLATFORM_SHARED_CFLAGS"   >> $OUTPUTecho   "PLATFORM_SHARED_CFLAGS=" >> $OUTPUT3)修改Makefile,增加-fPIC的编译选项vi   Makefile增加-fPIC4)对比附件补丁leveldbpatch.zip,将代码合入(替换源码压缩包对应路径中的文件即可):5)执行编译make   -j20export   LEVELDB_HOME=`pwd`cp   out-static/libleveldb.a . 5.2.3 编译leveldbjni1)通过git获取源码git   clone https://github.com/fusesource/leveldbjni.gitcd   leveldbjniexport   LEVELDBJNI_HOME=`pwd`        2)修改pom.xmlvi   pom.xml 注释如下红框内注释内容,并增加如下两行    <module>leveldbjni-linux64</module>      <module>leveldbjni-all</module>3)修改leveldbjni-all/pom.xml文件vi   leveldbjni-all/pom.xml 注释如下红框内注释内容,并按红框内框内容进行修改4)修改所有pom.xml文件中的版本号将所有pom.xml文件中的版本“99-master-SNAPSHOT”改为“1.8”:sed -i   's/99-master-SNAPSHOT/1.8/g' `find . -name pom.xml`5)编译选项增加 -fsigned-charvim leveldbjni/src/main/native-package/Makefile.in增加-fsigned-char6)修改automake版本号vi   leveldbjni/src/main/native-package/aclocal.m4vi   leveldbjni/src/main/native-package/configure把automake版本号从1.14改成1.13,注意不要改成1.13.4(根据系统安装automake版本号进行修改)7)执行maven编译并查看编译结果export   LIBRARY_PATH=${SNAPPY_HOME};export C_INCLUDE_PATH=${LIBRARY_PATH};export   CPLUS_INCLUDE_PATH=${LIBRARY_PATH}mvn   clean package -P download -P linux64-aarch64 –DskipTestscd   leveldbjni-all/target/注:执行maven编译会自动编译五个模块:leveldbjni-project、leveldbjni、leveldbjni-linux64、leveldbjni-linux64-aarch64、leveldbjni-all;8)将编译后的leveldbjni-all-1.8.jar复制到本地maven仓对应路径进行覆盖cp   leveldbjni-all-1.8.jar   /root/.m2/repository/org/fusesource/leveldbjni/leveldbjni-all/1.8/5.3 编译netty-all-4.0.23.Final.jar编译依赖关系:netty-4.0.23.Final à netty-tcnative-1.1.30.Fork2 à apr-1.5.2将编译生成的netty-tcnative-1.1.30.Fork2.jar拷贝到maven本地仓库,然后编译netty-all-4.0.23.Final.jar 1)下载apr-1.5.2源码,并解压wget https://archive.apache.org/dist/apr/apr-1.5.2.tar.gztar   zxvf apr-1.5.2.tar.gzcd apr-1.5.2/        2)编译apr-1.5.2并查看编译结果./configuremakemake   install3)下载netty-tcnative-1.1.30.Fork2源码,并解压进入解压路径wget   https://codeload.github.com/netty/netty-tcnative/tar.gz/netty-tcnative-1.1.30.Fork2mv   netty-tcnative-1.1.30.Fork2 netty-tcnative-1.1.30.Fork2.tar.gztar   zxvf netty-tcnative-1.1.30.Fork2.tar.gzcd   netty-tcnative-netty-tcnative-1.1.30.Fork2/        4)修改pom.xml vi pom.xml 增加如下内容              <configureArgs>                  <configureArg>CFLAGS=-fsigned-char</configureArg>              </configureArgs>5)编译netty-tcnative-1.1.30.Fork2mvn   install注:执行mvn install编译安装会直接替换本地maven仓中的netty-tcnative-1.1.30.Fork2-linux-aarch_64.jar6)下载netty-4.0.23.Final源码,并解压进入解压目录wget   https://github.com/netty/netty/archive/netty-4.0.23.Final.tar.gztar   zxvf netty-4.0.23.Final.tar.gzcd   netty-netty-4.0.23.Final/        7)修改transport-native-epoll/pom.xmlvi transport-native-epoll/pom.xml 增加如下内容              <configureArgs>                  <configureArg>CFLAGS=-fsigned-char</configureArg>              </configureArgs>8)使用maven编译并查看编译结果mvn   package -DskipTestscd all/target/9)将编译后的netty-all-4.0.23.Final.jar拷贝到本地maven仓对应路径cp   netty-all-4.0.23.Final.jar   /root/.m2/repository/io/netty/netty-all/4.0.23.Final/ 5.4 编译jruby-cloudera-1.0.0.jar5.4.1 编译libjruby-cext.solibjruby-cext.so包含在jruby-complete.jar中,需要先编译jruby-complete.jar,先在x86服务器上编译,然后返回arm服务器继续编译;1、在x86服务器上编译1)从github网站下载jruby-1.6.8.tar.gz源码并解压wget   https://github.com/jruby/jruby/archive/1.6.8.tar.gztar zxvf 1.6.8.tar.gzcd jruby-1.6.8/        2)打补丁(见附件jruby-complete-1.6.8-01.rar,解压后获得jruby-complete-1.6.8-01.patch)patch -p0 <   jruby-complete-1.6.8-01.patch检查打补丁是否跟patch内容一致:vi build.xmlvi   cext/src/Makefilevi   maven/jruby-complete/pom.xmlvi maven/jruby-core/pom.xmlvi   maven/jruby/pom.xmlvi maven/pom.xmlvi pom.xml3)在jruby-1.6.8.tar.gz源码解压路径创建jffi-native文件夹,下载jffi-1.2.14-native.jarmkdir jffi-nativecd jffi-native/wget   http://repo1.maven.org/maven2/com/github/jnr/jffi/1.2.14/jffi-1.2.14-native.jarjar xvf   jffi-1.2.14-native.jarcd jni/4)删除里面除了aarch64-Linux目录外的所有目录rm -rf   arm* D* i* p* s* x*5)重新打包jffi-aarch64_Linux.jarjar   -cvf jffi-aarch64_Linux.jar aarch64-Linux/6)将jffi-aarch64_Linux.jar添加到jruby-1.6.8的build_lib路径中,然后执行ant编译cp jffi-aarch64_Linux.jar   ../../build_lib/cd ../../ant7)回上层路径将整个jruby-1.6.8目录打包cd ../tar   zcvf jruby-1.6.8.tar.gz jruby-1.6.88)将打包后jruby-1.6.8.tar.gz传到arm服务器继续编译2、在arm服务器上编译1)解压从x86编译后的jruby-1.6.8.tar.gz并进入解压路径tar   zxvf jruby-1.6.8.tar.gzcd jruby-1.6.8/2)编译extant   cext3)编译jar-jruby-completeant   jar-jruby-complete4)进入lib路径,解压jruby-complete.jar并进入解压后的cext/native/路径cd   lib/jar   xvf jruby-complete.jarcd   cext/native/5)进入路径cd   aarch64-Linux/6)查看编译后的libjruby-cext.so是否为aarch64readelf   -h libjruby-cext.so | grep -i machine 5.4.2 编译libjffi-1.0.so1)改用已经有aarch64的jffi-1.2.14-native.jar中的libjffi-1.2.so打包到jruby-cloudera-1.0.0.jar中,进入本地maven仓jruby-cloudera-1.0.0.jar所在路径并解压jruby-cloudera-1.0.0.jarcd /root/.m2/repository/org/jruby/jruby-cloudera/1.0.0/mkdir testcp jruby-cloudera-1.0.0.jar   test/cd test/jar xvf jruby-cloudera-1.0.0.jar2)下载jffi-1.2.14-native.jar并解压mkdir -p   /home/test/libjfficd /home/test/libjffi/wget   http://repo1.maven.org/maven2/com/github/jnr/jffi/1.2.14/jffi-1.2.14-native.jarjar xvf   jffi-1.2.14-native.jar3)将libjffi-1.2.so拷贝到/root/.m2/repository/org/jruby/jruby-cloudera/1.0.0/test/jni/aarch64-Linux/路径下cp jni/aarch64-Linux/libjffi-1.2.so   /root/.m2/repository/org/jruby/jruby-cloudera/1.0.0/test/jni/aarch64-Linux/cd /root/.m2/repository/org/jruby/jruby-cloudera/1.0.0/test/jni/aarch64-Linux/4)删除libjffi-1.0.sorm -rf   libjffi-1.0.so5)返回/root/.m2/repository/org/jruby/jruby-cloudera/1.0.0/test路径,压缩jruby-cloudera-1.0.0.jar并将其拷贝到/root/.m2/repository/org/jruby/jruby-cloudera/1.0.0路径下cd ../../jar   cvf jruby-cloudera-1.0.0.jar builtin cext com jay jline jni jnr jruby   META-INF org YechtService.cp   jruby-cloudera-1.0.0.jar ../6 Hbase-1.2.0-CDH5.15.1编译6.1 下载源码下载代码并解压:wget https://archive.cloudera.com/cdh5/cdh/5/hbase-1.2.0-cdh5.15.1-src.tar.gztar -zxvf hbase-1.2.0-cdh5.15.1-src.tar.gz6.2 打patch补丁进入hbase源码解压目录:cd hbase-1.2.0-cdh5.15.1/在解压路径执行如下命令打如下附件patch补丁(也可通过在编译环境执行wget https://issues.apache.org/jira/secure/attachment/12899868/HBASE-19188.branch-1.2.002.patch获取):export   MAVEN_OPTS="-Xms1024m -Xmx10G -XX:PermSize=4096m"yum install patchpatch -p1 <   HBASE-19188.branch-1.2.002.patch注:附件patch补丁名为HBASE-19188.branch-1.2.002.patch.rar6.3 执行编译         修改pom.xml中findbugs-maven-plugin的版本号(从3.0.0改为3.0.4):vim pom.xml将版本号从3.0.0改为3.0.4修改pom.xml,注释check-jar-contents相关内容:vim pom.xml注释如下红框内容执行编译并查看编译后的结果(每次编译前需要指定内存大小):export MAVEN_OPTS="-Xms1024m -Xmx12G   -XX:PermSize=4096m"mvn clean install assembly:single -DskipTests -Prelease,security,native,hadoop-snappy -Drat.numUnapprovedLicenses=200 -Dhadoop.profile=2.0 -Dhadoop-snappy.version=0.0.1-SNAPSHOTcd hbase-assembly/target/6.4 注意点    1)编译过程中遇到问题可以参考9 FAQ    2)第一次编译的时候会从远程maven仓库下载jar包到本地仓库,但是有几个jar包是X86的,所以在hbase编译完成及第5章的jar包编译完成后,需要将第5章编译的jar包替换掉本地仓库中相应路径的jar包,然后重新编译一次hbase。第二次编译会很快,所以不用担心。 7 验证1、编译验证使用checkSo工具(获取地址:https://bbs.huaweicloud.com/forum/thread-22679-1-1.html)检查编译后的hbase-assembly/target/hbase-1.2.0-cdh5.15.1-bin.tar.gz中是否不再含有依赖的x86架构的so文件,检查方法参考工具中的 《CheckSo使用说明.docx》,如果还有依赖的x86架构的so文件,则需要继续完成对应jar包的编译,直到无依赖的x86架构的so文件后,再次编译该组件并通过checkSo工具检查确认,编译后的组件包不再有依赖的x86架构的so文件则表明编译成功。        通过checkSo工具检查hbase-assembly/target/路径下编译后的hbase-1.2.0-cdh5.15.1-bin.tar.gz发现存在如下依赖的so文件:        上图依赖库的编译见 5 依赖库编译 章节(需要编译jruby-cloudera-1.0.0.jar、leveldbjni-all-1.8.jar、netty-all-4.0.23.Final.jar、snappy-java-1.0.4.1.jar),完成依赖库编译后需要重新编译前面编译包含依赖库的hbase-1.2.0-cdh5.15.1-bin.tar.gz,直到编译后的hbase-1.2.0-cdh5.15.1-bin.tar.gz通过checkSo工具检查不再有依赖so等文件;2、功能验证暂无。 8 参考信息http://archive.cloudera.com/cdh5/cdh/5/hbase/https://hbase.apache.org/ 9 FAQ9.1 git clone报证书错误9.1.1 问题现象9.1.2 解决方法git config --global http."sslVerify" false9.2 wget下载https链接报证书错误9.2.1 问题现象9.2.2 解决方法在下载命令后面跟参数--no-check-certificate9.3 编译leveldbjni报automake命令找不到9.3.1 问题现象9.3.2 解决方法没有安装automake-1.14,可以使用yum install automake安装。如果yum源上找的没有1.14的版本,则需要修改leveldbjni-linux64/target/native-build下的配置文件。修改leveldbjni/src/main/native-package/configure和leveldbjni/src/main/native-package/aclocal.m4,将里面的1.14改成服务器上安装的automake版本,比如1.13。9.4 编译leveldbjni时error: required file 'autotools/compile' not found9.4.1 问题现象9.4.2 解决方法根据问题信息,需要手动进入相应目录,手动执行相应命令安装。cd leveldbjni-linux64/target/native-buildautomake   --add-missing9.5 hbase编译过程报“Can't find bundle for base name org.apache.jasper.resources.LocalStrings“错误9.5.1 问题现象执行“mvn package -DskipTests assembly:single”编译hbase-1.3.0-src.tar.gz时报“Can't find bundle for base name org.apache.jasper.resources.LocalStrings, locale en_US”错误;9.5.2 解决方法需要打HBASE-19188.branch-1.2.002.patch补丁,步骤如下:1、在hbase-1.3.0-src.tar.gz解压路径执行“wget https://issues.apache.org/jira/secure/attachment/12899868/HBASE-19188.branch-1.2.002.patch”获取patch补丁2、执行“patch -p1 < HBASE-19188.branch-1.2.002.patch”打pathch补丁;3、打完patch补丁后执行“mvn clean package -DskipTests assembly:single”继续编译;9.6 hbase编译过程报“Cannot assign configuration entry ‘pluginArtifacts’ with value ‘${plugin.artifacts}’ of type “错误9.6.1 问题现象9.6.2 解决方法将pom.xml中的findbugs-maven-plugin的版本从3.0.0改为3.0.4。9.7 hbase编译过程报“Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.2:exec (check-jar-contents) on project hbase-shaded-check-invariants: Command execution failed.: Process exited with an error: 1(Exit value: 1) “错误9.7.1 问题现象9.7.2 解决方法修改pom.xml注释如下红框部分。9.8 hbase编译过程报报“[Help 1] http://cwiki.apace.org/confluence/display/MAVEN/OutofMemoryError“错误9.8.1 问题现象9.8.2 解决方法编译过程报内存不足,则每次maven编译前指定java内存大小:export MAVEN_OPTS="-Xms1024m -Xmx12G -XX:PermSize=4096m"   【来自转载】
总条数:138 到第
上滑加载中