计算组实例快速入门

Hologres V2.0版本推出了全新的弹性高可用实例形态,将计算资源分解为不同的计算组(Virtual Warehouse),更好的服务于高可用部署。本文为您介绍如何使用计算组。

背景信息

在Hologres 1.1版本已经实现了共享存储的多实例读写分离的高可用部署架构,一个主实例可以绑定多个只读从实例,实例与实例之间共享存储,但是计算资源是互相隔离的,从而实现读写分离高可用部署,详情请参见主从实例读写分离部署(共享存储)

但是现在的只读从实例模式,存在以下限制:

  • 多个实例使用独立的Endpoint,切换流量时,需要更改Endpoint。

  • 只读从实例和主实例共享一套元数据,无法根据每个只读从实例的作用单独设置参数,例如根据查询高可用的要求,针对每个只读从实例设置不一样的Replica(副本)数。

为了解决以上问题,Hologres V2.0版本推出了全新的弹性高可用实例形态,将计算资源分解为不同的计算组(Virtual Warehouse),相较于只读从实例模式,具备如下优点:

  • 计算组之间共享数据、元数据。

  • 使用一个Endpoint,无需切换Endpoint即可实现流量切换。

计算组架构介绍请参见计算组架构介绍

注意事项

仅Hologres V2.0.4及以上版本支持使用计算组实例,如果您的实例是V2.0.4以下版本,请您使用自助升级或加入Hologres钉钉交流群反馈,详情请参见如何获取更多的在线支持?

使用说明

