前言
先还原一个很多人都经历过的场面。
数据规模上 T 的库要迁金仓,KDTS 装好,任务建好,点开始。然后你盯着进度条看了十分钟,它挪了 2%。这时候人的第一反应通常是:这工具是不是不行?
大概率不是工具的问题。默认参数是给小规模库兜底的,几十个 G、几百张表,怎么跑都无所谓。数据量一大就顶不住了------线程数保守、内存给得抠、目标库还是出厂设置,三样叠一起,快得起来才怪。
这篇把大数据量迁移的调优三板斧讲透:线程怎么算、JVM 内存怎么给、金仓端参数怎么改。全是能直接抄走用的东西。
一、动手之前,先搞清楚慢在哪
KDTS 迁移的本质,说白了就是个搬运工:从 Oracle 那头把数据读出来,经过自己中转,再写进金仓这一头。全程三个环节------源端读、工具中转、目标端写,干的全是网络 IO 加磁盘 IO 的活儿。
这种活儿有个特点:线程大部分时间在等。等网络回包,等磁盘转身,CPU 闲得发慌,活儿却推不动。
所以调优思路也就清楚了。一是把等待的空档利用起来------多开线程;二是中转站要够大------JVM 内存给足;三是接收端敞开门收货------金仓端参数放开。三件事对应后面三章,挨个说。
顺便提醒一句:先确认瓶颈再动手。源端磁盘老旧、网络只有百兆、目标库和数据目录挤同一块盘,这三种属于硬件债,调参数救不了,先把环境理顺再谈调优。
二、线程数怎么定:一个公式,别拍脑袋
线程不是越多越好,也不是拍脑袋填个数。官方给的思路很明确:数据迁移是 IO 密集型任务,按 IO 密集型的公式算------
线程数 = CPU 核心数 ÷(1 - 阻塞系数)
阻塞系数取 0.8 到 0.9,一般取 0.9。取 0.9 有个好处:分母正好是 0.1,公式退化成"核心数 × 10",心算都够用。
放张速算表,直接对号入座:
| 机器配置 | 阻塞系数取 0.9 时的线程数 |
|---|---|
| 4 核 | 40 |
| 8 核 | 80 |
| 16 核 | 160 |
| 32 核 | 320 |
| 64 核 2 路(共 128 核) | 1280 |
改哪儿?SHELL 版的 KDTS,配置在 conf/kb-thread-config.xml 里,照着公式调线程池就行;BS 版更省事,建任务时"线程配置"那一步直接在页面上填。
两个提醒,都挺值钱。
一是别上头。线程翻倍,速度不会翻倍------线程上下文切换本身是要花钱的,超过公式算出来的量,多开的线程全在内耗。
二是看部署。KDTS 如果跟金仓数据库挤在同一台服务器上,就别把公式算满,资源大头要留给数据库,线程数往下减,减多少看数据库吃多少。当然,最好还是分开部署,各干各的,互不抢食。
三、JVM 内存:线程喂饱了,堆也得跟上
这两件事是连着的。线程开多了、游标读取量调大了,每个线程手里都攥着一批数据等着写,堆内存的需求跟着水涨船高。堆不给够,轻则 GC 抽风、速度忽快忽慢,重则直接 OOM 给你看。
JVM 参数在启动脚本里改。SHELL 版进 bin 目录,编辑 startup.sh,找 JAVA_OPT 那行:
bash
JAVA_OPT="-server -Dfile.encoding=UTF-8 -Dconfig.path=${CONFIG_DIR} -Xmx16g -Xms16g"
关键就两个:-Xmx 是堆上限,-Xms 是初始堆。建议设成一样的值,跑起来不用反复扩堆,省心也省性能。给多少?看机器:内存减掉操作系统和数据库要的,剩下的大部分给到 -Xmx,先这么起步,跑一轮再看要不要收。
顺带说两句 JDK。版本要 JDK 11 或更高;用解压版直接放进 KDTS 自带的 jdk 目录就好,别装进系统、别加环境变量------迁移工具是临时工,别让它污染服务器上其他应用。另外 KDTS 默认会自动探测 JVM 内存,你手动改这一行,就是接管了这个逻辑。
四、目标端金仓:别用出厂设置接货
搬家的卡车在门口排队了,接收方也得开门腾地方。金仓端三件事要做。
头一件,shared_buffers。默认才 128M,这是给演示环境准备的量。生产迁移建议调到物理内存的四分之一,64G 的机器给 16G,不心疼。改 kingbase.conf,重启生效:
ini
# kingbase.conf
shared_buffers = 16GB # 建议物理内存的 1/4,默认 128M 实在太小
第二件,空间和文件预分配。数据目录所在磁盘,空间按迁移规模的 1.5 倍以上留。规模大的库,迁移前预先创建够大的数据文件和日志文件------不然数据库边写边扩,每次扩容都是一次 IO 抖动,攒多了很伤速度。
第三件,参数对齐。这块最容易翻车,说两个典型的坑。
字符集。源端 Oracle 是 ZHS16GBK,金仓 initdb 就选 GBK,一头一头对上。一头 GBK 一头 UTF8,转码开销是小事,乱码才是大事。源端编码这么查:
sql
select userenv('language') from dual;
-- 返回形如 SIMPLIFIED CHINESE_CHINA.ZHS16GBK
Oracle 还有些冷门字符集,US7ASCII、WE8ISO8859P1 之类的,中文经过它们必乱码。KDTS 里有配套的解码参数(characterNeedDecoding 一族),真碰上了,按手册对号入座去设。
日期格式。Oracle 里要是存过 '0099-09-30' 这种年份,工具导出来会变成 '99-09-30',金仓默认把 99 认成月份,直接报 date/time field value out of range,任务当场中断。提前在配置文件里把 datestyle 设成 'ISO,YMD',按年月日解析,这个坑就填上了。
还有个不起眼的 nls_length_semantics。金仓默认 CHAR,Oracle 那边常见是 BYTE,不一致的话,char 类型迁过去可能带着一串莫名其妙的空格。查清源端的值,把金仓这边设成一致的。
五、任务参数:默认值是及格线,不是天花板
线程、内存、目标库都弄利索了,最后看任务本身。KDTS 建任务时那一堆配置项,默认值对大数据量基本都不合适。挑影响大的列张表:
| 参数 | 默认值 | 大数据量场景怎么调 |
|---|---|---|
| 源库游标读取记录数(fetch-size) | 100 | 适当调大读得更顺,代价是吃内存,跟 JVM 配合着调 |
| 批量写入目标库记录数 | 1000 | 一般够用,写入偏慢再加大 |
| 每次批量提交大小 | 100MB | 大字段多的库重点照顾这个 |
| LOB 字段预读取大小 | 4000Byte | 大对象多就调大,别让大字段拖累全队 |
| 大表拆分阈值(行数/大小) | --- | 核心开关!超阈值的表自动拆块并行搬 |
| 源/目标数据库连接数 | 100 | 要和线程数配套,线程多连接少等于白搭 |
| 表排序依据 | 按行数和大字段大小交替 | 保持默认,大表先动工 |
重点展开两个。
大表拆分,这是大数据量迁移的命根子。一张两亿行的表不拆,就是一个线程从头搬到尾------你开 160 个线程,159 个在旁边看热闹。把拆分阈值设好,超线的大表自动切块、多线程并搬,效率差着数量级。行数和大小两个阈值都能设,另有拆分条件文件可以用,它的优先级更高,想精细控制切法就上它。
表排序。默认那个"按行数和大字段大小交替"其实挺科学------大表先上工,避免小表全搬完了、只剩一张巨表单线程收尾的尴尬收场。这个默认值,别乱动。
调参别一把梭。一次只动一个,拿几张中等规模的表试跑,看吞吐变化,心里有数了再动下一个。
六、怎么知道调优生效了
别凭感觉,看数。
迁移前先摸底,搞清楚要搬多少东西:
sql
select segment_name, round(bytes / 1024 / 1024 / 1024, 2) as size_gb
from user_segments
where segment_type = 'TABLE'
order by bytes desc;
跑起来之后盯三个地方:KDTS 的迁移日志,吞吐和报错都在里面;操作系统的 IO 指标,iostat 看磁盘利用率和带宽有没有打满;目标库的写入情况。
一个容易误判的点:CPU 使用率不高是正常的,IO 密集型任务就长这样,别看见 CPU 闲着就觉得没调好。真正该看的是吞吐------每分钟多少行、多少 MB。调一次参数,对比一次吞吐,两三轮下来,最优配置自己就浮出来了。
要是带宽打满、两边磁盘都还有余量?恭喜,说明参数到位了,瓶颈在网络。要么加带宽,要么接受现状,这已经不是调参能解决的事了。
最后
把这套东西压缩成四句话:
线程按公式算,核心数乘十起步;JVM 堆给够,Xms 和 Xmx 设成一样;金仓端放开 shared_buffers,字符集日期格式提前对齐;任务里的大表拆分一定要开,连接数跟线程配套着设。
默认参数是给小库的温柔,大数据量面前,该出手就出手。调优这事没有玄学,公式加实测,一轮一轮逼近最优。祝各位迁移顺利,进度条跑出下载软件的感觉。