MatrixGate 常见问题

本文档介绍 MatrixGate 使用中的常见问题。


1 数据加载性能低


做数据加载时,发现磁盘 I/O 利用率高,但是加载速度很慢。

问题分析

使用 gpcheckperf 命令看磁盘性能,网络性能,发现磁盘性能仅 80MB/s。

解决方案

加载多块磁盘提升 I/O 性能,将 WAL 和 Data 数据盘分开, 尽可能提升 I/O 性能。


2 failed to acquire resources on on or more segments ,fatal out of memory


mxgate 同时开启加载 30 张表时,出现 OOM 异常。

问题分析

YMatrix 是多进程模式,高并发请求过来,连接数过多,无法分配内存给相应的请求,从而报错。

解决方案

调整 /etc/sysctl.conf 中的内核参数 vm.overcommit_memory = 2
调整 mxgate prepared 参数,从 prepared=10 改为 prepared = 5


3 mxgate 发生锁等待卡住


问题分析

查看 mxgate 进程状态:

  1. mxgate status 查看 mxgate 的进程状态

  2. 查看是否有数据正常入库

  3. 也可用通过 ps -ef|grep mxgate 查看 mxgate 的进程状态

查看锁等待信息:
granted 列值为 false,表示尚未获得锁的进程。可使用如下 SQL 语句查看:

=# CREATE VIEW v_locks_monitor AS   
WITH t_wait AS    
(    
  SELECT a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.granted,   
  a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid,a.transactionid,a.fastpath,    
  b.state,b.query,b.xact_start,b.query_start,b.usename,b.datname,b.client_addr,b.client_port,b.application_name   
    FROM pg_locks a,pg_stat_activity b WHERE a.pid=b.pid AND NOT a.granted   
),   
t_run AS   
(   
  SELECT a.mode,a.locktype,a.database,a.relation,a.page,a.tuple,a.classid,a.granted,   
  a.objid,a.objsubid,a.pid,a.virtualtransaction,a.virtualxid,a.transactionid,a.fastpath,   
  b.state,b.query,b.xact_start,b.query_start,b.usename,b.datname,b.client_addr,b.client_port,b.application_name   
    FROM pg_locks a,pg_stat_activity b WHERE a.pid=b.pid AND a.granted   
),   
t_overlap AS   
(   
  SELECT r.* FROM t_wait w JOIN t_run r ON   
  (   
    r.locktype IS NOT DISTINCT FROM w.locktype AND   
    r.database IS NOT DISTINCT FROM w.database AND   
    r.relation IS NOT DISTINCT FROM w.relation AND   
    r.page IS NOT DISTINCT FROM w.page AND   
    r.tuple IS NOT DISTINCT FROM w.tuple AND   
    r.virtualxid IS NOT DISTINCT FROM w.virtualxid AND   
    r.transactionid IS NOT DISTINCT FROM w.transactionid AND   
    r.classid IS NOT DISTINCT FROM w.classid AND   
    r.objid IS NOT DISTINCT FROM w.objid AND   
    r.objsubid IS NOT DISTINCT FROM w.objsubid AND   
    r.pid <> w.pid   
  )    
),    
t_unionall AS    
(    
  SELECT r.* FROM t_overlap r    
  UNION ALL    
  SELECT w.* FROM t_wait w    
)    
SELECT locktype,datname,relation::regclass,page,tuple,virtualxid,transactionid::text,classid::regclass,objid,objsubid,   
string_agg(   
'Pid: '||CASE WHEN pid IS NULL THEN 'NULL' ELSE pid::text END||chr(10)||   
'Lock_Granted: '||CASE WHEN granted IS NULL THEN 'NULL' ELSE granted::text END||' , Mode: '||CASE WHEN mode IS NULL THEN 'NULL' ELSE mode::text END||' , FastPath: '||CASE WHEN fastpath IS NULL THEN 'NULL' else fastpath::text END||' , VirtualTransaction: '||CASE WHEN virtualtransaction IS NULL THEN 'NULL' else virtualtransaction::text END||' , Session_State: '||CASE WHEN state IS NULL THEN 'NULL' else state::text END||chr(10)||   
'Username: '||CASE WHEN usename IS NULL THEN 'NULL' else usename::text END||' , Database: '||CASE WHEN datname IS null THEN 'NULL' else datname::text END||' , Client_Addr: '||CASE WHEN client_addr IS NULL THEN 'NULL' else client_addr::text END||' , Client_Port: '||CASE WHEN client_port IS NULL THEN 'NULL' else client_port::text END||' , Application_Name: '||CASE WHEN application_name IS NULL THEN 'NULL' else application_name::text END||chr(10)||    
'Xact_Start: '||CASE WHEN xact_start IS NULL THEN 'NULL' else xact_start::text END||' , Query_Start: '||CASE WHEN query_start IS NULL THEN 'NULL' else query_start::text END||' , Xact_Elapse: '||CASE WHEN (now()-xact_start) IS NULL THEN 'NULL' else (now()-xact_start)::text END||' , Query_Elapse: '||CASE WHEN (now()-query_start) IS NULL THEN 'NULL' else (now()-query_start)::text END||chr(10)||    
'SQL (Current SQL in Transaction): '||chr(10)||  
CASE WHEN query IS NULL THEN 'NULL' else query::text END,    
chr(10)||'--------'||chr(10)    
ORDER BY    
  (  CASE mode    
    WHEN 'INVALID' THEN 0   
    WHEN 'AccessShareLock' THEN 1   
    WHEN 'RowShareLock' THEN 2   
    WHEN 'RowExclusiveLock' THEN 3   
    WHEN 'ShareUpdateExclusiveLock' THEN 4   
    WHEN 'ShareLock' THEN 5   
    WHEN 'ShareRowExclusiveLock' THEN 6   
    WHEN 'ExclusiveLock' THEN 7   
    WHEN 'AccessExclusiveLock' THEN 8   
    ELSE 0   
  END  ) DESC,   
  (CASE WHEN granted THEN 0 ELSE 1 END)  
) AS lock_conflict  
FROM t_unionall   
GROUP BY   
locktype,datname,relation,page,tuple,virtualxid,transactionid::text,classid,objid,objsubid ;

