Springboot 系列 (25) - Springboot+HBase 大数据存储(三)| HBase Shell,HBase REST 服务 和 Phoenix 组件

发布时间 2023-03-26 19:14:46作者: 垄山小站


在 “Springboot 系列 (24) - Springboot+HBase 大数据存储(二)| 安装配置 Apache HBase 和 Apache Zookeeper” 里我们安装配置了 Apache HBase 和 Apache Zookeeper,本文将介绍 HBase Shell,HBase REST 服务 和 Phoenix 组件。


HBase Shell

HBase Shell 是 HBase 的一套命令行工具,可以使用 shell 命令在 HBase 所在的本机上查询/操作 HBase 的数据。

HBase Shell 相关文档:https://hbase.apache.org/book.html#shell


HBase REST 服务

REST ( Representational State Transfer ) 于 2000 年在 HTTP 规范的主要作者之一 Roy Fielding 的博士论文中引入。

REST 允许通过与 URL 本身绑定的 API 进行客户端 ~ 服务器交互。配置和运行 HBase 附带的 REST 服务器,该服务器将 HBase 表、行、单元格和元数据公开为 URL 指定的资源。

HBase 附带的 REST 服务器可以作为守护进程运行,该守护进程启动嵌入式 Jetty servlet 容器并将 servlet 部署到其中。

HBase REST 相关文档:https://hbase.apache.org/book.html#_rest


Phoenix 组件

Phoenix 是 HBase 的开源 SQL 皮肤。通过 Phoenix 可以使用标准 JDBC API 代替 HBase 客户端 API 来创建表,插入数据和查询 HBase 数据。

Phoenix 会把 SQL 编译成一系列的 Hbase 的 scan 操作,然后把 scan 结果生成标准的 JDBC 结果集,其底层由于使用了 Hbase 的API,协处理器,过滤器。Phoenix 支持的操作:SELECT, FROM、WHERE、GROUP BY、HAVING、ORDER BY 等。

Phoenix 其实就是一个客户端,它处于应用程序和 HBase 之间。Phoenix 客户端分为两种:

    (1) 瘦客户端:将用户写好的 SQL 转交给 Phoenix Query 服务,由 Phoenix Query 服务把 SQL 解析成对应的HBase 操作,并交给 HBase 执行,执行完成之后并负责把结果收集回来,并转换成二维表格返回给用户。Phoenix Query 服务只针对瘦客户端。Phoenix Query 服务需要放到 HBase 的 RegionServer 里面。

    (2) 胖客户端:不需要依赖 Phoenix Query 服务,客户端本身就可以完成 SQL 的解析和提交操作(连接 Zookeeper)。
建议用胖客户端,少一个需要维护的服务。

Phoenix 与 HBase 连接后会自动创建这些系统表:SYSTEM.CATALOG、SYSTEM.CHILD_LINK、SYSTEM.FUNCTION、SYSTEM.LOG、SYSTEM.MUTEX、SYSTEM.SEQUENCE、SYSTEM.STATS、SYSTEM.TASK,其中 SYSTEM.CATALOG 表用于存放 Phoenix 创建表时的元数据。

Phoenix 创建表时会自动调用 HBase 客户端创建相应的表,并且在 SYSTEM.CATALOG 系统表中记录 Phoenix 创建表时的元数据,其主键的值对应 HBase 的 RowKey,非主键的列对应 HBase 的Column(列族不指定时为0,且列会进行编码)。

通过 Phoenix 创建的表,必须通过 Phoenix 客户端来对表进行操作,因为通过 Phoenix 创建的表其非主键的列会进行编码。

Phoenix 的 SQL 中如果表名、字段名不使用双引号标注那么默认转换成大写,Phoenix 中的字符串使用单引号进行标注。

在 Phoenix 中,默认情况下,库名,表名,字段名等会自动转换为大写,若要小写,使用双引号,如 "ns1",要特别注意引号的使用方式。

Phoenix:https://phoenix.apache.org/

 

1. 系统环境

    操作系统:Ubuntu 20.04
    Java 版本:openjdk 11.0.18
    Hadoop 版本:3.2.2
    Zookeeper 版本:3.6.3

    HBase 版本:2.4.4
    HBase 所在路径:~/apps/hbase-2.4.4

    本文 HBase 在 HBase + Zookeeper (独立的) 模式下运行,Zookeeper 使用端口 2182。

 

