DM8 分布计算集群(DMDPC)Docker 命令行部署指南

简介

DMDPC是一款同时支持在线分析处理 (OLAP) 和在线事务处理 (OLTP) 的新型分布式数据库系统。它不仅保留了传统单机数据库的大部分功能,还提供了分布式计算集群所特有的高可用性、高扩展性、高性能、高吞吐量以及对用户透明等高级特性。本文借助命令行工具部署 DPC 集群。

系统架构

DMDPC 的架构由三个核心组件组成:

  1. 计划生成节点 (SP):对外提供分布式数据库服务,负责接收用户请求、生成执行计划,并调度计划的执行。一个集群中可以存在多个 SP 节点。连接上任何一个 SP 节点都可以获得完整的数据库服务。 对于一次客户端请求任务来说,客户端连接的 SP 负责生成、划分并调度计划,其它的 SP 和 BP 负责执行计划。
  2. 数据存储节点(BP):负责存储数据,并执行 SP 调度的任务。
  3. 元数据服务器节点 (MP):存储元数据信息,并为 SP 和 BP 提供元数据服务即字典信息服务,所有 DDL 请求都会经过 SP 转发给 MP 执行,元数据信息全部存储在 MP。一个 DMDPC 集群只能配置一个 MP 节点提供服务。但是可以配置多个备用MP。

DMDPC 支持多副本系统架构,确保数据安全性和高可用性。每个 BP 或 MP 节点可以配置成一个或多副本系统,以应对可能出现的各种故障情况。
DM8 分布计算集群(DMDPC)Docker 命令行部署指南_第1张图片

系统原理

在 DMDPC 中,数据根据用户指定的分布规则分布在不同的 BP 上。DMDPC 的核心在于对用户请求的并行执行。下面对查询流程分别进行详细说明。
DM8 分布计算集群(DMDPC)Docker 命令行部署指南_第2张图片

  1. 客户端发送请求给 SP;
  2. SP 生成执行计划,同时 SP 向 MP 申请获取字典信息;
  3. MP 返回字典信息给 SP;
  4. SP将生成的执行计划中的一个或多个子计划发送给此次查询相关的 BP;
  5. 相关 BP 接收并执行子计划。根据实际需要,不同 BP 间、同一 BP不同线程间可能存在数据交换;
  6. 相关 BP 在子计划执行完成时将成功与否信息和/或请求调度信息返回 SP;
  7. SP向客户端返回最终查询结果。

在 DMDPC 查询流程中,SP 作为计划生成和调度中心,BP 执行具体的数据操作,而 MP 提供必要的元数据支持,共同协作完成客户端的查询请求,这一流程不仅适用于查询操作,而且可以扩展到了所有的DDL和DML操作,SP、BP和MP在整个数据处理流程中协同工作,实现了高效的分布式数据库服务。

部署前提

部署 DMDPC 集群所用到的硬件和软件环境。

  • 硬件环境:
    主机一台或多台。用于部署 MP、SP 和 BP。内存大小要求:至少2GB。测试环境中可以将上述服务部署到同一主机,生产环境下推荐每个主机只部署一种类型服务器。
  • 软件环境:
    操作系统。Linux、Unix、Windows 等。
    达梦数据库软件。安装好 DM 数据库软件之后,将拥有配置和管理 DMDPC 所需的所有软件:dmserver、dminit、DIsql 等。这些软件位于安装目录的 bin、tool 等子目录中。

系统规范

  • 集群中 SP、BP、MP 都有自己的实例名,这些实例名要求全局唯一;
  • 一个 DMDPC 集群可以有多个 SP 和多个 BP,但只能有一个 MP;
  • DMDPC 中数据的分布以分区为单位,同一分区必须位于同一 BP,同一表的不同分区可以位于不同 BP,一张分区表的所有分区可以只落在部分BP;非分区表只包含一个分区,因此非分区表只落在一个 BP 上。分区表包含一个或多个分区,因此分区表可以落在一个或多个 BP 上;DMDPC 下,分区列同时也是分布列;
  • 在 DMDPC 中分区和分布统一为一个概念;在 DM MPP 中,分区和分布是两个不同的概念;
  • 实例在初始化时需指定 DPC_MODE 以决定其角色(SP、BP 或 MP),随后启动时需要附带上 DPC_MODE参数。实例角色在初始化后不能更改。

