Phoenix查询测试经验总结

作者: Jeffbond | 来源:发表于2016-11-29 12:29 被阅读0次

    1. 背景

    适当的索引能够让极大提升查询速度,因此在Phoenix查询的测试用例中包括了对有索引跟无索引的查询性能的比较。测试过程中遇到一些问题,在此记录下来。

    2. 问题及解决

    2.1. 创建索引时报错,报错如下:

    //创建索引语句:
    0: jdbc:phoenix:localhost> CREATE INDEX ind_1 ON TESTINPUT(ff1);
    
    //报错:
    Error: ERROR 1029 (42Y88): Mutable secondary indexes must have the hbase.regionserver.wal.codec property set to org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec in the hbase-sites.xml of every region server tableName=IND_1 (state=42Y88,code=1029)
    java.sql.SQLException: ERROR 1029 (42Y88): Mutable secondary indexes must have the hbase.regionserver.wal.codec property set to org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec in the hbase-sites.xml of every region server tableName=IND_1
        at org.apache.phoenix.exception.SQLExceptionCode$Factory$1.newException(SQLExceptionCode.java:396)
        at org.apache.phoenix.exception.SQLExceptionInfo.buildException(SQLExceptionInfo.java:145)
        at org.apache.phoenix.schema.MetaDataClient.createIndex(MetaDataClient.java:1162)
        at org.apache.phoenix.compile.CreateIndexCompiler$1.execute(CreateIndexCompiler.java:95)
        at org.apache.phoenix.jdbc.PhoenixStatement$2.call(PhoenixStatement.java:322)
        at org.apache.phoenix.jdbc.PhoenixStatement$2.call(PhoenixStatement.java:314)
        at org.apache.phoenix.call.CallRunner.run(CallRunner.java:53)
        at org.apache.phoenix.jdbc.PhoenixStatement.executeMutation(PhoenixStatement.java:312)
        at org.apache.phoenix.jdbc.PhoenixStatement.execute(PhoenixStatement.java:1435)
        at sqlline.Commands.execute(Commands.java:822)
        at sqlline.Commands.sql(Commands.java:732)
        at sqlline.SqlLine.dispatch(SqlLine.java:808)
        at sqlline.SqlLine.begin(SqlLine.java:681)
        at sqlline.SqlLine.start(SqlLine.java:398)
        at sqlline.SqlLine.main(SqlLine.java:292)
    
    • 原因:Phoenix支持两种索引:可变索引跟不可变索引。在可变表上建的索引是可变索引,在不可变表上建的索引是不可变索引。可变索引是指插入或删除数据的时候会同时更新索引;不可变索引适用于只写入一次不再更改的表,索引只建立一次,再插入数据不会更新索引。上面使用的语句是创建可变索引,需要在hbase-site.xml中进行相关配置使其支持可变索引(不可变索引无需另外配置,默认支持)。

    • 解决:对HMaster和HRegionserver节点分别增加配置,然后重启HBase集群

      • HMaster
      <property>
        <name>hbase.regionserver.wal.codec</name>
        <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
      </property>
      <property>
       <name>hbase.master.loadbalancer.class</name>
       <value>org.apache.phoenix.hbase.index.balancer.IndexLoadBalancer</value>
      </property>
      <property>
       <name>hbase.coprocessor.master.classes</name>
       <value>org.apache.phoenix.hbase.index.master.IndexMasterObserver</value>
      

    </property>

     - HRegionserver
    
    

    <property>
    <name>hbase.regionserver.wal.codec</name>
    <value>org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec</value>
    </property>
    <property>
    <name>hbase.region.server.rpc.scheduler.factory.class</name>
    <value>org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory</value>
    <description>Factory to create the Phoenix RPC Scheduler that usesseparate queues for index and metadata updates</description>
    </property>
    <property>
    <name>hbase.rpc.controllerfactory.class</name>
    <value>org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory</value>
    <description>Factory to create the Phoenix RPCScheduler that uses separate queues for index and metadataupdates</description>
    </property>
    <property>
    <name>hbase.coprocessor.regionserver.classes</name>
    <value>org.apache.hadoop.hbase.regionserver.LocalIndexMerger</value>
    </property>

    
    ### 2.2. 对10亿数据查询时,报错如下:
    
    

    16/11/29 10:33:50 WARN client.ScannerCallable: Ignore, probably already closed
    org.apache.hadoop.hbase.regionserver.LeaseException: org.apache.hadoop.hbase.regionserver.LeaseException: lease '1132' does not exist
    at org.apache.hadoop.hbase.regionserver.Leases.removeLease(Leases.java:221)
    at org.apache.hadoop.hbase.regionserver.Leases.cancelLease(Leases.java:206)

    ...

    org.apache.phoenix.exception.PhoenixIOException: org.apache.phoenix.exception.PhoenixIOException: Failed after attempts=36, exceptions:
    Tue Nov 29 10:33:50 CST 2016, null, java.net.SocketTimeoutException: callTimeout=60000, callDuration=60321: row '��s,d' on table 'TEST11' at region=TEST11,\x11\x00\x00\x00\x00\x00\x00\x00\x00,1479985615575.c3adb68acea8d88d223bffd3acc16c2e., hostname=node-20-105,60020,1480385981798, seqNum=1244662

    ...

    Caused by: org.apache.hadoop.hbase.ipc.CallTimeoutException: Call id=18173, waitTime=60001, operationTimeout=60000 expired.
    at org.apache.hadoop.hbase.ipc.Call.checkAndSetTimeout(Call.java:70)
    at org.apache.hadoop.hbase.ipc.RpcClientImpl.call(RpcClientImpl.java:1197)
    ...

    
    - 原因:
    
    某些查询需要很长时间才能返回结果,被HBase的超时机制杀掉了。
    
    - 思路:
    
    增大超时时间,在hbase-site.xml里增加了如下配置:
    
    

    <property>
    <name>hbase.rpc.timeout</name>
    <value>600000</value>
    </property>

    <property>
    <name>hbase.client.operation.timeout</name>
    <value>600000</value>
    </property>

    <property>
    <name>hbase.client.scanner.timeout.period</name>
    <value>600000</value>
    </property>

    <property>
    <name>hbase.regionserver.lease.period</name>
    <value>600000</value>
    </property>

    <property>
    <name>phoenix.query.timeoutMs</name>
    <value>600000</value>
    </property>

    <property>
    <name>phoenix.query.keepAliveMs</name>
    <value>600000</value>
    </property>

    <property>
    <name>hbase.client.ipc.pool.type</name>
    <value>RoundRobinPool</value>
    </property>
    <property>
    <name>hbase.client.ipc.pool.size</name>
    <value>10</value>
    </property>

    
    最终虽然配置生效了,但是还是报同样的错。已经将网上说的可能的配置项都配了还是无法解决超时问题。等增加了机器,查询时间变短,10亿数据的查询应该就没有超时问题了。
    
    
    
    ## 3. 特性
    
    - 不可变索引默认支持,不需要另外配置;可变索引需要如上添加配置才能支持
    - 创建不可变表:
    

    CREATE TABLE TABLENAME (pk long PRIMARY KEY,col1 int) IMMUTABLE_ROWS=true;

    - 创建索引有以下几种方式:
    

    CREATE INDEX ind_name ON TABLENAME(COLUMN1);
    CREATE INDEX ind_name ON TABLENAME(COLUMN1,COLUMN2);
    CREATE INDEX ind_name ON TABLENAME(COLUMN1) INCLUDE(COLUMN2);

    - 执行查询的时候,Phoenix查询优化器将选择合适的索引。可以使用explain plan进行查看
    

    0: jdbc:phoenix:localhost> explain select ff3,if1 from testinput where ff3 >= 0.7 and ff3 < 0.9 order by if1;
    +------------------------------------------+
    | PLAN |
    +------------------------------------------+
    | CLIENT 1-CHUNK PARALLEL 1-WAY RANGE SCAN OVER IND_4 [0.7] - [0.9] |
    | SERVER SORTED BY ["IF1"] |
    | CLIENT MERGE SORT |
    +------------------------------------------+

    - 除非所有查询使用的列被索引或者覆盖列,否则二级索引不会被使用
    - 建索引的时候不要包括primary key,否则索引不会被使用;可以单独对primary key建索引
    - where条件里有primary key的时候会使用Range Scan,因为表本来就是按照primary key的顺序排列的
    - primary key在插入时是自动排序的,插入完成后primary key保持有序(如果该表只有一个分区,则全局有序;如果有多个分区,则在每个分区内部有序,并非全局有序)
    - 对某几个(1个或多个)列建索引,则会生成一张索引表,该表由创建索引的这几个列组成,并在最后一列添加primary key列。也就是说索引表也是一张表,只不过该表列数比原表少。
    - 索引表的第一列是有序的
    - upsert into一个跟之前一样的primary key,会将之前那个primary key的记录替换成新的。
    - phoenix虽然不支持update语句,但是可以用upsert into tablename(id,columnname) values(id,newvalue)来实现同样的功能。
    - local index 对应的索引表的分区跟表的分区在同一个region server上(索引表分区数必须跟表分区数一样)
    - global index 对应的索引表的分区跟表的分区不一定在同一个region server上(索引表分区数必须跟表分区数一样)
    - 对一张表建了多个local index,对于HBase来讲,其实只存了一张索引表。但是global index则不同。
    
    ## 4. 参考资料
    - https://github.com/forcedotcom/phoenix/wiki/Secondary-Indexing
    - http://phoenix.apache.org/language/index.html#create_index
    - http://blog.csdn.net/jiangshouzhuang/article/details/52387718
    
    
    ![FullStackPlan](https://img.haomeiwen.com/i1752522/2e4b0e5141927479.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    欢迎关注公众号: FullStackPlan 获取更多干货哦~
    

    相关文章

      网友评论

        本文标题:Phoenix查询测试经验总结

        本文链接:https://www.haomeiwen.com/subject/gdtouttx.html