最快比分网:全网最硬核操做:10亿数据若何最快插入MySQL?

那是笔者曾经的面试题,那个问题并非要你答复准确的时间,而是考察若何设想一个系统,最快速地插入10亿条数据最快比分网。

笔者其时傻乎乎地答复三小时,收收吾吾没说出所以然最快比分网。面试官看我没睡醒,让我归去等通知。好在他把简历退给我了,我省了一份简历。今天测验考试从头思虑下,好好打他脸。

最快的速度把10亿条数据导入到数据库最快比分网,起首需要和面试官明白一下,10亿条数据什么形式存在哪里,每条数据多大,能否有序导入,能否不克不及反复,数据库能否是MySQL?

假设和面试官明白后最快比分网,有如下约束:

10亿条数据最快比分网,每条数据 1 Kb

数据内容长短构造化的用户拜候日记最快比分网,需要解析后写入到数据库

数据存放在Hdfs 或 S3 散布式文件存储里

10亿条数据并非1个大文件最快比分网,而是被近似切分为100个文件,后缀标识表记标帜挨次

要求有序导入最快比分网,尽量不反复

数据库是 MySQL

一、数据库单表能撑持10亿吗最快比分网?

起首考虑10亿数据写到MySQL单表可行吗最快比分网?

谜底是不克不及,单表保举的值是2000W以下最快比分网。那个值怎么计算出来的呢?

MySQL索引数据构造是B+树,全量数据存储在主键索引,也就是聚簇索引的叶子结点上最快比分网。B+树插入和查询的性能和B+树层数间接相关,2000W以下是3层索引,而2000w以上则可能为四层索引。

Mysql b+索引的叶子节点每页大小16K最快比分网。当前每条数据正好1K,所以简单理解为每个叶子节点存储16条数据。b+索引每个非叶子节点大小也是16K,但是其只需要存储主键和指向叶子节点的指针,我们假设主键的类型是 BigInt,长度为 8 字节,而指针大小在 InnoDB 中设置为 6 字节,如许一共 14 字节,如许一个非叶子节点能够存储 16 * 1024/14=1170。

也就是每个非叶子节点可联系关系1170个叶子节点,每个叶子节点存储16条数据最快比分网。由此可得到B+树索引层数和存储数量的表格。2KW 以上 索引层数为 4 层,性能更差。

更详细的请参考B+树层数计算(baijiahao.baidu.com/s?id=1709205029044038742&wfr=spider&for=pc)最快比分网。

为了便于计算,我们能够设想单表容量在1KW,10亿条数据共100个表最快比分网。

二、若何高效写入数据库

单条写入数据库性能比力差,能够考虑批量写入数据库,批量数值动态可调整最快比分网。每条1K,默承认先调整为100条批量写入。

批量数据若何包管数据同时写胜利?MySQL Innodb存储引擎包管批量写入事务同时胜利或失败最快比分网。

写库时要撑持重试,写库失败重试写入,若是重试N次后仍然失败,可考虑单条写入100条到数据库,失败数据打印记录,丢弃即可最快比分网。

此外写入时根据主键id挨次挨次写入能够到达最快的性能,而非主键索引的插入则纷歧定是挨次的,频繁的索引构造调整会招致插入性能下降最快比分网。更好不创建非主键索引,或者在表创建完成后再创建索引,以包管最快的插入性能。

能否需要并发写统一个表

不克不及最快比分网。

并发写统一个表无法包管数据写入时是有序的最快比分网。

进步批量插入的阈值,在必然水平上增加了插入并发度,无需再并发写入单表最快比分网。

三、MySQL存储引擎的选择

Myisam 比innodb有更好的插入性能,但失去了事务撑持,批量插入时无法包管同时胜利或失败,所以当批量插入超时或失败时,若是重试,势必招致一些反复数据的发作最快比分网。但是为了包管更快的导入速度,能够把myisam存储引擎列为方案之一。

