主题
近几个阶段对调度部分的问题也算收集的比较多,随着主数据、资产、指标等功能的深入,同步性能、实际场景的特殊性等问题,以及flink、chunjun等数据cdc即时捕获能力,算是有了一个初步的认知,一些具体的问题具体做一个分享。
离线与即时
离线
常规的数据同步,指定周期进行增量或者全量同步,如果数据情况无增量字段(时间、ID增量),数据情况比较不理想,数据管理者又非自身,此种场景下常常需要全表扫描,降低扫描周期来进行妥协,通常通过外部调度进行同步,增量这种形式存在漏洞,即历史数据变更至少需要数据实体满足两个新增和修改时间作为要求,同时针对数据的移除也可能会要求逻辑删除,才可能堵住增量带来的问题。
通常对针对一些数据变更比较少的数据,如果变更比较频繁的数据,常常就是全量同步,但数据量增大以及应用数据比较频繁时,不可能进行移除再新增这种破坏性极大,比如:基础数据之上存在很多的调度,很容易造成一些不可控因素出现,信息类&统计类的因为频率或者周期的因素造成数据异常。此种需对同步策略进行数据优化,中间需要存在数据对比策略,保证数据结果的稳定,通常用MD5或者补充字段将数据进行切片局部同步。
CDC
CDC(Change Data Capture)变化数据捕获概念,当你能够识别并获得最近发生变化的数据时,抽取及其后面的转换、装载操作显然都会变得更高效,因为这样需要处理的数据量就会少很多
数据库日志
这个是当前flink等现代ETL工具比较典型的处理办法,针对所有的数据表都为一方所有,如互联网公司,都数据都为自己所有,可配合调整,数据的同步量级,搬运摆渡数量巨大。
触发器
针对一些特定表做监控,数量有限,处理比较量比较小,不需要额外的开销,在数据库中即可实现相关数据的补全改造处理
数据库代理
需对应用配置提出要求,批量改造或者替换原本的服务端口,在代理侧集中处理,针对其执行语句做监听分析
埋点
在应用侧进行消息通知埋点,小型的单体或复合项目,在既有的标准约束下进行,但现有的场景下多数是渐进式的,应用改造往往造成业务的波动、成本、甚至是无运维主体的情况。
抓包
和代理有点儿类似,但有所区别,和服务器探针/服务器监听类似,Prometheus、Uptime Kuma差不多,类似一个小型的端监听,可以是本机的mysql服务监听,可以进行局部的应用服务监听,此项场景是参考主数据库在集团,子公司无控服务器权限,仅有访问权限的场景,在应用局部可进行类似埋点的操作(自有的局部数据即可)
实践情况整理
过程及问题
1.python搞定后,网络服务监听没问题,即通过navicat操作服务器上的数据库,能有效捕获到数据库的执行语句
from scapy.all import sniff, TCP, Raw, IP,show_interfaces
import logging
import concurrent.futures
# 配置日志
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
# 指定的 IP 和端口
TARGET_IP = '127.0.0.1'
MYSQL_PORT = 3306
# 解析 MySQL 命令
def parse_mysql_packet(packet):
if packet.haslayer(TCP) and packet[TCP].dport == MYSQL_PORT and packet.haslayer(Raw):
payload = packet[Raw].load
if len(payload) >= 5:
packet_length = int.from_bytes(payload[:3], byteorder='little')
packet_number = payload[3]
command = payload[4]
if command == 0x03: # Query command
query = payload[5:].decode('utf-8', errors='replace').strip()
if query.upper().startswith(('INSERT', 'UPDATE', 'DELETE')):
logging.debug(f"Query: {query}")
def packet_callback(packet):
# logging.debug(f"Received packet from {packet[IP].src}:{packet[TCP].sport} to {packet[IP].dst}:{packet[TCP].dport}")
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.submit(parse_mysql_packet, packet)
# if packet.haslayer(IP) and packet[IP].dst == TARGET_IP:
# parse_mysql_packet(packet)
if __name__ == "__main__":
show_interfaces()
logging.info(f"Starting to capture packets for IP: {TARGET_IP} and port: {MYSQL_PORT}...")
try:
sniff(filter=f"tcp port {MYSQL_PORT}", prn=packet_callback, store=0)
# sniff(filter=f"tcp and dst port {MYSQL_PORT}", prn=packet_callback, store=0)
except Exception as e:
logging.error(f"An error occurred: {e}")
2.本机的数据库服务,通过程序进行操作,监听不到相关的活动
因为我是在windows下进行的,后发现winpcap貌似是没办法进行本机回环的检测,相当于规避了"localhost",因此安装了npcap,获取到了本机回环的网卡信息
npcap安装
增加回环
通过scapy show_interfaces找出来回环的网卡信息,配置好
sniff(iface="Software Loopback Interface 1",filter=f"tcp port {MYSQL_PORT}", prn=packet_callback, store=0)
成功的监听到本机的语句执行,这里做了一些简单规则,将相关的变更通知到指定的消息队列,即可作为一个小型的采集终端,linux上略有区别,针对数据库的监听需要调整一下iface='lo',此项还没做验证
结语
以上只是针对数据库变更问题在一些场景受限情况下的思路,成本和实施的思路比较小,不必集成厚重的一些处理,针对其他库,可能需要根据其传输做一些指定解析,算是对双端没啥大的要求,而且成本相对比较低的一个方案。