Docker 部署 DMDPC

集群规划

RAFT 组名 角色 实例名称 IP PORT_NUM AP_PORT_NUM 路径
RAFT_SP1 SP SP1 192.168.80.201 5237 6000 /opt/dmdbms/dpc_data/sp1
RAFT_1 BP BP1 192.168.80.201 5238 6001 /opt/dmdbms/dpc_data/bp1
RAFT_2 BP BP2 192.168.80.201 5239 6002 /opt/dmdbms/dpc_data/bp2
缺省为 NULL 或者 MP_RAFT MP MP 192.168.80.201 5240 6003 /opt/dmdbms/dpc_data/mp

达梦环境准备

在宿主机创建sp1、bp1、bp2、mp等目录,并将目录挂载到容器内的指定目录

# 加载 Docker 镜像
docker load -i dm8_20230808_rev197096_x86_rh6_64_single.tar

# 运行 Docker 容器
docker run -d --name dm8_dpc --privileged=true --network host \
-p 5237:5237  \
-p 5238:5238  \
-p 5239:5239  \
-p 5240:5240  \
-p 12000:12000 \
-v /home/ct/dm8/dpc_data/sp1:/opt/dmdbms/dpc_data/sp1 \
-v /home/ct/dm8/dpc_data/bp1:/opt/dmdbms/dpc_data/bp1 \
-v /home/ct/dm8/dpc_data/bp2:/opt/dmdbms/dpc_data/bp2 \
-v /home/ct/dm8/dpc_data/mp:/opt/dmdbms/dpc_data/mp \
dm8_single:dm8_20230808_rev197096_x86_rh6_64

# 进入容器内部
docker exec -it dm8_dpc bash

初始化数据库实例

进入达梦bin目录,初始化 4 个数据库实例,实例名称分别为 SP1、BP1、BP2 和 MP。

cd /opt/dmdbms/bin

./dminit path=/opt/dmdbms/dpc_data/sp1 instance_name=SP1 port_num=5237 ap_port_num=6000 dpc_mode=SP 
./dminit path=/opt/dmdbms/dpc_data/bp1 instance_name=BP1 port_num=5238 ap_port_num=6001 dpc_mode=BP 
./dminit path=/opt/dmdbms/dpc_data/bp2 instance_name=BP2 port_num=5239 ap_port_num=6002 dpc_mode=BP
./dminit path=/opt/dmdbms/dpc_data/mp  instance_name=MP  port_num=5240 ap_port_num=6003 dpc_mode=MP

配置 MP.INI 文件

为 SP、BP 和 MP 实例配置 MP.INI 文件。并将 MP.INI 文件内容分别写入 SP(SP1)、BP(BP1、BP2)和 MP 中。要求端口号与MP、BP和SP上的ap_port_num不冲突。

# 进入所有实例对应的目录
cd /opt/dmdbms/dpc_data/sp1/DAMENG/
cd /opt/dmdbms/dpc_data/bp1/DAMENG/
cd /opt/dmdbms/dpc_data/bp2/DAMENG/
cd /opt/dmdbms/dpc_data/mp/DAMENG/

# 添加并配置 MP.INI 文件
vi mp.ini
mp_host = 192.168.80.201
mp_port = 12000

启动 MP 并注册实例

在DMDPC 运行过程中,MP 需要始终处于开启状态。所以MP必须第一个启动。

# 启动 MP
cd /opt/dmdbms/bin
./dmserver /opt/dmdbms/dpc_data/mp/DAMENG/dm.ini dpc_mode=MP

将 MP、SP 和 BP 等实例加入集群,增加 1 个 MP、1 个 SP 和 2 个 BP 节点。只有在注册当前登录 MP 节点后,才可以注册其余节点。后续增加 MP、SP 节点和 BP 节点无先后之分。

# 搭建DMDPC过程中加入MP、SP和BP,必须登录MP进行操作
cd /opt/dmdbms/bin
./disql SYSDBA/[email protected]:5240