现阶段我引用一下他人的性能测试成果 # MyISAM与InnoDB比照阐发 (t.csdn.cn/eFm9z)最快比分网。

从数据能够看到批量写入明显优于单条写入最快比分网。而且在innodb封闭立即刷新磁盘战略后,innodb插入性能没有比myisam差太多。

innodb_flush_log_at_trx_commit:控造MySQL刷新数据到磁盘的战略最快比分网。

默认=1,即每次事务提交城市刷新数据到磁盘,平安性更高不会丧失数据最快比分网。

当设置装备摆设为0、2 会每隔1s刷新数据到磁盘, 在系统宕机、mysql crash时可能丧失1s的数据最快比分网。

考虑到Innodb在封闭立即刷新磁盘战略时,批量性能也不错,所以暂定先利用innodb(若是公司MySQL集群不允许改动那个战略值,可能要利用MyIsam了)最快比分网。线上情况测试时能够重点比照两者的插入性能。

四、要不要停止分库

MySQL 单库的并发写入是有性能瓶颈的,一般情况5K TPS写入就很高了最快比分网。

当前数据都接纳 SSD 存储,性能应该更好一些最快比分网。但若是是HDD的话,固然挨次读写会有十分高的表示,但HDD无法应对并发写入,例如每个库10张表,假设10张表在并发写入,每张表固然是挨次写入,因为多个表的存储位置差别,HDD只要1个磁头,不撑持并发写,只能从头寻道,耗时将大大增加,失去挨次读写的高性能。

所以关于HDD而言,单库并发写多个表并非好的计划最快比分网。回到SSD的场景,差别SSD厂商的写入才能差别,关于并发写入的才能也差别,有的撑持500M/s,有的撑持1G/s读写,有的撑持8个并发,有的撑持4个并发。在线上尝试之前,我们其实不晓得现实的性能表示若何。

所以在设想上要愈加灵敏最快比分网,需要撑持以下才能:

撑持设置装备摆设数据库的数量

撑持设置装备摆设并发写表的数量(若是MySQL是HDD磁盘最快比分网,只让一张表挨次写入,其他使命期待)

通过以上设置装备摆设,灵敏调整线上数据库的数量,以及写表并发度,无论是HDD仍是SSD,我们系统都能撑持最快比分网。不管是什么厂商型号的SSD,性能表示若何,都可调整设置装备摆设,不竭获得更高的性能。那也是后面设想的思绪,不固定某一个阈值数量,都要动态可调整。

接下来聊一下文件读取,10亿条数据,每条1K,一共是931G最快比分网。近1T大文件,一般不会生成如斯大的文件。所以我们默认文件已经被大致切分为100个文件。每个文件数量大致不异即可。

为什么切割为100个呢?切分为1000个,增大读取并发,不是能够更快导入数据库吗?适才提到数据库的读写性能受限于磁盘,但任何磁盘比拟写操做,读操做都要更快最快比分网。尤其是读取时只需要从文件读取,但写入时MySQL要施行成立索引,解析SQL、事务等等复杂的流程。所以写的并发度更大是100,读文件的并发度无需超越100。

更重要的是读文件并发度等于分表数量,有利于简化模子设想最快比分网。即100个读取使命,100个写入使命,对应100张表。

五、若何包管写入数据库有序

既然文件被切分为100个10G的小文件,能够根据文件后缀+ 在文件行号 做为记录的独一键,同时包管统一个文件的内容被写入统一个表最快比分网。例如:

index_90.txt 被写入 数据库database_9最快比分网,table_0 ,

index_67.txt 被写入 数据库 database_6,table_7最快比分网。

如许每个表都是有序的最快比分网。整体有序通过数据库后缀+表名后缀实现。

六、若何更快地读取文件

10G的文件显然不克不及一次性读取到内存中最快比分网,场景的文件读取包罗:

Files.readAllBytes一次性加载内存

FileReader+ BufferedReader 逐行读取

