项目纪实--如何搭建一个高可用强一致性灵活元数据管理的数据平台实现高效可靠的数据分发等功能

本文详细记录了一个大型数据平台的构建过程,重点探讨了如何通过需求分析、后台框架设计以及分发策略的选择,实现一个高效可靠的数据分发系统。文章讨论了Kafka Topic、Redis Pub/Sub等方案的优缺点,并最终选择了自定义的Redis解决方案,以确保数据的高一致性与灵活性。此外,文章还强调了元数据管理的重要性,以及在实现过程中面临的挑战和解决策略。
摘要由CSDN通过智能技术生成

项目纪实–大型数据平台系统构建

背景:18年入职这家轻松的国企,在19年难得接(抢)到一个有意思的项目,开始定义还比较简单:写一个CMS用于近期某XX项目中发布数据,开始是找到别人被别婉拒后我主动给接了过来。本身没什么难点,且背景我在前期早已了解过一些,所以答应接过来。原来各项目/产品中总是需要用到些采集处理好的各类数据,这些数据存在于各数据库各表中(多来源多库多结构表),之前的解决方式是各个项目/产品需要数据就问我们要,如果DB里面已有我们就直接把数据位置(哪个库哪个表)和连接配置告诉他们让他们自己去拿,库里面没有的话就写生产流程让它有再给。这样做的坏处相信写过些项目的程序员应该都能知道,来个数据类需求就给一份数据库连接配置出去随他们怎么用。再加上还有个采集监控看板直接每天通过高频查库统计结果数据(很显然这里有两种可替代更优方案:1.从源数据生产过程日志统计.2.从入库管道统计)
更多技术老旧,历史遗留等各种原因积弊就不多说了,本文目的也不在此。总之,反应到具体使用体验上面是各种死锁和慢查询一堆,反应慢体验差…
显然这个任务如果还是如之前各项目那般掏数据库也能解决需求,但前面提到的原来各项目中出现的问题也都会出现。我可不愿重蹈覆辙。
那么是时候做出改变了,虽然还不明确后面将要实现的是什么(反正不是一开始说的CMS)以及如何实现,但面对各项目/产品中数据消费类需求场景,从根本上统一并彻底解决的方向及目标基本是想象出来了:一个系统解决所有数据类需求,高性能可扩展高灵活配置热更新易维护等。