查看特定表名锁信息, 如果有其他处于 idle in transaction 的进程,则找到 mppsessionid

=# SELECT * FROM pg_locks WHERE relation='t1_p'::regclass;
 locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction |  pid   |       mode       | g
ranted | fastpath | mppsessionid | mppiswriter | gp_segment_id 
----------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+--------+------------------+--
-------+----------+--------------+-------------+---------------
 relation |   693089 |  2693588 |      |       |            |               |         |       |          | 23/40692           | 100289 | RowExclusiveLock | t
       | t        |        37099 | t           |            -1
 relation |   693089 |  2693588 |      |       |            |               |         |       |          | 33/198609          | 100676 | AccessShareLock  | t
       | t        |        37099 | t           |             4
 relation |   693089 |  2693588 |      |       |            |               |         |       |          | 33/198609          | 100676 | RowExclusiveLock | t
       | t        |        37099 | t           |             4
(3 rows)

查看事务是否处于 waiting 状态:

[mxadmin@sdw21 gpconfigs]$ gpssh -f ./seg_host 
=> ps -ef|grep 37099
[sdw18] mxadmin  213588 152755  0 21:19 ?        00:00:00 postgres:  8000, mxadmin test 192.168.100.32(31024) con37099 seg8 idle
[sdw18] mxadmin  213589 152762  0 21:19 ?        00:00:00 postgres:  8001, mxadmin test 192.168.100.32(20614) con37099 seg9 idle
[sdw18] mxadmin  213590 152766  0 21:19 ?        00:00:00 postgres:  8002, mxadmin test 192.168.100.32(22542) con37099 seg10 idle
[sdw18] mxadmin  213591 152778  0 21:19 ?        00:00:00 postgres:  8003, mxadmin test 192.168.100.32(45560) con37099 seg11 idle
[sdw18] mxadmin  213592 152782  0 21:19 ?        00:00:00 postgres:  8004, mxadmin test 192.168.100.32(27438) con37099 seg12 idle
[sdw18] mxadmin  213593 152788  0 21:19 ?        00:00:00 postgres:  8005, mxadmin test 192.168.100.32(47258) con37099 seg13 idle
[sdw18] mxadmin  213594 152791  0 21:19 ?        00:00:00 postgres:  8006, mxadmin test 192.168.100.32(62898) con37099 seg14 idle
[sdw18] mxadmin  213966 212889  0 21:20 pts/2    00:00:00 grep --color=auto 37099
[sdw19] mxadmin  236149 203253  0 21:19 ?        00:00:00 postgres:  8000, mxadmin test 192.168.100.32(27718) con37099 seg16 idle
[sdw19] mxadmin  236150 203248  0 21:19 ?        00:00:00 postgres:  9007, mxadmin test 192.168.100.32(37320) con37099 seg15 idle
[sdw19] mxadmin  236151 203267  0 21:19 ?        00:00:00 postgres:  8003, mxadmin test 192.168.100.32(64854) con37099 seg19 idle
[sdw19] mxadmin  236152 203263  0 21:19 ?        00:00:00 postgres:  8002, mxadmin test 192.168.100.32(65230) con37099 seg18 idle
[sdw19] mxadmin  236153 203257  0 21:19 ?        00:00:00 postgres:  8001, mxadmin test 192.168.100.32(40968) con37099 seg17 idle
[sdw19] mxadmin  236154 203269  0 21:19 ?        00:00:00 postgres:  8004, mxadmin test 192.168.100.32(54360) con37099 seg20 idle
[sdw19] mxadmin  236155 203278  0 21:19 ?        00:00:00 postgres:  8005, mxadmin test 192.168.100.32(41424) con37099 seg21 idle
[sdw19] mxadmin  236156 203279  0 21:19 ?        00:00:00 postgres:  8006, mxadmin test 192.168.100.32(41532) con37099 seg22 idle
[sdw19] mxadmin  236157 203280  0 21:19 ?        00:00:00 postgres:  8007, mxadmin test 192.168.100.32(23184) con37099 seg23 idle
[sdw19] mxadmin  236295 235047  0 21:20 pts/1    00:00:00 grep --color=auto 37099
[sdw20] mxadmin  188516  35758  0 21:19 ?        00:00:00 postgres:  8000, mxadmin test 192.168.100.32(47346) con37099 seg24 idle
[sdw20] mxadmin  188517  35773  0 21:19 ?        00:00:00 postgres:  8003, mxadmin test 192.168.100.32(59058) con37099 seg27 idle
[sdw20] mxadmin  188518  35779  0 21:19 ?        00:00:00 postgres:  8004, mxadmin test 192.168.100.32(58736) con37099 seg28 idle
[sdw20] mxadmin  188519  35767  0 21:19 ?        00:00:00 postgres:  8002, mxadmin test 192.168.100.32(11736) con37099 seg26 idle
[sdw20] mxadmin  188520  35783  0 21:19 ?        00:00:00 postgres:  8005, mxadmin test 192.168.100.32(45638) con37099 seg29 idle
[sdw20] mxadmin  188521  35760  0 21:19 ?        00:00:00 postgres:  8001, mxadmin test 192.168.100.32(52888) con37099 seg25 idle
[sdw20] mxadmin  188522  35784  0 21:19 ?        00:00:00 postgres:  8006, mxadmin test 192.168.100.32(42540) con37099 seg30 idle
[sdw20] mxadmin  188523  35785  0 21:19 ?        00:00:00 postgres:  8007, mxadmin test 192.168.100.32(41324) con37099 seg31 idle
[sdw20] mxadmin  188650 187294  0 21:20 pts/1    00:00:00 grep --color=auto 37099

