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
查询计算组用于服务查询。操作步骤
创建数据库。
Superuser账号登录HoloWeb创建名称为
erp_database
的数据库,详情请参见创建数据库。登录数据库后,使用如下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);
创建计算组。
Superuser账号登录HoloWeb,在顶部菜单栏选择安全中心 > 计算组管理。
您可以在计算组管理页面查看实例现有的计算组。
在计算组管理页面的右上角,单击新增计算组。
在新增计算组对话框,填写计算组名称和选择计算组资源。
本场景新增名称为
read_warehouse_1
的计算组:在计算组管理页面可查看计算组状态,待计算组对应的状态列为正在运行时,即计算组创建成功。
向计算组加载数据。
Table Group是Hologres中数据的载体。默认情况下,新创建的计算组无权访问任何Table Group,所以如果要使用计算组查询数据,需要先为计算组赋予Table Group的权限。
查看当前数据库的Table Group。
使用如下SQL查看当前数据库有哪些Table Group:
SELECT tablegroup_name FROM hologres.hg_table_group_properties GROUP BY tablegroup_name;
返回结果示例如下:
即当前数据库仅有一个Table Group。
为计算组加载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);
查看计算组加载Table Group的情况。
select * from hologres.hg_warehouse_table_groups;
示例返回结果如下:
即read_warehouse_1已经加载了erp_database_tg_default 这个Table Group的数据。
设置用户权限。
默认情况下新建的计算组,非授权用户不能访问,当您需要让其他账号访问计算组时需要进行授权。为
ram_test
RAM用户授权访问read_warehouse_1计算组授权示例如下:查看用户拥有计算组的权限信息。
select * from hologres.hg_warehouse_users;
查看用户默认计算组的信息。
select * from hologres.hg_user_default_warehouse;
在实例中加入用户。
在HoloWeb的用户管理页面添加RAM用户至Hologres实例,详情请参见用户管理。
赋予
ram_test
用户erp_databse
数据库的查询权限。在HoloWeb的DB授权页面,为
ram_test
用户授予数据库的查询权限,详情请参见RAM用户权限授权快速入门。为用户
ram_test
添加read_warehouse_1计算组的权限。CALL hg_grant_warehouse_access_privilege ('read_warehouse_1', 'p4_2xxxxxxxxxxxxxxx');
参数说明请参见计算组授权管理。
将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');
查看当前账号使用的计算组。
此时使用
ram_test
用户连接实例时,使用如下命令验证使用的计算组是否为read_warehouse_1:select current_warehouse();
场景2:计算组流量切换
在场景一的基础上,如果发现计算组read_warehouse_1有故障,此时需要将账号ram_test
的流量切换到init_warehouse计算组上。
示意图。
注意事项
由于切换流量需要重新连接才生效,所以需要保证您连接到Hologres的应用具备重连机制。
连接到Hologres时请使用Hologres自动的路由逻辑,切勿在连接字符串中指定使用的计算组名。
操作步骤
为用户
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');
将init_warehouse计算组设置为
ram_test
用户的默认计算组。使用如下命令将
ram_test
用户的默认计算组设置为init_warehouse,设置完毕后,用户和实例建立新连接即会使用计算组init_warehouse的资源。CALL hg_set_user_default_warehouse ('p4_2xxxxxxxxxxxxxxx', 'init_warehouse');
断开所有用户非默认计算组的连接。
SELECT hg_kill_non_default_warehouse_connections();
重新建立连接后,即会使用新配置的默认计算组连接到实例。