2. HBase Shell

    1) 运行 Shell

        $ cd ~/apps

        $ ./hbase-2.4.4/bin/hbase shell

            hbase:001:0> help

                HBase Shell, version 2.4.4, r20e7ba45b0c3affdc0c06b1a0e5cbddd1b2d8d18, Mon Jun  7 15:31:55 PDT 2021
                Type 'help "COMMAND"', (e.g. 'help "get"' -- the quotes are necessary) for help on a specific command.
                Commands are grouped. Type 'help "COMMAND_GROUP"', (e.g. 'help "general"') for help on a command group.

                ...

            hbase:002:0> version

                2.4.4, r20e7ba45b0c3affdc0c06b1a0e5cbddd1b2d8d18, Mon Jun  7 15:31:55 PDT 2021
                Took 0.0002 seconds

            hbase:003:0> status

                1 active master, 0 backup masters, 1 servers, 0 dead, 1.0000 average load
                Took 0.4128 seconds


    2) Table 操作 

        # 查看所有表
        hbase:004:0> list       

            TABLE
            0 row(s)
            Took 0.3782 seconds
            => []

        # 创建 test 表,一个列族 base_info
        hbase:005:0> create 'test', 'base_info'

            Created table test
            Took 1.2217 seconds
            => Hbase::Table - test

        # 查看表描述信息
        hbase:006:0> describe 'test'

            Table test is ENABLED
            test
            COLUMN FAMILIES DESCRIPTION
            {NAME => 'base_info', BLOOMFILTER => 'ROW', IN_MEMORY => 'false', VERSIONS => '1', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODI
            NG => 'NONE', COMPRESSION => 'NONE', TTL => 'FOREVER', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION
            _SCOPE => '0'}

            1 row(s)
            Quota is disabled
            Took 0.1358 seconds

        # 添加 2 个列族
        hbase:007:0> alter 'test', 'adv_info', 'del_info'

            Updating all regions with the new schema...
            1/1 regions updated.
            Done.
            Took 2.3449 seconds

        # 删除 1 个列族
        hbase:008:0> alter 'test', {NAME => 'del_info', METHOD => 'delete'}
 
            Updating all regions with the new schema...
            1/1 regions updated.
            Done.
            Took 2.1434 seconds

        # 检查表是否存在
        hbase:009:0> exists 'demo'

            Table demo does not exist
            Took 0.0220 seconds
            => false

        # 使用 disable 禁用一个表
        hbase:010:0> disable 'test'

            Took 0.3985 seconds

        # 使用 is_enabled 查看一个表是否被禁用,也可以用 is_disabled 来查看
        hbase:011:0> is_enabled 'test'

            false
            Took 0.0143 seconds
            => false

        # 使用 enable 启用一个表
        hbase:010:0> enable 'test'

        # 删除一个表,删除前要先使用 disable 禁用这个表
        hbase:013:0> disable 'demo'
        hbase:014:0> drop 'demo'


    3) 添加/删除数据

        可以通过 put 命令来插入数据,上文如我们新建 test 表,它拥有二个列簇 base_info 和 adv_info。列簇下的列不需要提前创建,在需要时通过:来指定即可。

        # 添加数据
        hbase:015:0> put 'test', 'rowkey_1', 'base_info:name', 'Tom'
        hbase:016:0> put 'test', 'rowkey_1', 'base_info:age', '12'
        hbase:017:0> put 'test', 'rowkey_1', 'base_info:job', 'Student'

        hbase:018:0> put 'test', 'rowkey_2', 'base_info:name', 'Jerry'
        hbase:019:0> put 'test', 'rowkey_2', 'base_info:salary', '3000'
        hbase:020:0> put 'test', 'rowkey_2', 'base_info:job', 'Engineer'

        hbase:021:0> put 'test', 'rowkey_3', 'base_info:name', 'del_user'
        hbase:022:0> put 'test', 'rowkey_3', 'base_info:age', '20'
        hbase:023:0> put 'test', 'rowkey_3', 'base_info:salary', '5000'
        hbase:024:0> put 'test', 'rowkey_3', 'base_info:job', 'Art'

        hbase:025:0> get 'test', 'rowkey_3'

            COLUMN                            CELL
            base_info:age                    timestamp=2023-03-22T18:41:51.992, value=20
            base_info:job                    timestamp=2023-03-22T18:42:06.667, value=Art
            base_info:name                   timestamp=2023-03-22T18:41:43.650, value=del_user
            base_info:salary                 timestamp=2023-03-22T18:41:58.937, value=5000
            1 row(s)``
            Took 0.0077 seconds

        # 删除列/数据
        hbase:027:0> delete 'test','rowkey_3','base_info:job'
        hbase:028:0> get 'test', 'rowkey_3'

            COLUMN                            CELL
            base_info:age                    timestamp=2023-03-22T18:41:51.992, value=20
            base_info:name                   timestamp=2023-03-22T18:41:43.650, value=del_user
            base_info:salary                 timestamp=2023-03-22T18:41:58.937, value=5000
            1 row(s)
            Took 0.0099 seconds

        # 删除整行数据
        hbase:029:0> deleteall 'test', 'rowkey_3'
        hbase:030:0> get 'test', 'rowkey_3'

            COLUMN                            CELL
            0 row(s)
            Took 0.0046 seconds
        
        # 退出 Shell
        hbase:031:0> exit    # 或 quit


    4) 查询数据

        # 查询表中有多少行
        hbase:001:0> count 'test'

            2 row(s)
            Took 0.3769 seconds
            => 2

        # 获取一个列族的数据
        hbase:002:0> get 'test', 'rowkey_1', 'base_info'

            COLUMN                            CELL
            base_info:age                    timestamp=2023-03-22T18:31:00.415, value=12
            base_info:job                    timestamp=2023-03-22T18:31:08.839, value=Student
            base_info:name                   timestamp=2023-03-22T18:30:43.745, value=Tom
            1 row(s)
            Took 0.0126 seconds

        # 查询整表数据
        hbase:003:0> scan 'test'

            ROW                    COLUMN+CELL
            rowkey_1               column=base_info:age, timestamp=2023-03-22T18:31:00.415, value=12
            rowkey_1               column=base_info:job, timestamp=2023-03-22T18:31:08.839, value=Student
            rowkey_1               column=base_info:name, timestamp=2023-03-22T18:30:43.745, value=Tom
            rowkey_2               column=base_info:job, timestamp=2023-03-22T18:37:11.844, value=Engineer
            rowkey_2               column=base_info:name, timestamp=2023-03-22T18:36:31.967, value=Jerry
            rowkey_2               column=base_info:salary, timestamp=2023-03-22T18:36:39.804, value=3000
            2 row(s)
            Took 0.0142 seconds

        # 扫描一个列簇
        hbase:004:0> scan 'test', {COLUMN=>'base_info'}

            ROW                    COLUMN+CELL
            rowkey_1               column=base_info:age, timestamp=2023-03-22T18:31:00.415, value=12
            rowkey_1               column=base_info:job, timestamp=2023-03-22T18:31:08.839, value=Student
            rowkey_1               column=base_info:name, timestamp=2023-03-22T18:30:43.745, value=Tom
            rowkey_2               column=base_info:job, timestamp=2023-03-22T18:37:11.844, value=Engineer
            rowkey_2               column=base_info:name, timestamp=2023-03-22T18:36:31.967, value=Jerry
            rowkey_2               column=base_info:salary, timestamp=2023-03-22T18:36:39.804, value=3000
            2 row(s)
            Took 0.0277 seconds

        # 扫描一个列
        hbase:005:0> scan 'test', {COLUMNS=> 'base_info:name'}

            ROW                    COLUMN+CELL
            rowkey_1               column=base_info:name, timestamp=2023-03-22T18:30:43.745, value=Tom
            rowkey_2               column=base_info:name, timestamp=2023-03-22T18:36:31.967, value=Jerry
            2 row(s)
            Took 0.0123 seconds

        # 使用 FILTER 找到某个列的值等于 12
        hbase:005:0> scan 'test', FILTER=>"ValueFilter(=,'binary:12')"
        
            ROW                  COLUMN+CELL
            rowkey_1             column=base_info:age, timestamp=2023-03-22T18:31:00.415, value=12
            1 row(s)
            Took 0.0152 seconds

        # 使用 FILTER 找到包含 'Tom'
        hbase:006:0> scan 'test', FILTER=>"ValueFilter(=,'substring:Tom')"

            Took 0.0070 seconds
            hbase:013:0> scan 'test', FILTER=>"ValueFilter(=,'substring:Tom')"
            ROW                  COLUMN+CELL
            rowkey_1             column=base_info:name, timestamp=2023-03-22T18:30:43.745, value=Tom
            1 row(s)
            Took 0.0135 seconds


        注:除了列(COLUMNS)、FILTER(按条件过滤行)修饰词外,HBase 还支持 Limit(限制查询结果行数),STARTROW (ROWKEY 起始行,会先根据这个key 定位到 region,再向后扫描)、STOPROW (结束行)、TIMERANGE(限定时间戳范围)、VERSIONS(版本)等。
        
    5) Namespace 操作

        命名空间,类似于关系型数据库下的 database,每个命名空间下有多个表。

        # 创建 Namespace
        hbase:002:0> create_namespace 'springboot'

        # 查看 Namespace
        hbase:003:0> describe_namespace 'springboot'

            DESCRIPTION
            {NAME => 'springboot'}
            Quota is disabled
            Took 0.0186 seconds

        # 查看所有 Namespace
        hbase:004:0> list_namespace

            NAMESPACE
            default
            hbase
            springboot
            3 row(s)
            Took 0.0151 seconds

        # 在 springboot 下创建表 tbl_01
        hbase:006:0>create 'springboot:tbl_01', 'column_family1'

            Created table springboot:tbl_01
            Took 1.2189 seconds
            => Hbase::Table - springboot:tbl_01

        # 列出 springboot 下的所有 Table
        hbase:007:0> list_namespace_tables 'springboot'

            TABLE
            tbl_01
            1 row(s)
            Took 0.0197 seconds
            => ["tbl_01"]

        # 删除 Namespace
        hbase:008:0> drop_namespace 'springboot'

            ERROR: org.apache.hadoop.hbase.constraint.ConstraintException: Only empty namespaces can be removed. Namespace springboot has 1 tables

            ...

        注:命名空间 springboot 下有一个表 tbl_01,不能删除非空的命名空间。