解决方案

  1. 如果确实发现处于 waiting 的事务,或者事务一直没有完成,尽管拿到的是行级锁,也会影响自动创建子分区。

  2. 找到具体的 pid ,然后通过 SELECT pg_terminate_backend(pid); 语句杀掉此进程。

  3. plpython UDF 不接受 kill 信号。

  4. 建议采用 kill -3 杀掉进程,最好不要用 kill -9。


4 mxgate 排除某一列


命令行使用时,通过参数 --exclude-columns 排除指定的列即可, 如是以后台运行模式,则在配置文件修改参数 exclude-columns=["列名"], 重启生效即可。

示例

以命令的方式进行加载 CSV 文件(有表头),采用 tail -n +2 命令排除第一列。

$ tail -n +2 /home/mxadmin/workspace/nyc-taxi-data/yellow_tripdata_2016-01.csv | mxgate --source stdin --db-database postgres --db-master-host mdw --db-master-port 5432 --db-user mxadmin --time-format raw --target trip --parallel 256  --delimiter ','  --exclude-columns trip_duration 


5 mxgate 流式加载增加列不停服的办法


  1. 准备测试数据
// 建表
CREATE TABLE t1(id int,a int);
// 生成测试数据
INSERT INTO t1 SELECT i,i FROM generate_series(1,10) AS i;
// 导出到文件
COPY t1 TO '/home/mxadmin/data/t1.csv' WITH delimiter '|';
// 清空
TRUNCATE TABLE t1;
  1. 生成配置文件
$ mxgate config --db-database postgres \
            --db-master-host localhost \
            --db-master-port 6432 \
            --db-user mxadmin \
            --target public.t1 \
            --time-format raw \
            --delimiter '|' \
            > mxgate.conf
  1. 启动 mxgate
$ mxgate start --config mxgate.conf 
******************************************************
 __  __       _        _       ____       _       