场景1:创建全新的计算组实例

  • 示意图

    场景示意图如下:使用init_warehouse写入计算组用于写入数据;使用read_warehouse_1查询计算组用于服务查询。

    image..png

  • 操作步骤

    1. 创建数据库。

      1. Superuser账号登录HoloWeb创建名称为erp_database的数据库,详情请参见创建数据库image.png

      2. 登录数据库后,使用如下SQL向其中导入样例数据。

        DROP FOREIGN TABLE IF EXISTS odps_customer_10g;
        DROP FOREIGN TABLE IF EXISTS odps_lineitem_10g;
        DROP FOREIGN TABLE IF EXISTS odps_nation_10g;
        DROP FOREIGN TABLE IF EXISTS odps_orders_10g;
        DROP FOREIGN TABLE IF EXISTS odps_part_10g;
        DROP FOREIGN TABLE IF EXISTS odps_partsupp_10g;
        DROP FOREIGN TABLE IF EXISTS odps_region_10g;
        DROP FOREIGN TABLE IF EXISTS odps_supplier_10g;
        
        
        IMPORT FOREIGN SCHEMA "MAXCOMPUTE_PUBLIC_DATA#default" LIMIT to
        (
            odps_customer_10g,
            odps_lineitem_10g,
            odps_nation_10g,
            odps_orders_10g,
            odps_part_10g,
            odps_partsupp_10g,
            odps_region_10g,
            odps_supplier_10g
        ) 
        FROM SERVER odps_server INTO public OPTIONS(if_table_exist'error',if_unsupported_type'error');
        
        DROP TABLE IF EXISTS LINEITEM;
        
        BEGIN;
        CREATE TABLE LINEITEM
        (
            L_ORDERKEY      BIGINT      NOT NULL,
            L_PARTKEY       INT         NOT NULL,
            L_SUPPKEY       INT         NOT NULL,
            L_LINENUMBER    INT         NOT NULL,
            L_QUANTITY      DECIMAL(15,2) NOT NULL,
            L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
            L_DISCOUNT      DECIMAL(15,2) NOT NULL,
            L_TAX           DECIMAL(15,2) NOT NULL,
            L_RETURNFLAG    TEXT        NOT NULL,
            L_LINESTATUS    TEXT        NOT NULL,
            L_SHIPDATE      TIMESTAMPTZ NOT NULL,
            L_COMMITDATE    TIMESTAMPTZ NOT NULL,
            L_RECEIPTDATE   TIMESTAMPTZ NOT NULL,
            L_SHIPINSTRUCT  TEXT        NOT NULL,
            L_SHIPMODE      TEXT        NOT NULL,
            L_COMMENT       TEXT        NOT NULL,
            PRIMARY KEY (L_ORDERKEY,L_LINENUMBER)
        );
        CALL set_table_property('LINEITEM', 'clustering_key', 'L_SHIPDATE,L_ORDERKEY');
        CALL set_table_property('LINEITEM', 'segment_key', 'L_SHIPDATE');
        CALL set_table_property('LINEITEM', 'distribution_key', 'L_ORDERKEY');
        CALL set_table_property('LINEITEM', 'bitmap_columns', 'L_ORDERKEY,L_PARTKEY,L_SUPPKEY,L_LINENUMBER,L_RETURNFLAG,L_LINESTATUS,L_SHIPINSTRUCT,L_SHIPMODE,L_COMMENT');
        CALL set_table_property('LINEITEM', 'dictionary_encoding_columns', 'L_RETURNFLAG,L_LINESTATUS,L_SHIPINSTRUCT,L_SHIPMODE,L_COMMENT');
        CALL set_table_property('LINEITEM', 'time_to_live_in_seconds', '31536000');
        COMMIT;
        
        DROP TABLE IF EXISTS ORDERS;
        
        BEGIN;
        CREATE TABLE ORDERS
        (
            O_ORDERKEY      BIGINT      NOT NULL PRIMARY KEY,
            O_CUSTKEY       INT         NOT NULL,
            O_ORDERSTATUS   TEXT        NOT NULL,
            O_TOTALPRICE    DECIMAL(15,2) NOT NULL,
            O_ORDERDATE     timestamptz NOT NULL,
            O_ORDERPRIORITY TEXT        NOT NULL,
            O_CLERK         TEXT        NOT NULL,
            O_SHIPPRIORITY  INT         NOT NULL,
            O_COMMENT       TEXT        NOT NULL
        );
        CALL set_table_property('ORDERS', 'segment_key', 'O_ORDERDATE');
        CALL set_table_property('ORDERS', 'distribution_key', 'O_ORDERKEY');
        CALL set_table_property('ORDERS', 'bitmap_columns', 'O_ORDERKEY,O_CUSTKEY,O_ORDERSTATUS,O_ORDERPRIORITY,O_CLERK,O_SHIPPRIORITY,O_COMMENT');
        CALL set_table_property('ORDERS', 'dictionary_encoding_columns', 'O_ORDERSTATUS,O_ORDERPRIORITY,O_CLERK,O_COMMENT');
        CALL set_table_property('ORDERS', 'time_to_live_in_seconds', '31536000');
        COMMIT;
        
        DROP TABLE IF EXISTS PARTSUPP;
        
        BEGIN;
        CREATE TABLE PARTSUPP
        (
            PS_PARTKEY    INT    NOT NULL,
            PS_SUPPKEY    INT    NOT NULL,
            PS_AVAILQTY   INT    NOT NULL,
            PS_SUPPLYCOST DECIMAL(15,2) NOT NULL,
            PS_COMMENT    TEXT   NOT NULL,
            PRIMARY KEY(PS_PARTKEY,PS_SUPPKEY)
        );
        CALL set_table_property('PARTSUPP', 'distribution_key', 'PS_PARTKEY');
        CALL set_table_property('PARTSUPP', 'colocate_with', 'LINEITEM');
        CALL set_table_property('PARTSUPP', 'bitmap_columns', 'PS_PARTKEY,PS_SUPPKEY,PS_AVAILQTY,PS_COMMENT');
        CALL set_table_property('PARTSUPP', 'dictionary_encoding_columns', 'PS_COMMENT');
        CALL set_table_property('PARTSUPP', 'time_to_live_in_seconds', '31536000');
        COMMIT;
        
        DROP TABLE IF EXISTS PART;
        
        BEGIN;
        CREATE TABLE PART
        (
            P_PARTKEY     INT    NOT NULL PRIMARY KEY,
            P_NAME        TEXT   NOT NULL,
            P_MFGR        TEXT   NOT NULL,
            P_BRAND       TEXT   NOT NULL,
            P_TYPE        TEXT   NOT NULL,
            P_SIZE        INT    NOT NULL,
            P_CONTAINER   TEXT   NOT NULL,
            P_RETAILPRICE DECIMAL(15,2) NOT NULL,
            P_COMMENT     TEXT   NOT NULL
        );
        CALL set_table_property('PART', 'distribution_key', 'P_PARTKEY');
        CALL set_table_property('PART', 'bitmap_columns', 'P_PARTKEY,P_SIZE,P_NAME,P_MFGR,P_BRAND,P_TYPE,P_CONTAINER,P_COMMENT');
        CALL set_table_property('PART', 'dictionary_encoding_columns', 'P_NAME,P_MFGR,P_BRAND,P_TYPE,P_CONTAINER,P_COMMENT');
        CALL set_table_property('PART', 'time_to_live_in_seconds', '31536000');
        COMMIT;
        
        
        
        DROP TABLE IF EXISTS CUSTOMER;
        BEGIN;
        CREATE TABLE CUSTOMER
        (
            C_CUSTKEY    INT    NOT NULL PRIMARY KEY,
            C_NAME       TEXT   NOT NULL,
            C_ADDRESS    TEXT   NOT NULL,
            C_NATIONKEY  INT    NOT NULL,
            C_PHONE      TEXT   NOT NULL,
            C_ACCTBAL    DECIMAL(15,2) NOT NULL,
            C_MKTSEGMENT TEXT   NOT NULL,
            C_COMMENT    TEXT   NOT NULL
        );
        CALL set_table_property('CUSTOMER', 'distribution_key', 'C_CUSTKEY');
        CALL set_table_property('CUSTOMER', 'bitmap_columns', 'C_CUSTKEY,C_NATIONKEY,C_NAME,C_ADDRESS,C_PHONE,C_MKTSEGMENT,C_COMMENT');
        CALL set_table_property('CUSTOMER', 'dictionary_encoding_columns', 'C_NAME,C_ADDRESS,C_PHONE,C_MKTSEGMENT,C_COMMENT');
        CALL set_table_property('CUSTOMER', 'time_to_live_in_seconds', '31536000');
        COMMIT;
        
        DROP TABLE IF EXISTS SUPPLIER;
        
        BEGIN;
        CREATE TABLE SUPPLIER
        (
            S_SUPPKEY   INT    NOT NULL PRIMARY KEY,
            S_NAME      TEXT   NOT NULL,
            S_ADDRESS   TEXT   NOT NULL,
            S_NATIONKEY INT    NOT NULL,
            S_PHONE     TEXT   NOT NULL,
            S_ACCTBAL   DECIMAL(15,2) NOT NULL,
            S_COMMENT   TEXT   NOT NULL
        );
        CALL set_table_property('SUPPLIER', 'distribution_key', 'S_SUPPKEY');
        CALL set_table_property('SUPPLIER', 'bitmap_columns', 'S_SUPPKEY,S_NAME,S_ADDRESS,S_NATIONKEY,S_PHONE,S_COMMENT');
        CALL set_table_property('SUPPLIER', 'dictionary_encoding_columns', 'S_NAME,S_ADDRESS,S_PHONE,S_COMMENT');
        CALL set_table_property('SUPPLIER', 'time_to_live_in_seconds', '31536000');
        COMMIT;
        
        DROP TABLE IF EXISTS NATION;
        
        BEGIN;
        CREATE TABLE NATION(
          N_NATIONKEY INT NOT NULL PRIMARY KEY,
          N_NAME text NOT NULL,
          N_REGIONKEY INT NOT NULL,
          N_COMMENT text NOT NULL
        );
        CALL set_table_property('NATION', 'distribution_key', 'N_NATIONKEY');
        CALL set_table_property('NATION', 'bitmap_columns', 'N_NATIONKEY,N_NAME,N_REGIONKEY,N_COMMENT');
        CALL set_table_property('NATION', 'dictionary_encoding_columns', 'N_NAME,N_COMMENT');
        CALL set_table_property('NATION', 'time_to_live_in_seconds', '31536000');
        COMMIT;
        
        DROP TABLE IF EXISTS REGION;
        
        BEGIN;
        CREATE TABLE REGION
        (
            R_REGIONKEY INT  NOT NULL PRIMARY KEY,
            R_NAME      TEXT NOT NULL,
            R_COMMENT   TEXT
        );
        CALL set_table_property('REGION', 'distribution_key', 'R_REGIONKEY');
        CALL set_table_property('REGION', 'bitmap_columns', 'R_REGIONKEY,R_NAME,R_COMMENT');
        CALL set_table_property('REGION', 'dictionary_encoding_columns', 'R_NAME,R_COMMENT');
        CALL set_table_property('REGION', 'time_to_live_in_seconds', '31536000');
        COMMIT;
        
        INSERT INTO public.customer SELECT * FROM public.odps_customer_10g ;
        INSERT INTO public.lineitem SELECT * FROM public.odps_lineitem_10g ;
        INSERT INTO public.nation SELECT * FROM public.odps_nation_10g ;
        INSERT INTO public.orders SELECT * FROM public.odps_orders_10g ;
        INSERT INTO public.part SELECT * FROM public.odps_part_10g ;
        INSERT INTO public.partsupp SELECT * FROM public.odps_partsupp_10g ;
        INSERT INTO public.region SELECT * FROM public.odps_region_10g ;
        INSERT INTO public.supplier SELECT * FROM public.odps_supplier_10g ;
        
        vacuum nation;
        vacuum region;
        vacuum supplier;
        vacuum customer;
        vacuum part;
        vacuum partsupp;
        vacuum orders;
        vacuum lineitem;
        
        analyze nation;
        analyze region;
        analyze lineitem;
        analyze orders;
        analyze customer;
        analyze part;
        analyze partsupp;
        analyze supplier;
        analyze lineitem (l_orderkey,l_partkey,l_suppkey);
        analyze orders (o_custkey);
        analyze partsupp(ps_partkey,ps_suppkey);
    2. 创建计算组。

      1. Superuser账号登录HoloWeb,在顶部菜单栏选择安全中心 > 计算组管理

        您可以在计算组管理页面查看实例现有的计算组。

        image.png

      2. 计算组管理页面的右上角,单击新增计算组

      3. 新增计算组对话框,填写计算组名称和选择计算组资源

        本场景新增名称为read_warehouse_1的计算组:image.png

      4. 计算组管理页面可查看计算组状态,待计算组对应的状态列为正在运行时,即计算组创建成功。

        image.png

    3. 向计算组加载数据。

      Table Group是Hologres中数据的载体。默认情况下,新创建的计算组无权访问任何Table Group,所以如果要使用计算组查询数据,需要先为计算组赋予Table Group的权限。

      1. 查看当前数据库的Table Group。

        使用如下SQL查看当前数据库有哪些Table Group:

        SELECT tablegroup_name
        FROM hologres.hg_table_group_properties
        GROUP BY tablegroup_name;

        返回结果示例如下:image..png

        即当前数据库仅有一个Table Group。

      2. 为计算组加载Table Group。

        由于需要使用read_warehouse_1查询该数据库中erp_database_tg_default Table Group的数据,所以需要使用如下SQL为计算组read_warehouse_1加载erp_database_tg_default

        CALL hg_table_group_load_to_warehouse ('erp_database.erp_database_tg_default', 'read_warehouse_1', 1);
      3. 查看计算组加载Table Group的情况。

        select * from hologres.hg_warehouse_table_groups;

        示例返回结果如下:image..png

        read_warehouse_1已经加载了erp_database_tg_default 这个Table Group的数据。

    4. 设置用户权限。

      默认情况下新建的计算组,非授权用户不能访问,当您需要让其他账号访问计算组时需要进行授权。为ram_testRAM用户授权访问read_warehouse_1计算组授权示例如下:

      1. 查看用户拥有计算组的权限信息。

        select * from hologres.hg_warehouse_users;
      2. 查看用户默认计算组的信息。

        select * from hologres.hg_user_default_warehouse;
      3. 在实例中加入用户。

        在HoloWeb的用户管理页面添加RAM用户至Hologres实例,详情请参见用户管理

        image..png

      4. 赋予ram_test用户erp_databse数据库的查询权限。

        在HoloWeb的DB授权页面,为ram_test用户授予数据库的查询权限,详情请参见RAM用户权限授权快速入门image..png

      5. 为用户ram_test添加read_warehouse_1计算组的权限。

        CALL hg_grant_warehouse_access_privilege ('read_warehouse_1', 'p4_2xxxxxxxxxxxxxxx');

        参数说明请参见计算组授权管理

      6. read_warehouse_1计算组设置为ram_test用户的默认计算组。

        由于需要ram_test用户连接Hologres使用read_warehouse_1的资源,不使用init_warehouse,实现读写分离,那么就需要使用如下命令将ram_test的默认计算组设置为read_warehouse_1

        CALL hg_set_user_default_warehouse ('p4_2xxxxxxxxxxxxxxx', 'read_warehouse_1');
      7. 查看当前账号使用的计算组。

        此时使用ram_test用户连接实例时,使用如下命令验证使用的计算组是否为read_warehouse_1

        select current_warehouse();