*** 
(1) TRANSACTION:
TRANSACTION 268814508, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 1
MySQL thread id 2615055, OS thread handle 139826487912192, query id 170694941 127.0.0.1 xwcj update
insert into web_article (name,category,leadtitle,title,subtitle,abstract,author,editor,image_list,image_desc,content,htmlcontent,keywords,url,referer,publish_date,fetch_date) values ('XX网','图片',NULL,'“离婚冷静期”的前后两个30天,你注意到了吗?',NULL,'XX新闻是国内主流新闻网站中工网旗下综合新闻资讯门户,也是XX网核心主频道,每天24小时为广大网民滚动报道国内、国际及社会新闻。','XX新闻','高冲','2020-05/20200530/XX网/54ce9478f38b08d0ba5cc15682fe542169a435c5.jpg',NULL,'5月30日,《中华人民共和国民法典》颁布后的首个周六,北京市朝阳区民政局门前人头攒动,前来办理婚姻登记的人在办事大厅外排起了长队。据工作人员透露,5月30日当天有300多对前来办理婚姻登记的个人,“结婚的多,离婚的也不少,排在前面的几对全是办离
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 516 page no 691642 n bits 288 index FTS_DOC_ID_INDEX of table `xwcj`.`web_article` trx id 268814508 lock_mode X insert intention waiting
*** (2) TRANSACTION:
TRANSACTION 268814497, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
6 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 1
MySQL thread id 2615252, OS thread handle 139826764535552, query id 170694920 127.0.0.1 xwcj update
insert into web_article (name,category,leadtitle,title,subtitle,abstract,author,editor,image_list,image_desc,content,htmlcontent,keywords,url,referer,publish_date,fetch_date) values ('xx网','国内新闻',NULL,'中国颁发第二届全国创新争先奖  10团队和286个人获奖',NULL,'全国创新争先奖由中国科协、人力资源和社会保障部、科技部、国务院国资委于2017年共同设立,评选颁奖周期为3年。今年的第二届评奖还特别设立“疫情防控”和“脱贫攻坚”专题,表彰为疫情防控和脱贫攻坚作出重要贡献的科技工作者。','cnews','翟璐','2020-05/20200530/xx网/a58e814ba0a3cc019a41967cffed140b408d27a3.jpg,2020-05/20200530/xx网/3457e1bfaa7d68e493c78d74aede2e721c7d797b.jpg,2020-05/20200530/xx网/a46598144454a84002577a28a76f1a00b938481a.jpg','5月30日,第二届全国创新争先奖表彰奖励大会在北京
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 516 page no 691642 n bits 288 index FTS_DOC_ID_INDEX of table `xwcj`.`web_article` trx id 268814497 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 516 page no 691642 n bits 288 index FTS_DOC_ID_INDEX of table `xwcj`.`web_article` trx id 268814497 lock_mode X insert intention waiting
*** WE ROLL BACK TRANSACTION (1)
-- *一些慢查询的情况*    

因为在接手前已经了解过足够多细节和问题,所以能猜出它大致想要做出个什么东西(内容管理/数据分发系统/平台)及主要目的(更高效可靠的分发最好能兼容多差异项目且灵活配置热更新且解救数据库于水深火热)最差能接受的结果(简单加个redis缓存层也比原来掏数据库强多了),最理想能达成的实现效果以及我在哪些方面能做得更出彩些以实现项目最终实际效能的可能更大突破。显然如果仅仅是写一个CMS满足此XX项目需求也是可以完成任务,但后面如果又来了一个B项目C项目有其它的数据类需求呢?而且遇到项目中的需求变更呢?虽相比于直接掏数据库,CMS对项目需求可能解决的稍高效方便些,但依然是每来一个项目需求就又要重新改代码改配置部署测试等重复一遍,与之前直接写SQL掏数据库的开发流程并没有提高太多,只是项目内的优化而不是全局性质的优化并没有持久的长远提高整体效率。那么如果是一个高效可靠具有成熟的分发平台呢?这个理想中的数据平台后面可以统一支撑解决所有项目/产品中这些数据类的需求? 所有项目/产品都作为平台租户将租户注册频道订阅退订等生命周期管理及数据消费及统计等核心功能统一托管在平台之上呢?
以上为背景交代,后面开始讲开发过程及其中一些思路

开发环节

需求分析

数据如何消费即客户端拿到数据后的处理转换使用等过程这里并不会提及。只讲作为平台提供服务涉及相关。首先,我们的基础数据大致有4~5个大类,个大类下面又有少则几百多则几千级别的小类。而各个项目/产品对这些各类数据的需求是差异非常大的,有的项目(客户)对各大类里面个小类都有数据需求,还有的项目只需要某一大类里面部分小类…总之千人千面定制化很多还时常有使用过程中的后续变更,具体就不一一举例了。
对于上面这种场景,很容易就能抽象出一种用户(租户)对频道的多对多订阅消费关系。每个有数据需求的项目/产品都可以对应为一个租户,对应的小类则可称为频道。同属一个大类的频道则可称为在同一频道组内,对应的频道组也可用于批量订阅。类似的场景可联想到很多,比如通信里面的单播(点对点),组播,广播;ROS里面的Publisher/Subscriber(依赖的是MQ)…所以具体实现我们也有很多现成的工具可供选择,比如:redis里面的pubsub,kafka里面的Topic,各种MQ(rabbitMq,zeroMq…)里面的topic/pub-sub…为了方便和直观,后面所有对应的对象和关系都只用频道/用户/订阅来替代说明。

原来的对接方式,有数据需求的用户那边直接写SQL取数据,对于某些高产频道每天数据生产增量更新的频率比较高数据量也比较多,统计排查慢查询时有一种情况是这样:对应订阅很多这种高产频道的用户每天多频次用SQL取对应频道全量数据越取越多越来越慢…(为什么不是通过表内id增量SQL取,因为频道数据不仅是插入新数据还有很多已有数据的更新)。用户那边也不是写完SQL测过就完事了,后面用需求还可能会变更(往往订阅更多的频道或者更新),而我们的频道也会变的,有些频道因为数据来源的原因相当于没数据(失效删除),还有的是更名,还有迁移到其它频道组的可能,总之频道数据提供方和用户消费端都会有各种变化。而原来的开发方式决定了:1.显式的工作量,无论是提供方数据结构有变化还是用户消费端需求变化往往就面临两端都要进行一系列变更测试维护等,如果是提供方的变化还会导致变化涉及到的所有用户消费端的更改。2.即便当时测试通过,还有变更埋下的可能潜在隐患,另外还有一些冷门项目后期无人/少人维护,提供数据变更后可能都没人注意到…
各用户对数据需求的记录及管理(变更),取数据的方式以及过程中一致性效率可靠性的问题,本来就不应该是用户端的问题,这些由服务端就可以处理好,也本来就该是由服务端处理的。意识到这些后,需求基本就确定了:要用什么样的API提供哪些服务,这些服务分别需要做到什么程度(哪些是最主要的要高可用,哪些非关键),关键api(核心功能)中要处理好其中涉及的哪些问题(一致性,高效率),后台需要记录和维护哪些数据,后台可能扩展哪些功能接口以提升平台效能。
关于最终实现效果,不妨先有这么些比较理想化的想象(后期基本都实现了):
1.用户总是以增量的方式取到最新的数据。
2.用户取数据的方式简单可靠,对于最大流量最高频使用接口最高效的理想情况是登录后仅通过Get方法请求固定接口不用带任何其它参数即请求得到所需要的数据。(所有频道数据更新和所有用户消费数据等事务的状态全部由服务端记录维护。其中经常用到信号这一机制来解耦实现:即频道更新和用户事务(消费)异常都是利用信号通知)
3.多用户取多频道中大量数据是高效且可靠的(服务要高可用高并发,同时要可应对用户取数据过程中网络中断客户端处理异常服务端发送异常等导致的一致性等问题…)。
4.用户每次需求变更不需要在客户端做任何代码修改及变更维护等(所有用户对数据频道的订阅关系由服务端统一管理,并实时更新影响到到分发接口业务逻辑中)。
5.用户在客户端的消费数据频率及其他设置(几种输出格式及储存层可配置选择)是由客户端自己决定,所以各用户之间消费逻辑完全隔离互不可见,服务端各频道数据更新频率及可能的各频道之间的具体差异化由服务端信号控制,单独解耦出信号接口,更灵活自由。
6.频道内数据来源由持久存储数据库主动同步至高效内存数据库(redis),每次同步(更新)数据的同时给对应信号接口发一个信号。信号内容及控制粒度暂定频道级别(通知哪些频道有更新)。
7.6中提到的信号驱动机制仅在生产端(前半部分流程),事实上在此数据模型中使用Event-Driven-Programming(基于事件信号signal)来实现全流程的主动推送也是可以的。后面会讲到项目的实际实现是在频道数据同步更新(持久数据库主动同步到Redis)这一步用了Event-Driven-Programming的信号来触发频道激活。那么由频道激活触发主动推送至用户端显然也是顺理成章不难实现。具体为什么没有EDP一直到底实现实时主动推送后面会讲,这里只是提供一种思路讨论,也从一个方向说明数据模型的灵活兼容有效性。
8.以上提到所有功能细节对客户端无成本,客户端从此不需要写SQL仅需用账号无脑调API就就获得比以前更优质(永无慢查询)的服务。

从零到一,后台框架雏形

前面说过,几乎所有业务直接击中mysql它会扛不住导致的问题太多,所以用个缓存Redis业务层不直接从mysql表里面取数据分发是很自然的选择。虽然初始数据还是在Mysql里面,后来也进行了热点/非热点分表(近3天,历史,当时也初略统计下,近3天的新数据不到10G)。这样一来高频率大流量的最主要的业务读逻辑就全分到Redis中了。那么还有用户和频道信息以及他们之间的多对多订阅关系之类的这些元数据,这类数据的特征是:体量小(主要就几张表,频道表,用户表,外键关系表等,最大也就频道表几千条记录)读多写少更新也少但安全性反而要求更高的的非热点数据,就目前体

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值