3. HBase REST 服务

    1) 启动 REST 服务器

        $ cd ~/apps

        # 前台运行,默认端口为 8080
        $ ./hbase-2.4.4/bin/hbase rest start -p 8888

        # 后台运行
        $ ./hbase-2.4.4/bin/hbase-daemon.sh start rest -p 8888

        # 显示所有非系统表
        $ curl -X GET -H "Accept: text/plain" "http://localhost:8888"

            test
            springboot:tbl_01

        # 显示 HBase 版本
        $ curl -X GET -H "Accept: text/plain" "http://localhost:8888/version/cluster"

            2.4.4

        # HBase 群集状态
        $ curl -X GET -H "Accept: text/plain" "http://localhost:8888/status/cluster"

            1 live servers, 0 dead servers, 4.0000 average load

            1 live servers
                Test-Ubuntu20:16020 1679556060710
                    requests=16, regions=4
                    heapSizeMB=41
                    maxHeapSizeMB=494
            ...

    2) Table 操作

        # 创建新表
        $ curl -X PUT \
            -H "Accept: text/plain" \
            -H "Content-Type: text/xml" \
            -d '<?xml version="1.0" encoding="UTF-8"?><TableSchema name="demo"><ColumnSchema name="column_family1" /></TableSchema>' \
            "http://localhost:8888/demo/schema"

        # 显示表的结构信息   
        $ curl -X GET -H "Accept: text/plain" "http://localhost:8888/demo/schema"

            { NAME=> 'demo', IS_META => 'false', COLUMNS => [ { NAME => 'column_family1', BLOOMFILTER => 'ROW', IN_MEMORY => 'false', VERSIONS => '1', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', COMPRESSION => 'NONE', TTL => '2147483647', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0' } ] }


        # 更新表结构
        $ curl -X POST \
            -H "Accept: text/plain" \
            -H "Content-Type: text/xml" \
            -d '<?xml version="1.0" encoding="UTF-8"?><TableSchema name="demo"><ColumnSchema name="column_family1" KEEP_DELETED_CELLS="true" /></TableSchema>' \
            "http://localhost:8888/demo/schema"


        # 显示表分区
        $ curl -X GET -H "Accept: text/plain" "http://localhost:8888/demo/regions"

            demo,,1679558889289.b7e89a9e95ad237aeb9439cff11d83c2. [
            id=1679558889289
            startKey=''
            endKey=''
            location='Test-Ubuntu20:16020'
            ]


        # 删除表
        $ curl -X DELETE -H "Accept: text/plain" "http://localhost:8888/demo/schema"

    3) 查询数据

        # 查询 test 表 rowkey_1 下的数据
        $ curl -X GET -H "Accept: text/xml" "http://localhost:8888/test/rowkey_1"

            <?xml version="1.0" encoding="UTF-8" standalone="yes"?><CellSet><Row key="cm93a2V5XzE="><Cell column="YmFzZV9pbmZvOmFnZQ==" timestamp="1679481060415">MTI=</Cell><Cell column="YmFzZV9pbmZvOmpvYg==" timestamp="1679481068839">U3R1ZGVudA==</Cell><Cell column="YmFzZV9pbmZvOm5hbWU=" timestamp="1679481043745">VG9t</Cell></Row></CellSet>

            注:key、column 和值是被 Base64 编码的,可以运行如下命令解码。

            $ echo "cm93a2V5XzE=" | base64 -d

                rowkey_1

        # 查询 test 表 rowkey_1 下 base_info 列族的 name 列的数据
        $ curl -X GET -H "Accept: text/xml" "http://localhost:8888/test/rowkey_1/base_info:name"
        
            <?xml version="1.0" encoding="UTF-8" standalone="yes"?><CellSet><Row key="cm93a2V5XzE="><Cell column="YmFzZV9pbmZvOm5hbWU=" timestamp="1679481043745">VG9t</Cell></Row></CellSet>

            $ echo "VG9t" | base64 -d

                Tom

    4) Namespace        

        # 查看所有 Namespace
        $ curl -X GET -H "Accept: text/xml" "http://localhost:8888/namespaces"

            <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Namespaces><Namespace>default</Namespace><Namespace>hbase</Namespace><Namespace>springboot</Namespace></Namespaces>

        # 查看指定 Namespace 下的表
        $ curl -X GET -H "Accept: text/xml" "http://localhost:8888/namespaces/springboot/tables"

            <?xml version="1.0" encoding="UTF-8" standalone="yes"?><TableList><table name="tbl_01"/></TableList>

    5) 停止 REST 服务器

        $ cd ~/apps        
        $ ./hbase-2.4.4/bin/hbase-daemon.sh stop rest