|  \/  | __ _| |_ _ __(_)_  __/ ___| __ _| |_ ___ 
| |\/| |/ _` | __| '__| \ \/ / |  _ / _` | __/ _ \
| |  | | (_| | |_| |  | |>  <| |_| | (_| | ||  __/
|_|  |_|\__,_|\__|_|  |_/_/\_\\____|\__,_|\__\___|
  Version: v4.6.5+Dev (git: master 4f01c039)
  Your Copy is Licensed to: http://www.ymatrix.cn
******************************************************
Launching MatrixGate daemon...
MatrixGate daemon started successfully
  1. 加载数据
curl http://localhost:8086/ -X POST -H 'Content-Type: text/plain' --data-binary "@t1.csv"
  1. 查看数据
postgres=# SELECT * FROM t1;
 id  | a 
-----+-----
  1 |  1
  2 |  2
  3 |  3
  4 |  4
  5 |  5
  1. 暂停 mxgate

指定进程 pid 暂停。

$ mxgate pause -X -S -p 133478 

指定 job 名称 schema.table 暂停。

$ mxgate pause -X -S --job public.t1

pause 默认是异步的,这时还有行排他锁。如果要添加字段,会等待行排他锁结。
加上 -S 参数,就代表是暂停 mxgate 进程是同步执行的。

输出如下:

******************************************************
 __  __       _        _       ____       _       
|  \/  | __ _| |_ _ __(_)_  __/ ___| __ _| |_ ___ 
| |\/| |/ _` | __| '__| \ \/ / |  _ / _` | __/ _ \
| |  | | (_| | |_| |  | |>  <| |_| | (_| | ||  __/
|_|  |_|\__,_|\__|_|  |_/_/\_\\____|\__,_|\__\___|
  Version: v4.6.5+Dev (git: master 4f01c039)
  Your Copy is Licensed to: http://www.ymatrix.cn
******************************************************
begin to pause all jobs, please wait...
public.t1 paused

暂停 mxgate 任务时,会将 web 外部表的定义删除。

  1. 增加一个字段
=# ALTER TABLE t1 ADD COLUMN b int;
  1. 重新启动指定的任务
$ mxgate resume -R --job public.t1

恢复 mxgate 进程时,会再次创建外部表。

  1. 加载数据
$ curl http://localhost:8086/ -X POST -H 'Content-Type: text/plain' --data-binary "@t1.csv"

数据加载正常。


6 mxgate socket 文件缺失?


正常情况下 socket 文件如下:

$ cat /tmp/.s.MXGATED.4329.17056.lock 
## This mxgate process is part of MatrixDB internal tools
90969
/var/log/matrixdb/matrixgate.2022-09-15_093212-90969.log
0
4329.17056
17056
/tmp/mxgate.conf

经过排查,是 /tmp/.s.MXGATED.8086.0.lock 文件如果长时间没有被使用,文件可能会被系统删除。

解决方案

$ ps -ef |grep mxgate
mxadmin   59272 277634  0 11:57 pts/1    00:00:00 grep --color=auto mxgate
mxadmin   68731      1 40 Jan27 ?        7-11:13:10 /opt/ymatrix/matrixdb-5.0.0+enterprise/bin/mxgated daemon --config mxgate_chj_iot.conf
$ kill 68731
$ touch /tmp/.s.MXGATED.8086.0.lock
$ cat /tmp/.s.MXGATED.8086.0.lock  # 内容不重要,关键是文件要有 6 行
336941
$ wc -l /tmp/.s.MXGATED.8086.0.lock 
6 /tmp/.s.MXGATED.8086.0.lock
$ chmod 644 .s.MXGATED.8086.0.lock
$ mxgate status

******************************************************
 __  __       _        _       ____       _       
|  \/  | __ _| |_ _ __(_)_  __/ ___| __ _| |_ ___ 
| |\/| |/ _` | __| '__| \ \/ / |  _ / _` | __/ _ \
| |  | | (_| | |_| |  | |>  <| |_| | (_| | ||  __/
|_|  |_|\__,_|\__|_|  |_/_/\_\\____|\__,_|\__\___|
  Version: v4.3.13 (git: HEAD cef61ced)
  Your Copy is Licensed to: yMatrix.cn; 2022-04-13; any
******************************************************
PID          336941 alive
Launched At  2022-01-28 21:08:16
Up For       18 days 0 hours 39 minutes 15 seconds
Binary       /opt/ymatrix/matrixdb-5.0.0+enterprise/bin/mxgated
Log          
Config    


7 data format error: invalid input syntax for type integer: "1970-01-01 00:00:01"


问题分析

mxgate 设计之初主要是为了快速加载时序类数据,默认第一列为时间类型。

解决方案

mxgate 中的参数 time-format 默认为 unix-second,将其改为 raw 即可。


8 mxgate 入库时间字段默认值相差 8 小时


问题分析

mxgate 在参数 time-format 默认为 unix-second,会导致入数相差 8 小时。

解决方案

mxgate 中的参数 time-format 默认为 unix-second,将其改为 raw 即可。


9 Aborting operation regardless of REJECT LIMIT value, last error was: invalid input syntax for type timestamp: ""22:31:01"", column batch_num


问题分析

mxgate 数据加载,源端和目标端数据类型不一致报错。

表结构。

=# CREATE TABLE s1.test1
 id                   character varying(36),
 created_date_time    timestamp(6) without time zone , 
 modified_date_time   timestamp(6) without time zone ,
 substep              character varying(36)        ,
 substep_id           character varying(6)         ,
 txdate               date                         ,
 batch_num            time(0) without time zone    
 )
DIETRIBUTED BY (id)

执行命令。

$ mxgate  --source transfer --src-host 172.26.14.15 --src-port 5432 --src-db wdp --src-user user1 --src-password password1 --src-schema s1 --src-table test1 --compress "gzip" --port-base 9000 --local-ip 172.26.14.17 --db-master-host 172.26.14.17 --db-database wdp --target s1.test1 --format csv --time-format raw --use-auto-increment=false

后台 Segment 报错日志。

"Aborting operation regardless of REJECT LIMIT value, last error was: invalid input syntax for type timestamp: ""22:31:01"", column batch_num",

解决方案

将目标端的 batch_num 修改为time(0) without time zone 类型,两边的数据类型需要保持一致。


10 ERROR c.s.o.matrixdb.MatrixdbSource 77 -MatrixdbSource sendingPostRequest errorCode: 400, errorMsg: target table name is empty


问题分析

在通过 HTTP 方式写入 mxgate 时提示表为空。

解决方案

  1. 检查 HTTP 写入时的表填写是否正确。
  2. 查看 mxgate.conf 配置文件中表名与数据库中的表是否正确。


11 responseCode:500 errorMsg: ERROR: invalid byte sequence for encoding "UTF8": 0x81


问题分析

在通过 HTTP 方式写入 mxgate 时提示编码错误。

解决方案

请检查源数据中是否有 ASCII 符号。


12 body size exceeds the given limit


问题分析

在通过 HTTP 方式写入 mxgate 时发送的数据量超过了 max-body-bytes 的限制,默认值是 4M,可以在 mxgate.conf 配置文件中查看。

解决方案

按需修改 mxgate.confmax-body-bytes 大小,然后进行重启。


13 you license is expired 2022-11-02


启动 MatrixGate 报错:

you license is expired 2022-11-02

问题分析

License 授权到期。

解决方案

首先,向 YMatrix 售后技术人员或者销售人员申请新的 License。

然后,在所有节点上将老的 License 文件删除。

$ cd /opt/ymatrix/matrixdb5/bin
$ rm LICENSE_${OLD} 

在所有节点上将新的 License 文件上传到 /opt/ymatrix/matrixdb5/bin,并授予 755 权限。

$ chmod 755 LICENSE_${NEW}


14 使用 MatrixGate 迁移数据报错:Cannot start source: --local-ip localhost is not a valid IP address


问题分析

使用 mxgate 迁移数据报错。

迁移代码:

[mxadmin@mdw ~]$ mxgate --source transfer \
       --src-host localhost \
       --src-port 5432 \
       --src-db mxdb_poc \
       --src-user mxadmin \
       --src-password 123123 \
       --src-schema public \
       --src-table t_hash \
       --compress "lz4" \
       --port-base 9393 \
       --local-ip localhost \
       --db-database mxdb_poc \
       --db-user mxadmin \
       --db-password 123123 \
       --target public.t_hash_new \
       --format csv \
       --parallel 256 \
       --stream-prepared 0 \
       --interval 250 \
       --time-format raw

报错日志:

main.go:210: 2022-12-24:21:29:43.018 matrixgate:mxadmin:sdw4:023119-[CRITICAL]:-2022-12-24:21:29:43.018 matrixgate:mxadmin:sdw4:023119-[CRITICAL]:-Cannot start source: --local-ip localhost is not a valid IP address
github.com/ymatrix-data/go-common-libs/utils/logger.FatalOnError
    /home/runner/go/pkg/mod/github.com/ymatrix-data/go-common-libs@v1.12.4/utils/logger/logger.go:395
main.failQuit.func1
    /home/runner/work/matrixdb-ci/matrixdb-ci/src/bin/mxgated/main.go:210
sync.(*Once).doSlow
    /opt/hostedtoolcache/go/1.19.2/x64/src/sync/once.go:74
sync.(*Once).Do
    /opt/hostedtoolcache/go/1.19.2/x64/src/sync/once.go:65
main.failQuit
    /home/runner/work/matrixdb-ci/matrixdb-ci/src/bin/mxgated/main.go:207
main.main
    /home/runner/work/matrixdb-ci/matrixdb-ci/src/bin/mxgated/main.go:113
runtime.main
    /opt/hostedtoolcache/go/1.19.2/x64/src/runtime/proc.go:250
runtime.goexit
    /opt/hostedtoolcache/go/1.19.2/x64/src/runtime/asm_amd64.s:1594
exit status 1

解决方案

将迁移模式当中的参数 --local-ip 改写成实际的物理 IP 地址,例如:192.168.247.132。 改写后的迁移代码如下:

[mxadmin@mdw ~]$ mxgate --source transfer \
       --src-host localhost \
       --src-port 5432 \
       --src-db mxdb_poc \
       --src-user mxadmin \
       --src-password 123123 \
       --src-schema public \
       --src-table t_hash \
       --compress "lz4" \
       --port-base 9393 \
       --local-ip 192.168.247.132 \
       --db-database mxdb_poc \
       --db-user mxadmin \
       --db-password 123123 \
       --target public.t_hash_new \
       --format csv \
       --parallel 256 \
       --stream-prepared 0 \
       --interval 250 \
       --time-format raw


15 使用 MatrixGate 数据加载表数据存在双引号


问题分析

我们可以通过创建测试表来分析此问题。具体步骤如下:

  1. 创建测试表
[mxadmin@mdw ~]$ psql -d mxdb
mxdb=# CREATE TABLE public.test(order_no text,info text) DIETRIBUTED BY(order_no);
  1. 查看测试数据
[mxadmin@mdw ~]$ cat test.csv 
"1x01"|"A"
"1x02"|"B"
"2x01"|"C"
"2x02"|"D"
"3x01"|"E"
"3x02"|"F"
  1. 使用 MatrixGate 执行数据加载命令
[mxadmin@mdw ~]$ cat test.csv| \
mxgate --source stdin \
--db-database mxdb_poc \
--db-master-host 127.0.0.1 \
--db-master-port 5432 \
--db-user mxadmin \
--db-password 123123 \
--time-format raw \
--delimiter "|" \
--target public.test \
--parallel 256 \
--stream-prepared 0 \
--interval 250
  1. 查看数据表里面的数据,发现存在双引号,问题得到复现
mxdb=# SELECT * FROM test;
 order_no | info 
----------+------
 "1x01"   | "A"
 "1x02"   | "B"
 "3x01"   | "E"
 "2x01"   | "C"
 "2x02"   | "D"
 "3x02"   | "F"
(6 rows)

而我们想要的理想结果应当如下:

mxdb=# SELECT * FROM test;
 order_no | info 
----------+------
 1x01     | A
 1x02     | B
 2x01     | C
 2x02     | D
 3x01     | E
 3x02     | F
(6 rows)

解决方案

执行数据加载的时候,加上参数 --format csv

[mxadmin@mdw ~]$ cat test.csv| \
mxgate --source stdin \
--db-database mxdb_poc \
--db-master-host 127.0.0.1 \
--db-master-port 5432 \
--db-user mxadmin \
--db-password 123123 \
--time-format raw \
--format csv \
--delimiter "|" \
--target public.test \
--parallel 256 \
--stream-prepared 0 \
--interval 250

这时,再查看数据表里面的数据,得到理想结果。

mxdb=# SELECT * FROM test;
 order_no | info 
----------+------
 1x01     | A
 1x02     | B
 2x01     | C
 2x02     | D
 3x01     | E
 3x02     | F
(6 rows)


16 MatrixGate 升级


问题描述

MatrixGate 在使用过程中因为特殊原因需要升级,但不知如何操作。

解决方案

  1. 将 MatrixGate 的写入程序关闭。

  2. 使用 mxadmin 用户将 MatrixGate 启动的 HTTP 服务停止。

[root@mdw ~]# su - mxadmin
[mxadmin@mdw ~]$ mxgate stop
  1. 使用 root 用户,关闭 Supervisor 服务。
[root@mdw ~]# systemctl stop matrixdb.supervisor.service
  1. 使用 root 用户,替换 MatrixGate 二进制文件。

首先,进入到 /bin 目录。

[root@mdw ~]# cd /usr/local/matrixdb/bin/

然后,将原来的二进制 MatrixGate 文件备份。

[root@mdw ~]# mv mxgate mxgate."bak."`date +%Y%m%d%H%M`
[root@mdw ~]# mv mxgated mxgated."bak."`date +%Y%m%d%H%M`

将新的 MatrixGate 二进制文件上传到 /usr/local/matrixdb/bin/, 并赋予 755 权限。

[root@mdw ~]# chmod 755 mxgate
[root@mdw ~]# chmod 755 mxgated

最后,查看替换后的版本信息。

[root@mdw ~]# su - mxadmin
[mxadmin@mdw ~]$ mxgate --version
  1. 使用 root 用户,启动 Supervisor 服务。
[root@mdw ~]# systemctl start matrixdb.supervisor.service
  1. 启动 MatrixGate。
[root@mdw ~]# su - mxadmin 
[mxadmin@mdw ~]$ mxgate start --config /home/mxadmin/mxgate.conf
  1. 启动 MatrixGate 前端的数据写入业务。


17 MatrixGate 需要加载包含 unix 时间数据的数据文件,但数据文件中 unix 数据所在的字段不是第一个字段


问题描述

使用 MatrixGate 加载 unix 时间数据,但数据文件中 unix 数据所在的字段不是第一个字段,因无法进行类型转换而报错。 我们可以通过创建测试表来复现并分析此问题。示例如下:

  1. 创建测试表
[mxadmin@mdw ~]$ psql testdb
testdb=# CREATE TABLE dest2(
    c1 int,
    c2 text,
    time timestamp,
    c3
)DISTRIBUTED BY(c1);
  1. 准备测试数据
[mxadmin@mdw ~]$ cat test2.csv
1,2,1603777821678,2
1,2,1603777822670,3
1,2,1603777823628,4
1,2,1603777824673,5
1,2,1603777825578,6
  1. 执行 MatrixGate 数据加载命令
[mxadmin@mdw ~]$ cat test2.csv| \
mxgate \
--source stdin \
--db-database testdb \
--db-master-host mdw \
--db-master-port 5432 \
--db-user mxadmin \
--time-format unix-ms \
--target dest2 \
--delimiter ',' \
--parallel 256 \
--stream-prepared 0

报错信息如下:

stdin.go:168: 2022-04-15:12:38:52.443 matrixgate:mxadmin:mdw:006560-[ERROR]:-[Source.STDIN] load error: data format error: invalid input syntax for type integer: "1970-01-01 00:00:00.001", column c1

问题分析

MatrixGate 默认把第一个字段当成时间字段进行转换。

解决方案

  1. 版本要求 MatrixGate v4.4.7 及更高版本。

  2. 生成 mxgate 配置文件

    [mxadmin@mdw ~]$ mxgate config --db-database testdb \
               --db-master-host localhost \
               --db-master-port 5432 \
               --db-user mxadmin \
               --target public.dest2 \
               --format csv \
               --time-format unix-ms \
               --delimiter ',' \
               --parallel 256 \
               --stream-prepared 0 \
               --interval 250 \
               --transform plain \
               --source stdin \
               > mxgate.conf
  3. 修改 mxgate 配置文件

    [mxadmin@mdw ~]$ vi mxgate.conf
    #找到对应的地方进行修改
    [[job.target]]
     # deduplicate-key = []
     delimiter = ","
     # error-handling = "accurate"
     # exclude-columns = []
     format = "csv"
     name = "job_csv_to_public.dest2"
     # null-as = ""
     schema = "public"
     table = "dest2"
     time-format = "unix-ms"
     # upsert-key = []
     # use-auto-increment = true
    #找到对应的地方进行修改
    transform = "plain"
    [transform.plain]
     mapping = [
         # secondsToTimestamp       秒级时间戳转换   1603777825          => 2020-10-27 05:50:25
         # millisecondsToTimestamp  毫秒级时间戳转换 1603777825123       => 2020-10-27 05:50:25.123
         # microsecondsToTimestamp  微秒级时间戳转换 1603777825123456    => 2020-10-27 05:50:25.123456
         # nanosecondsToTimestamp   纳秒级时间戳转换 1603777825123456789 => 2020-10-27 05:50:25.123457(注意:目前数据库只支持到微秒级时间戳精度,纳秒级时间戳会失真)
         {table-name = "public.dest2", field-map = [{dest = "c1", source = "0", enabled = true},
                                                    {dest = "c2", source = "1", enabled = true},
                                                    {dest = "ts", source = "2", enabled = true,transform = ["millisecondsToTimestamp"]},
                                                    {dest = "c3", source = "3", enabled = true},
                                                    ]}
                ]
  4. 配置说明

- table-name = "public.dest2" 指定表名;
- dest对应数据库每一列中的列名;
- source表示从进入mxgate的数据源获取dest对应列的方式:
- plain:进入 MatrixGate 的是csv数据,对应的source表示csv中的某一列的列号;
- json:进入 MatrixGate 的是JSON数据,对应的source是从一个JSON结构中获取dest对应值的JSON-Path表达式(关于JSON-Path可以参考这个文档JSON Path相关资料汇总 )
- enable=true表示该列数据需要通过 MatrixGate 写入到数据库,如果为false,则不写入;
- transform表示时间戳精度的转换函数:
- secondsToTimestamp:秒级时间戳转换
- millisecondsToTimestamp:毫秒级时间戳转换
- microsecondsToTimestamp:微秒级时间戳转换
- nanosecondsToTimestamp:纳秒级时间戳转换

注意
目前数据库只支持到微秒级时间戳精度,纳秒级时间戳会失真。

  1. 执行加载
    [mxadmin@mdw ~]$ tail -n +2 test2.csv| mxgate --config mxgate.conf


18 MatrixGate 加载数据文件中有 \N 字符


问题分析

我们可以通过创建测试表来复现并分析此问题。示例如下:

  1. 创建测试表
[mxadmin@mdw ~]$ psql -d mxdb
mxdb=# CREATE TABLE test(f1 int,f2 varchar(50),f3 varchar(50));
  1. 查看测试数据
[mxadmin@mdw ~]$ cat test.csv
1|test|\N
  1. 使用 MatrixGate 执行数据加载命令
[mxadmin@mdw ~]$ cat test.csv| \
mxgate --source stdin \
--db-database mxdb_poc \
--db-master-host 127.0.0.1 \
--db-master-port 5432 \
--db-user mxadmin \
--db-password 123123 \
--time-format raw \
--format csv \
--delimiter "|" \
--target public.test \
--parallel 256 \
--stream-prepared 0 \
--interval 250
  1. 查看数据表里面的数据,存在 N
mxdb=# SELECT * FROM test;
 f1 |  f2  | f3
----+------+----
  1 | test | N

理想结果应当如下:

mxdb=# SELECT * FROM test;
 f1 |  f2  | f3
----+------+----
  1 | test | 

解决方案

  1. 使用 MatrixGate 执行数据加载,加上参数 --null-as '\N'
[mxadmin@mdw ~]$ cat test.csv| \
mxgate --source stdin \
--db-database mxdb_poc \
--db-master-host 127.0.0.1 \
--db-master-port 5432 \
--db-user mxadmin \
--db-password 123123 \
--time-format raw \
--format csv \
--delimiter "|" \
--target public.test \
--parallel 256 \
--stream-prepared 0 \
--interval 250 \
--null-as '\N'
  1. 查看数据表里面的数据,得到理想结果
mxdb=# SELECT * FROM test;
 f1 |  f2  | f3
----+------+----
  1 | test | 


19 MatrixGate 通过迁移模式写入时出现 Handshaking was terminated on port XXX


问题分析

根据错误描述,初步确定是 SSH 握手中断导致。

继续排查源端数据库日志出现 lz4 | COPY XXX TO PROGRAM ssh -o StrictHostKeyChecking=no -p XXX 这样的报错,发现源端的操作系统是 Redhat 8.3,默认没有安装 lz4 软件包,导致 lz4 命令不识别,但是在写入命令有 --compress lz4 参数,所以导致报错。

解决方案

  1. 源端操作系统安装 lz4 软件包。
  2. 写入命令中去掉 --compress lz4 或者将参数调整为 --compress zstd


20 MatrixGate 可以实现任意列时间戳转换吗?


可以的。

注意!
此功能只在 MatrixGate v4.4.7 及更高版本支持。

  1. 数据库表结构样例
[mxadmin@mdw ~]$ psql testdb
testdb=# CREATE TABLE vehicle_basic_data_mars2(
  daq_time timestamp,
  vin varchar(32) ,
  lng float ,
  lat float ,
  speed float ,
  license_template varchar(16) ,
  flag integer
);
 Table "public.vehicle_basic_data_mars2"
      Column      |            Type             | Collation | Nullable | Default
------------------+-----------------------------+-----------+----------+---------
 daq_time         | timestamp without time zone |           |          |
 vin              | character varying(32)       |           |          |
 lng              | double precision            |           |          |
 lat              | double precision            |           |          |
 speed            | double precision            |           |          |
 license_template | character varying(16)       |           |          |
 flag             | integer                     |           |          |
  1. mxgate config 文件配置
  • 在 [transform]tag 下,首先配置 transform 的类型:
    • transform = "json":进入mxgate 的数据格式是 JSON;
    • transform = "plain":进入 mxgate 的数据格式是 CSV。
      [transform]
      ## Overall parallel level for transform, only for non-strict mode
      # parallel = 16
      ## Transform decodes input data and perform type/format conversion
      ## Types restricted to: plain/json/nil/tsbs
      # transform = "json"
      # [transform.json]
      #   mapping = [
      #       # secondsToTimestamp
      #       # millionSecondsToTimestamp
      #       # microsecondsToTimestamp
      #       # nanosecondsToTimestamp
      #       {table-name = "public.vehicle_basic_data_mars2", field-map = [{dest = "daq_time", source = "$.daq_time", enabled = true},
      #                                                                     {dest = "vin", source = "$.vin", enabled = true},
      #                                                                     {dest = "lng", source = "$.lng", enabled = true},
      #                                                                     {dest = "lat", source = "$.lat", enabled = true},
      #                                                                     {dest = "speed", source = "$.speed", enabled = true},
      #                                                                     {dest = "license_template", source = "$.license_template"},
      #                                                                     {dest = "flag", source = "$.flag", enabled = true},
      #                                                                   ]}
      #   ]
      transform = "plain"
      [transform.plain]
      mapping = [
          # secondsToTimestamp
          # milliSecondsToTimestamp
          # microsecondsToTimestamp
          # nanosecondsToTimestamp
          {table-name = "public.vehicle_basic_data_mars2", field-map = [{dest = "daq_time", source = "0", enabled = true, transform = ["secondsToTimestamp"]},
                                                                        {dest = "vin", source = "1", enabled = true},
                                                                        {dest = "lng", source = "2", enabled = true},
                                                                        {dest = "lat", source = "3", enabled = true},
                                                                        {dest = "speed", source = "4", enabled = true},
                                                                        {dest = "license_template", source = "5"},
                                                                        {dest = "flag", source = "6", enabled = true},
                                                                      ]}
      ]
  • 配置说明:
    • table-name = "public.vehicle_basic_data_mars2" 指定表名;
    • dest 对应数据库每一列中的列名;
    • source 表示从进入 mxgate 的数据源获取 dest 对应列的方式:
      • plain:进入 mxgate 的是 CSV 数据,对应的 source 表示 CSV 中的某一列的列号;
      • json:进入 mxgate 的是 JSON 数据,对应的 source 是从一个 JSON 结构中获取 dest 对应值的 JSON-Path 表达式;
    • enable=true 表示该列数据需要通过 mxgate 写入到数据库,如果为 false,则不写入;
    • transform 表示时间戳精度的转换函数:
      • secondsToTimestamp:秒级时间戳转换
      • milliSecondsToTimestamp:毫秒级时间戳转换
      • microsecondsToTimestamp:微秒级时间戳转换
      • nanosecondsToTimestamp:纳秒级时间戳转换

        注意!
        目前数据库只支持到微秒级时间戳精度,纳秒级时间戳会失真。

  1. 注意事项

(1). format 配置为 CSV

  • 全局 format 配置
    ## Data format to be read: text or csv
    ##   text : faster but cannot have delimiter or line breaks in textual fields
    ##   csv  : supports delimiter or line break in textual fields, must be double-quoted
    format = "csv"
  • Job format 配置
    ## Schema and table name must be in lower-case
    [[job.target]]
    # delimiter = "|"
    format = "csv"
    name = "public.vehicle_basic_data_mars2"
    schema = "public"
    table = "vehicle_basic_data_mars2"
    time-format = "raw"

    (2). mapping 中,数据库的每一列都需要配置,不能只配置需要时间戳转换的列,如果有哪一列没有配置,则该列的数据无法写入到 YMatrix。
    (3). 原来的 time-format 需要配置为 raw
    (4). 支持同时配置多列时间戳转换。
    (5). 对于 transform 中 json 或者 plain 的配置,同一个 mxgate 进程同一时间只能配置一个。


21 MatrixGate JAVA SDK JAR 包可以下载到本地导入吗?


可以的。

首先,点击下载 SDK 最新版本,按照如下图示操作,图示中为 v1.0.17,按照图示步骤替换为最新版本即可。

在此介绍三种导入本地 JAR 包的方法:使用 Maven 工具,使用 Gradle 工具,以及使用 IntelliJ IDEA 集成开发环境,任选其一即可。导入方法多元,你也完全可以选用其他开发环境和工具使操作更为顺手。

  1. 使用 Maven 工具

随后,在 pom.xml 文件中配置如下内容:

<!-- 在 pom.xml 文件中配置 -->
<dependencies>
    ...
    <dependency>
        <groupId>cn.ymatrix</groupId>
        <artifactId>mxgate-sdk-java</artifactId>
        <version>1.0</version>
        <scope>system</scope>
        <!-- systemPath中填入 JAR 包的绝对路径, 这里 ${project.basedir} 指的是当前 project 文件夹路径 -->
        <systemPath>${project.basedir}/lib/mxgate-sdk-java-1.0.jar</systemPath>
    </dependency>
    ...
</dependencies>

注意!
若你使用 IntelliJ IDEA 集成开发环境操作,可以设置 auto-reloading 自动更新文件。若未设置 auto-reloading,运行完毕新添加代码后,需点击右上角“m”按钮手动更新文件。

最后,为了保障 JAR 包的使用(不会出现 class not found 相关报错),还需要在 pom.xml 中增加以下内容,使得 target 文件夹包含所需依赖。

<plugins>
    ...
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
            <!-- 指定 jdk 版本,与本地一致即可, 若为1.8 则填入8即可-->
            <source>8</source>
            <target>8</target>
            <compilerArguments>
                <!-- 指定 local jar 所在目录,下例中在project下lib目录存放local jar -->
                <extdirs>${project.basedir}/lib</extdirs>
            </compilerArguments>>
        </configuration>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.2.2</version>
        <configuration>
            <archive>
                <manifest>
                    <!-- 在生成jar文件时向MANIFEST.MF中添加 classpath -->
                    <addClasspath>true</addClasspath>
                    <!-- 定义上述 classpath 的前缀, 需要与下面 maven-dependency-plugin 的 outputDirectory 一致 -->
                    <classpathPrefix>lib</classpathPrefix>
                    <mainClass>Main.Main</mainClass>
                </manifest>
                <manifestEntries>
                    <!-- 把 jar 加入到 MANIFEST.MF -->
                    <Class-Path>lib/mxgate-sdk-java-1.0.jar</Class-Path>
                </manifestEntries>>
            </archive>
        </configuration>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>copy-dependencies</id>
                <phase>prepare-package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
                <configuration>
                    <!-- 在 maven 产物target目录下生成lib目录,并把所有远程和本地的jar拷贝到该目录下 -->
                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                </configuration>
            </execution>
        </executions>
    </plugin>
    ...
</plugins>

完成。

  1. 使用 Gradle 工具

假设 JAR 包存放在本地 libs 路径下,使用以下代码导入本地 JAR 包:

repositories {
   flatDir {
       dirs 'libs'
   }
}
dependencies {
   implementation name: 'cn.ymatrix:mxgate-sdk-java:1.0.17'
}
  1. 使用 IntelliJ IDEA 集成开发环境


选择本地路径下的 mxgate-sdk-java.jar 文件。 确认 JAR 包已经成功导入到当前工程。


22 Kafka 消费 key 字段包含 @ 符号,数据解析找不到 value


问题分析

特殊字符 @ 无法正常解析。

问题复现

  1. 测试数据
    {
     "@timestamp": "2023-04-21T04:00:23.413+08:00",
     "@version": "1",
     "message": ">End--->.<Tid 189> Response(code=330110, description=, responseTime=1682020823413, responseBody=FlowVO(tips=请求异常,请稍后再试, flowData=null, queryTime=1682020823411, errCode=1))",
     "logger": "com.reachauto.cloud.log.aop.LogAspect",
     "thread": "XNIO-1 task-3",
     "level": "DEBUG",
     "levelVal": 10000,
     "springAppName": "reachcloud-vsp-sdk-bff-auth",
     "kafaServer": "test1.com.com:9092,test2.com:9092",
     "springProfileActive": "test",
     "callerSource": "auth_sdk",
     "ydtargs": "[89860803192030000383]",
     "ydtpath": "/api/v1/flow/query",
     "ydtuserid": "5816d78e4rh31aa5a3c1bce523a764deea36cfd551fcbdbb8",
     "callerVersion": "1.30.17",
     "ydttype": "message",
     "ydtmethod": "GET",
     "PtxId": "6883576",
     "PspanId": "-5187341585210826311",
     "grayVersion": "unknown",
     "ydtrequrl": "http://vsp-show-vehicle.reachauto-mobility.com/api/v1/flow/query",
     "ydttime": "233",
     "ydtusertype": "VU",
     "ydtclass": "FlowController.queryFlow(String)",
     "caller":
     {
         "class": "com.reachauto.cloud.log.aop.LogAspect",
         "method": "around",
         "file": "LogAspect.java",
         "line": 99
     }
    }
  2. 在图形化界面(Mxui)配置对应的 Kafka 数据接入

解决方案

  1. 在图形化界面配置失败后,找到对应生成的 mxgate.conf 文件。修改对应的 transform.json
    source = "$.@timestamp" --> source = "$['@timestamp']"
    source = "$.@Version" --> source = "$['@Version']"
  2. 在主机层面通过命令行启动服务,key 字段包含 @ 符号,数据消费正常。


23 mxgate 迁移模式非 mxadmin 用户提示没有权限


当使用 mxgate 的迁移模式时报错:

Create external table failed: create external table error for public.ddd_back, ERROR: permission denied: no privilege to create a readable gpfdist(s) external table (SQLSTATE 42501), will retry after 3 seconds

问题分析

用户使用 mxgate 迁移模式时需要通过创建外部表来同步数据,而使用非 mxadmin 用户时则没有创建外部表的权限。

解决方案

  1. 使用 mxgate 迁移模式时,使用 mxadmin 用户,使用 mxadmin 用户不会改变原表的权限。

  2. 给其他用户赋予外部表的权限,或者把其他用户提升为高权限。