# 注册当前MP实例,MP的RAFT组名可以指定为NULL或者'MP_RAFT'
SP_CREATE_DPC_INSTANCE('MP_RAFT','MP','MP',6003,5240, '192.168.80.201', '192.168.80.201','NORMAL',1,'MP instance');

# 注册RAFT组,名为RAFT_1
SP_CREATE_DPC_RAFT('BP','RAFT_1');

# 在RAFT_1组内注册BP实例BP1
SP_CREATE_DPC_INSTANCE('RAFT_1','BP1','BP',6001,5238, '192.168.80.201', '192.168.80.201','NORMAL',1,'BP instance');

# 注册RAFT_2
SP_CREATE_DPC_RAFT('BP', 'RAFT_2');

# 在RAFT_2内注册BP实例BP2
SP_CREATE_DPC_INSTANCE('RAFT_2','BP2','BP',6002,5239, '192.168.80.201', '192.168.80.201', 'NORMAL', 1, 'BP instance');

# 注册一个BP组,名为BG_1
SP_CREATE_DPC_BP_GROUP('BG_1', 'bp group1');

# 往BP组中添加RAFT组
SP_BP_GROUP_ADD_RAFT('BG_1', 'RAFT_1');
SP_BP_GROUP_ADD_RAFT('BG_1', 'RAFT_2');

# 增加SP,也要注册RAFT组
SP_CREATE_DPC_RAFT('SP', 'RAFT_SP1');

#在RAFT_SP1内注册SP实例SP1
SP_CREATE_DPC_INSTANCE('RAFT_SP1','SP1','SP',6000,5237, '192.168.80.201', '192.168.80.201','NORMAL', 2, 'SP instance');

# 注册一个容错域:FDOM_1 (可选)
SP_CREATE_FAULT_DOMAIN ('FDOM_1','fuzhou');

# 往容错域中添加实例
SP_FAULT_DOMAIN_MV_INST('FDOM_1','MP');
SP_FAULT_DOMAIN_MV_INST('FDOM_1','BP1');
SP_FAULT_DOMAIN_MV_INST('FDOM_1','BP2');

检测是否注册成功

select * from DPC_BP_GROUP;
select * from DPC_BP_RAFT;
select * from DPC_INSTANCE;

启动 SP 和 BP

启动 SP 和 BP 没有先后之分。MP、SP、BP 全部正常启动,且均处于 OPEN 状态,才是一个正常的 DMDPC 系统。

cd /opt/dmdbms/bin
./dmserver /opt/dmdbms/dpc_data/bp1/DAMENG/dm.ini dpc_mode=BP
./dmserver /opt/dmdbms/dpc_data/bp2/DAMENG/dm.ini dpc_mode=BP
./dmserver /opt/dmdbms/dpc_data/sp1/DAMENG/dm.ini dpc_mode=SP

测试

Windows 本地使用 dmfldr 工具将数据快速载入到 DMDPC 分布式数据库中。

原理

  1. 用户提出装载需求,使用 dmfldr 向 DMDPC 系统装载数据;
  2. dmfldr 向 SP 发送请求,请求获取装载表的 BP 服务器站点信息;
  3. SP 向 MP 发送请求,请求获取装载表的 BP 服务器站点信息;
  4. MP 根据 SP 的请求,在 MP 站点上查询系统表,收集待装载表所涉及的所有 BP 站点信息,并将这些 BP 站点信息全部返回给SP;
  5. SP 将 BP 站点信息返回给 dmfldr;
  6. dmfldr 得到表的 BP 站点信息后,首先与各个 BP 分别建立连接,然后将所有数据发往各自 BP 站点,再分别进行装载。
    在 DMDPC 架构中,dmfldr 装载流程如下图所示。
    DM8 分布计算集群(DMDPC)Docker 命令行部署指南_第3张图片
    准备控制文件和数据文件,详细dmfldr使用步骤可以参考:达梦数据库dmfldr快速数据装载工具从控制台操作到jni编程问题总结(windows+linux)
    在 Windows 环境下,向 SP 所在 192.168.80.201 的数据库进行数据装载
    命令行方式导入:
dmfldr.exe SYSDBA/[email protected]:5237 control='D:\DMDBMS\bin\test\out1.ctl' mode='in'

导入成功
DM8 分布计算集群(DMDPC)Docker 命令行部署指南_第4张图片
达梦官方JNI接口方式导入:

public class DMfldrTest {
    /**********自定义init函数,设置属性信息,并初始化当前快速装载实例**********/
    public synchronized static boolean init(Instance instance, int threadNum, String tableName)
    {
        // 分配句柄
        instance.allocInstance();
        // 设置必要的属性信息
        String host = "192.168.80.201";
        String port = "5237";
        String userName = "SYSDBA";
        String password = "SYSDBA";
        instance.setAttribute(Properties.FLDR_ATTR_SERVER, host);
        instance.setAttribute(Properties.FLDR_ATTR_PORT, port);
        instance.setAttribute(Properties.FLDR_ATTR_UID, userName);
        instance.setAttribute(Properties.FLDR_ATTR_PWD, password);
        // 其余属性用户均可根据实际情况选择性设置
        // 设置编码
        //System.out.println(System.getProperty("file.encoding"));
        //System.out.println(getFileCharsetName("/home/boss/dm/ct-test/" + tableName + ".txt"));
        try {
            instance.setAttribute(Properties.FLDR_ATTR_DATA_CHAR_SET,System.getProperty("file.encoding"));
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 设置是否插入自增列
        //instance.setAttribute(Properties.FLDR_ATTR_SET_INDENTITY, "0");
        // fldr task线程默认为cpu个数,如果客户端线程数大于cpu个数,则必须设置该参数
        instance.setAttribute(Properties.FLDR_ATTR_TASK_THREAD_NUM, String.valueOf(threadNum));
        // 装载日志
        String dmHome = System.getProperty("DM_HOME");
        if(dmHome != null && !dmHome.equals("")){
            if(dmHome.endsWith("/") || dmHome.endsWith("\\")){
                instance.setAttribute(Properties.FLDR_ATTR_BAD_FILE, dmHome + "BADFILE_2.TXT");
                instance.setAttribute(Properties.FLDR_ATTR_LOG_FILE, dmHome + "FLDRLOG_2.TXT");
            }else{
                instance.setAttribute(Properties.FLDR_ATTR_BAD_FILE, dmHome + File.separator + "BADFILE_2.TXT");
                instance.setAttribute(Properties.FLDR_ATTR_LOG_FILE, dmHome + File.separator + "FLDRLOG_2.TXT");
            }
        }
        //初始化当前快速装载实例
        return instance.initializeInstance(null, null, null, "TEST."+tableName);
    }

    public static void main(String[] args) {
        Instance instance = new Instance();
        String tableName = "TEST_DEVICE";
        String DATA_PATH = "D:/DMDBMS/bin/test/";
        String filename = "out";
        boolean success = init(instance,1,tableName);
        if(success){
            String ctl = "LOAD DATA\r\n" +
                    "INFILE '" + DATA_PATH + filename + ".txt'\r\n" +
                    "INTO TABLE TEST." + tableName + "\r\n" +
                    "FIELDS '|'\r\n";
            System.out.println(ctl);
            //根据ctrl内容进行数据载入
            instance.setControl(ctl);
            instance.finish();
            // 返回实际插入的行数
            long rowHaveCopied = Long.parseLong(instance.getAttribute(Properties.FLDR_ATTR_COMMIT_ROWS));
            if(rowHaveCopied == 0L){
                System.out.println(tableName + "导入异常");
            }
            else{
                System.out.println(tableName+"导入成功" + ",已复制行数:" + rowHaveCopied);
            }
            instance.uninitialize();
            instance.free();
        }else{
            byte[] message = null;
            try {
                message = instance.getErrorMsg().getBytes("utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            ;
            System.out.println("出错信息:" + message);
            instance.free();
        }
    }
}

导入成功
DM8 分布计算集群(DMDPC)Docker 命令行部署指南_第5张图片

你可能感兴趣的:(docker,容器,数据库,分布式)