场景2:计算组流量切换

在场景一的基础上,如果发现计算组read_warehouse_1有故障,此时需要将账号ram_test的流量切换到init_warehouse计算组上。

  • 示意图。image..png

  • 注意事项

    • 由于切换流量需要重新连接才生效,所以需要保证您连接到Hologres的应用具备重连机制。

    • 连接到Hologres时请使用Hologres自动的路由逻辑,切勿在连接字符串中指定使用的计算组名。

  • 操作步骤

    1. 为用户ram_test添加init_warehouse计算组的权限。

      如果之前未给ram_test添加init_warehouse的权限,需要使用如下命令为用户ram_test添加init_warehouse计算组的权限,让ram_test用户可以使用init_warehouse的资源。

      CALL hg_grant_warehouse_access_privilege ('init_warehouse', 'p4_2xxxxxxxxxxxxxxx');
    2. 将init_warehouse计算组设置为ram_test用户的默认计算组。

      使用如下命令将ram_test用户的默认计算组设置为init_warehouse,设置完毕后,用户和实例建立新连接即会使用计算组init_warehouse的资源。

      CALL hg_set_user_default_warehouse ('p4_2xxxxxxxxxxxxxxx', 'init_warehouse');
    3. 断开所有用户非默认计算组的连接。

      SELECT hg_kill_non_default_warehouse_connections(); 
    4. 重新建立连接后,即会使用新配置的默认计算组连接到实例。