4. Phoenix 组件

    1) 下载 Phoenix

        访问 http://archive.apache.org/dist/phoenix/phoenix-5.1.2/phoenix-hbase-2.4-5.1.2-bin.tar.gz,下载 phoenix-hbase-2.4-5.1.2-bin.tar.gz 保存到 ~/apps 目录。

        $ cd ~/apps
        $ tar -zvxf phoenix-hbase-2.4-5.1.2-bin.tar.gz
        $ mv phoenix-hbase-2.4-5.1.2-bin phoenix-5.1.2

        $ cd phoenix-5.1.2
        $ cp phoenix-server-hbase-2.4-5.1.2.jar ../hbase-2.4.4/lib  # HBase 集群的 master 和 slave 都要复制该文件   

    2) 配置 Phoenix Schema 操作权限

        $ cd ~/apps

        # 修改 HBase 配置文件,添加如下内容
        $ vim ./hbase-2.4.4/conf/hbase-site.xml

            <property>
                <name>phoenix.schema.isNamespaceMappingEnabled</name>
                <value>true</value>
            </property>
            <property>
                <name>phoenix.schema.mapSystemTablesToNamespace</name>
                <value>true</value>
            </property>


        # 修改 Phoenix 配置文件,添加如下内容
        $ vim ./phoenix-5.1.2/bin/hbase-site.xml

            <property>
                <name>phoenix.schema.isNamespaceMappingEnabled</name>
                <value>true</value>
            </property>
            <property>
                <name>phoenix.schema.mapSystemTablesToNamespace</name>
                <value>true</value>
            </property>    


    3) 重启 HBase

        $ cd ~/apps

        # 停止 HBase
        $ ./hbase-2.4.4/bin/stop-hbase.sh

        # 启动 HBase
        $ ./hbase-2.4.4/bin/start-hbase.sh

    4) Phoenix Shell (Python)

        SQL Support: https://phoenix.apache.org/language/index.html

        $ cd ~/apps
        $ ./phoenix-5.1.2/bin/sqlline.py localhost:2182    # localhost:2182 是 Zookeeper 的地址和端口

            ...

            Connected to: Phoenix (version 5.1)
            Driver: PhoenixEmbeddedDriver (version 5.1)
            Autocommit status: true
            Transaction isolation: TRANSACTION_READ_COMMITTED
            sqlline version 1.9.0

            # 创建 schema (就是 HBase 中的 Namespace,相当于 RDBMS 的数据库)
            0: jdbc:phoenix:localhost:2182> CREATE schema IF NOT EXISTS "ns_test";


            # 切换 schema,如果不执行 USE "ns_test",那默认操作的是 “default” schema
            0: jdbc:phoenix:localhost:2182> USE "ns_test";


            # 删除 schema
            0: jdbc:phoenix:localhost:2182> drop schema "ns_test";


            # 创建表
            0: jdbc:phoenix:localhost:2182> CREATE TABLE IF NOT EXISTS user (
            . . . . . . . . . . . . . . .)> id varchar PRIMARY KEY,
            . . . . . . . . . . . . . . .)> name varchar,
            . . . . . . . . . . . . . . .)> age integer);


            # 查看 Phoenix 创建的所有表
            0: jdbc:phoenix:localhost:2182> !tables

                +-----------+-------------+------------+--------------+---------+-----------+--- ...
                | TABLE_CAT | TABLE_SCHEM | TABLE_NAME |  TABLE_TYPE  | REMARKS | TYPE_NAME |
                +-----------+-------------+------------+--------------+---------+-----------+---
                |           | SYSTEM      | CATALOG    | SYSTEM TABLE |         |           |   
                |           | SYSTEM      | CHILD_LINK | SYSTEM TABLE |         |           |   
                |           | SYSTEM      | FUNCTION   | SYSTEM TABLE |         |           |   
                |           | SYSTEM      | LOG        | SYSTEM TABLE |         |           |   
                |           | SYSTEM      | MUTEX      | SYSTEM TABLE |         |           |   
                |           | SYSTEM      | SEQUENCE   | SYSTEM TABLE |         |           |   
                |           | SYSTEM      | STATS      | SYSTEM TABLE |         |           |   
                |           | SYSTEM      | TASK       | SYSTEM TABLE |         |           |  
                |           | ns_test     | USER       | TABLE        |         |           |   
                +-----------+-------------+------------+--------------+---------+-----------+---


            # 插入/更新数据
            0: jdbc:phoenix:localhost:2182> UPSERT INTO user VALUES ('1', 'Tom', 12);
            0: jdbc:phoenix:localhost:2182> UPSERT INTO user(id,name,age) VALUES ('2', 'Jerry', 10);

                注: 如果主键的值重复,那么进行更新操作,否则插入一条新的记录。在使用 UPSERT 时,主键的列不能为空(包括联合主键)。


            # 查询数据
            0: jdbc:phoenix:localhost:2182> SELECT * FROM user;

                +----+-------+-----+
                | ID | NAME  | AGE |
                +----+-------+-----+
                | 1  | Tom   | 12  |
                | 2  | Jerry | 10  |
                +----+-------+-----+
                2 rows selected (0.066 seconds)
                
                注:查询支持 ORDER BY、GROUP BY、LIMIT、JOIN 等操作,同时 Phoenix 提供了 COUNT()、MAX()、MIN()、SUM() 等函数。

            函数列表可以查看:http://phoenix.apache.org/language/functions.html
# 删除表 0: jdbc:phoenix:localhost:2182> DROP TABLE user; # 退出 sqlline,可以运行 !exit 或 !quit 或 !q 0: jdbc:phoenix:localhost:2182> !exit


        注:Phoenix 的 Python 开发包,可以运行如下命令安装:

            $ sudo apt-get install libkrb5-dev
            $ sudo pip install phoenixdb