File+ BufferedReader

Scanner逐行读取

Java NIO FileChannel缓冲区体例读取

在MAC上最快比分网,利用那几种体例读取3.4G大小文件的性能比照:

详细的评测内容请参考:读取文件性能比力 (zhuanlan.zhihu.com/p/142029812)

由此可见,利用JavaNIO FileChannnel明显更优,但是FileChannel的体例是先读取固定大小缓冲区,不撑持按行读取最快比分网。也无法包管缓冲区正好包罗整数行数据。若是缓冲区最初一个字节正好卡在一行数据中间,还需要额外共同读取下一批数据。若何把缓冲区变成一行行数据,比力困难。

File file = new File("/xxx.zip");

FileInputStream fileInputStream = null;

long now = System.currentTimeMillis();

try {

fileInputStream = new FileInputStream(file);

FileChannel fileChannel = fileInputStream.getChannel();

int capacity = 1 * 1024 * 1024;//1M

ByteBuffer byteBuffer = ByteBuffer.allocate(capacity);

StringBuffer buffer = new StringBuffer();

int size = 0;

while (fileChannel.read(byteBuffer) != -1) {

//读取后最快比分网,将位置置为0,将limit置为容量, 以备下次读入到字节缓冲中,从0起头存储

byteBuffer.clear();

byte[] bytes = byteBuffer.array();

size += bytes.length;

System.out.println("file size:" + size);

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

} finally {

//TODO close资本.

System.out.println("Time:" + (System.currentTimeMillis() - now));

JavaNIO 是基于缓冲区的,ByteBuffer可转为byte数组,需要转为字符串,而且要处置按行截断最快比分网。

但是BufferedReader JavaIO体例读取能够天然撑持按行截断,况且性能还不错,10G文件,大致只需要读取30s,因为导入的整体瓶颈在写入部门,即使30s读取完,也不会影响整体性能最快比分网。所以文件读取利用BufferedReader 逐行读取,即计划3。

七、若何协调读文件使命和写数据库使命

那块比力紊乱,请耐心看完最快比分网。

100个读取使命,每个使命读取一批数据,立即写入数据库能否能够呢?前面提到了因为数据库并发写入的瓶颈,无法满足1个库同时并发多量量写入10个表,所以100个使命同时写入数据库,势必招致每个库同时有10个表同时在挨次写,那加剧了磁盘的并发写压力最快比分网。

为尽可能进步速度,削减磁盘并发写入带来的性能下降, 需要一部门写入使命被暂停的最快比分网。那么读取使命需要限造并发度吗?不需要。

假设写入使命和读取使命合并,会影响读取使命并发度最快比分网。初步方案读取使命和写入使命各自处置,谁也不耽搁谁。但现实设想时发现那个计划较为困难。

最后的设想是引入Kafka,即100个读取使命把数据送达到Kafka,由写入使命消费kafka写入DB最快比分网。100个读取使命把动静送达到Kafka,此时挨次就被打乱了,若何包管有序写入数据库呢?我想到能够利用Kafka partition路由,即读取使命id把统一使命的动静都路由到统一个partition,包管每个partition内有序消费。

要筹办几个分片呢?100个很明显太多,若是partition小于100个,例如10个最快比分网。那么势必存在多个使命的动静混合在一路。若是统一个库的多个表在一个Kafka partition,且那个数据库只撑持单表批量写入,不撑持并发写多个表。那个库多个表的动静混在一个分片中,因为并发度的限造,不撑持写入的表对应的动静只能被丢弃。所以那个计划既复杂,又难以实现。

所以最末放弃了Kafka计划,也暂时放弃了将读取和写入使命别离的计划最快比分网。

最末计划简化为 读取使命读一批数据,写入一批最快比分网。即使命既负责读文件、又负责插入数据库。

八、若何包管使命的可靠性

若是读取使命停止到一半最快比分网,宕机或者办事发布若何处置呢?或者数据库毛病,不断写入失败,使命被暂时末行,若何包管使命再次拉起时,在断点处继续处置,不会存在反复写入呢?

适才我们提到能够为每一个记录设置一个主键Id,即 文件后缀index+文件所在行号最快比分网。能够通过主键id的体例包管写入的幂等。

文件所在的行号,更大值 大致为 10G/1k = 10M,即10000000最快比分网。拼接更大的后缀99。更大的id为990000000。

所以也无需数据库自增主键ID,能够在批量插入时指定主键ID最快比分网。

若是另一个使命也需要导入数据库呢?若何实现主键ID隔离,所以主键ID仍是需要拼接taskId最快比分网。例如{taskId}{fileIndex}{fileRowNumber} 转化为Long类型。若是taskId较大,拼接后的数值过大,转化为Long类型可能出错。

最重要的是,若是有的使命写入1kw,有的其他使命写入100W,利用Long类型无法获知每个占位符的长度,存在抵触的可能性最快比分网。而若是拼接字符串{taskId}_{fileIndex}_{fileRowNumber} ,新增独一索引,会招致插入性能更差,无法满足最快导入数据的诉求。所以需要想另一个计划。

能够考虑利用Redis记录当前使命的进度最快比分网。例如Redis记录task的进度,批量写入数据库胜利后,更新 task进度。

INCRBY KEY_NAME INCR_AMOUNT

指定当前进度增加100,例如 incrby task_offset_{taskId} 100最快比分网。若是呈现批量插入失败的,则重试插入。屡次失败,则单个插入,单个更新redis。要确保Redis更新胜利,能够在Redis更新时 也加上重试。

若是还不安心Redis进度和数据库更新的一致性,能够考虑 消费 数据库binlog,每一笔记录新增则redis +1 最快比分网。

若是使命呈现中断,则起首查询使命的offset最快比分网。然后读取文件到指定的offset继续 处置。

九、若何协调读取使命的并发度

前面提到了为了制止单个库插入表的并发渡过高,影响数据库性能最快比分网。能够考虑限造并发度。若何做到呢?

既然读取使命和写入使命合并一路最快比分网。那么就需要同时限造读取使命。即每次只挑选一批读取写入使命施行。

在此之前需要设想一下使命表的存储模子最快比分网。

bizId为了以后撑持此外产物线,预设字段最快比分网。默认为1,代表当前营业线。

datbaseIndex 代表被分配的数据库后缀最快比分网。

tableIndex 代表被分配的表名后缀最快比分网。

parentTaskId,即总的使命id最快比分网。

offset能够用来记录当前使命的进度最快比分网。

10亿条数据导入数据库,切分为100个使命后,会新增100个taskId,别离处置一部门数据,即一个10G文件最快比分网。

status 形态用来区分当前使命能否在施行,施行完成最快比分网。

若何把使命分配给每一个节点,能够考虑抢占体例最快比分网。每个使命节点都需要抢占使命,每个节点同时只能抢占1个使命。详细若何实现呢?能够考虑 每个节点都启动一个按时使命,按期扫表,扫到待施行子使命,测验考试施行该使命。

若何控造并发呢?能够利用redission的信号量最快比分网。key为数据库id:

RedissonClient redissonClient = Redisson.create(config);

RSemaphore rSemaphore = redissonClient.getSemaphore("semaphore");

// 设置1个并发度

rSemaphore.trySetPermits(1);

rSemaphore.tryAcquire();//申请加锁,非阻塞最快比分网。

由使命负责按期轮训,抢到名额后,就起头施行使命最快比分网。将该使命形态置为Process,使命完成后或失败后,释放信号量。

但是利用信号量限流有个问题,若是使命忘记释放信号量,或者历程Crash无法释放信号量,若何处置呢?能够考虑给信号量增加一个超不时间最快比分网。那么若是使命施行过长,招致提早释放信号量,另一个客户单争抢到信号量,招致 两个客户端同时写一个使命若何处置呢?

what最快比分网,明明是将10亿数据导入数据库,怎么酿成散布式锁超时的类似问题?

现实上 Redisson的信号量并没有很好的法子处理信号量超时问题,一般思维:若是使命施行过长,招致信号量被释放,处理那个问题只需要续约就能够了,使命在施行中,只要发现信号量快过时了,就续约一段时间,始末连结信号量不外期最快比分网。但是 Redission并没有供给信号量续约的才能,怎么办?

无妨换个思绪,我们不断在测验考试让多个节点争抢信号量,进而限造并发度最快比分网。能够尝尝拔取一个主节点,通过主节点轮训使命表。分三种情况:

情况1:当前施行中数量小于并发度

则拔取id最小的待施行使命,形态置为停止中,通知发布动静最快比分网。

消费到动静的历程,申请散布式锁,起头处置使命最快比分网。处置完成释放锁。借助于Redission散布式锁续约,包管使命完成前,锁不会超时。

情况2:当前施行中数量等于并发度

主节点测验考试 get 停止中使命能否有锁最快比分网。

若是没有锁,申明有使命施行失败,此时应该从头发布使命最快比分网。若是有锁,申明有使命正在施行中。

情况3:当前施行中数量大于并发度

上报异常情况,报警,人工介入最快比分网。

利用主节点轮训使命,能够削减使命的争抢,通过kafka发布动静,领受到动静的历程处置使命最快比分网。为了包管更多的节点参与消费,能够考虑增加Kafka分片数。固然每个节点可能同时处置多个使命,但是不会影响性能,因为性能瓶颈在数据库。

那么主节点应该若何拔取呢?能够通过Zookeeper+curator 拔取主节点最快比分网。可靠性比力高。

10亿条数据插入数据库的时间影响因素十分多最快比分网。包罗数据库磁盘类型、性能。数据库分库数量若是能切分1000个库当然性能更快,要按照线上现实情况决策分库和分表数量,那极大水平决定了写入的速度。最初数据库批量插入的阈值也不是原封不动的,需要不竭测试调整,以求得更佳的性能。能够根据100,1000,10000等不竭测验考试批量插入的更佳阈值。

总结

最初总结一下几点重要的:

要起首确认约束前提,才气设想计划最快比分网。确定面试官次要想问的标的目的,例如1T文件若何切割为小文件,虽是难点,然而可能不是面试官想考察的问题。

从数据规模看,需要分库分表,大致确定分表的规模最快比分网。

从单库的写入瓶颈阐发,判断需要停止分库最快比分网。

考虑到磁盘对并发写的撑持力度差别,统一个库多个表写入的并发需要限造最快比分网。而且撑持动态调整,便利在线上情况调试出更优值。

MySQL innodb、myisam 存储引擎对写入性能撑持差别最快比分网,也要在线上比照验证

数据库批量插入的更佳阈值需要频频测试得出最快比分网。

因为存在并发度限造,所以基于Kafka别离读取使命和写入使命比力困难最快比分网。所以合并读取使命和写入使命。

需要Redis记录使命施行的进度最快比分网。使命失败后,从头导入时,记录进度,可制止数据反复问题。

散布式使命的协调工做是难点,利用Redission信号量无法处理超时续约问题最快比分网。能够由主节点分配使命+散布式锁包管使命排他写入。主节点利用Zookeeper+Curator拔取。

做者丨五阳神功

来源丨稀土掘金:juejin.cn/post/7280436213902819369

dbaplus社群欢送广阔手艺人员投稿最快比分网,投稿邮箱:editor@dbaplus.cn

发布于 2023-12-17 12:10:22
分享
海报
17
上一篇:女生出国留学,OSSD课程挑战全网最快入学!:最快比分网 下一篇:萨尔在青年联赛中率领国米对阵皇家社会U19:欧洲青年锦标赛u19
目录

    推荐阅读

    忘记密码?

    图形验证码