当前位置: 首页 > 科技观察

为什么每个程序员都必须坚持写博客?本文教你怎么写

时间:2023-03-13 05:29:48 科技观察

1.回顾上一篇:《??为什么有些看起来很厉害的技术高手,设计的架构都很垃圾???》主要讲了将单体系统重构为分布式系统,避免单机负载过大。同时扩展了弹性资源调度、分布式容错机制等相关东西。在本文中,我们将继续聊聊这个系统后续的重构和演进过程。首先,让我们看一下目前的系统架构图,一起回顾一下。2.百亿级流量的高并发技术挑战上一篇文章说了,如果只是每天几十亿级的流量,其实现在的系统架构已经足够支撑了,但是我们面临的不是仅数十亿流量。简单的。我们面临的是越来越复杂的业务系统,越来越多的系统用户,以及每天百亿级的高并发流量。我给大家讲讲当时的系统部署。数据库部署了8台master和8台slave,即16台数据库服务器。每个数据库都部署在独立的数据库服务器上,全部使用物理机,机器的配置,我没记错的话应该是32核+128G+SSD固态硬盘。为什么物理机那么多,而且个个都是高配置?不知道大家有没有发现,到目前为止,我们最大的依赖就是MySQL!之前给大家解释过,当时的后台,我们要实时的跑几百条,复杂度在几百到几千行的大SQL,面对上亿行的海量数据的涌入,分析需要几秒钟。结果。任何开源系统都做不到这一点,Storm也做不到,SparkStreaming也做不到,所以必须是基于MySQL的纯自研数据平台架构来支持这种需求场景。因此,只有MySQL能够支持如此复杂的SQL语句的完美运行,所以我们前期必须严重依赖MySQL作为数据的存储和计算,将源源不断涌入的数据存储在MySQL中,然后基于数据分析的架构切片计算用于高性能运行复杂的大型SQL,基于MySQL进行计算。所以大家知道到目前为止MySQL是这个系统的命脉。当时的场景,每台数据库服务器每秒要承受2000个左右的并发请求。高峰期的CPU负载和IO负载其实是非常高的,而且高峰期主库和从库之间的延迟已经有点严重了。它将达到第二个级别。在我们的生产系统实际在线运行中,单台MySQL数据库服务器,我们一般不会允许它的峰值并发请求超过2000/s,因为一旦达到每秒上千请求,根据当前线上的资源来看服务器的负载,如果负载过高,MySQL服务器很可能会崩溃。那么这个时候,就出现了一个很尴尬的问题。这么多高配置的数据库服务器,要用8主8从来抵挡每天几十亿的流量,万一是亿流量怎么办?哪怕是百亿流量?您是否不断添加更多高配置机器?要知道,这种高配置的数据库服务器,如果是物理机的话,是非常昂贵的!之前给大家简单介绍了一下项目背景。整个这个大型系统组成的商业级平台,涉及的系统不止N个。该数据产品只是一个子产品。不可能为这样的产品投入大量的预算。使用高配置的机器来支持更高的并发写入。必须用技术手段重构系统架构,尽量利用有限的机器资源,用最好的架构来抵御超高并发写入的压力!3、这种架构的致命问题之一就是数据的存储和计算混杂在一个地方,都在同一个MySQL库中!大家想一想,把几千万的数据放到一张表里,然后每次跑一个复杂的SQL,SQL通过索引在表中定位到他要计算的数据段。这合适吗?答案显然是否定的!因为表的数据量很大,而你在每次实际的SQL操作中只需要计算一小部分数据。事实上,我们在生产环境中实践后发现,如果运行一条复杂的SQL,即使通过各种索引定位到的数据量很小,也会因为表的数据量太大而导致性能直线下降。所以首先要把数据存储和计算这两个东西分开。我们当时的想法是这样的:直接把数据写到一个storage里面,简单写就行了,然后在计算的时候从datastorage中提取你需要的数据。数据分片里面可能有一两千条数据,写到另一个专门用来计算的临时表里,那个临时表里面只有一两千条数据,然后你就可以运行你的各种复杂的SQL了。答对了!数据存储和计算这两个东西一旦分开,架构上就有很大的发挥空间。首先,只要你的数据存储支持高并发写入,如果每天流量上百亿,峰值并发达到每秒几十万,你就可以支持这个。然后支持计算引擎通过简单的操作从数据存储中提取少量数据。太好了,这个数据存储可以通过MySQL,那么这个需求为什么要用MySQL呢?兄弟!当时经过充分的技术调研和选择,我们选择了公司自主研发的分布式KV存储系统。这种KV存储系统完全分布式、高可用、高性能、轻量级、支持海量数据。之前经历过公司在线流量百亿级请求的测试,绝对没有问题。主要支持高并发写入数据和简单的查询操作,完全满足我们的需求。这里给大家说一句,其实业界很多类似的场景都会选择hbase,所以如果没有公司自研优秀的kv存储,可以使用hbase。非常精通hbase,合理避坑和优化。轻量级分布式kv系统,总体设计理念是支持一些简单的kv操作,严重依赖内存缓存热数据来支持高并发写入和读取,因为不需要支持MySQL中的那些事务,复杂的SQL等重量级机制.因此,在同等机器资源条件下,kv存储对高并发的支持能力至少是MySQL的数倍甚至数十倍。举个例子,大家应该都用过Redis。Redis单机普通配置支持每秒几万并发是可以的。其实就是这个道理。很轻量,转成高并发。那么,我们仍然可以将基于一些临时表从kv存储中提取出来的数据碎片存储在MySQL中,利用MySQL对复杂SQL语法的支持来进行计算。也就是说,在这个架构中,我们使用kv系统作为存储,使用MySQL进行少量数据的计算。这个时候我们在系统架构中引入了一个分布式的kv系统作为我们的数据存储。每天把海量的数据存储在这里就够了,然后我们的Slave计算引擎每次计算根据数据分片从kv存储中提取相应的数据放到MySQL中的临时表中,然后运行各种复杂的临时表中一两千条数据分片的SQL计算。看上面的图片。这个时候我们通过这一步的计算存储分离架构,选择了适合支持高并发的kv集群来抵御每天百亿级流量的写入。然后基于MySQL放少量数据作为临时表进行操作。这一步可以直接抵抗高并发请求。而且分布式kv存储可以按需扩展。如果并发越来越高,扩容加机器就够了。至此,架构的一个关键重构步骤就完成了。4、自研纯内存SQL计算引擎下一步就是追求极致的架构!因为此时我们面临的一个痛点是,其实MySQL只是作为一个临时表进行计算,主要是利用其复杂的SQL语法支持。但是问题是MySQL的并发虽然大大降低了,但是也不算低。因为需要计算大量的数据分片,所以还是需要经常读写MySQL。另外,每次从kv存储中取出数据,都得放到MySQL的临时表中,SQL要发给MySQL计算,还是多了几个步骤。因为我们当时面临的另一个问题是,每天大量的请求意味着大量的数据,大量的数据意味着时间片计算任务的负载仍然很重。一直那么依赖MySQL,还要维护很多各种临时表,可能多达几百张临时表,需要维护,注意修改它的表结构,分库分库的一些操作-表维度操作,所有这些都让依赖MySQL变得如此多余和麻烦。因此,我们决定,为了让架构更易于维护,将性能优化到极致,我们需要自己开发一个纯内存的SQL计算引擎。事实上,如果要开发一个能够支持MySQL复杂SQL语法的内存SQL计算引擎,还是有点困难和麻烦的。但是我们仔细研究了业务需要的几百条SQL之后,发现问题其实并没有那么复杂。因为其实一般的数据分析SQL主要是一些常用的函数,并没有那么多奇怪的、难懂的、有偏见的SQL语法。因此,在分析了所有线上的SQL之后,我们有针对性的开发了只支持几种语法的SQL引擎,包括嵌套查询组件、多表关联组件、分组聚合组件、多字段排序组件、少数常用函数,等等。然后,系统完全重构,不再依赖MySQL。每次从kv存储中取出一个数据分片,直接放入内存,然后我们使用自研的SQL计算引擎,在纯内存中定位一个数据分片。切片执行各种复杂的SQL。这种纯内存操作的性能,不用多说,大家应该能想象到,基本上纯内存的SQL执行都是毫秒级的,基本上一个分片操作都降到毫秒级了。性能进一步大幅提升,从此不再依赖MySQL,无需维护复杂的分库分表等。该架构上线后,彻底消除了对MySQL的依赖。理论上无论来多少流量,立即扩容kv集群和slave计算集群都可以解决。张临时表等比较费力、麻烦和作弊的解决方案。而且这种纯内存计算架构直接将计算性能提升到了毫秒级。而消除对MySQL的依赖还有一个好处。数据库机总是需要高配置,而从机主要是4核8G的普通虚拟机。分布式系统的本质就是尽可能地使用大量廉价的普通机器。可以做到高效的存储和计算。所以在百亿流量的负载下,我们Slave机部署几十台机器就够了,比部署几十台昂贵的高配置MySQL物理机划算多了!5、MQ调峰和流量控制其实对高并发架构稍有了解的同学会发现,在这个系统的架构中,为了高并发的编写,还有一个关键的组件需要加入,那就是MQ。因为如果我们处理的是高并发的非实时响应的写请求,我们可以先用MQ中间件来抵抗海量请求,然后再搭建一个中间分流系统,将流量异步转发到kv存储。同时,这种流量分发系统可以控制高并发流量。比如瞬时高并发写入真的造成后台系统压力过大,那么流量分配系统可以根据我们设置的阈值自动控制流量,防止高并发压力压垮后台系统。而且,在这个流控系统中,我们其实做了很多细节上的优化,比如数据校验,过滤无效数据,拆分数据分片,数据同步的幂等机制,100%保证数据落地在kv中的机制保证集群,等等。公司的MQ集群天然支持大流量写入和高并发请求,所以在MQ集群层面抗高并发不是问题。不管多高的并发,都可以按需扩展,然后我们自己的流控系统也是集群部署的,线上用的是4核8G的虚拟机,因为这台机器配置要求不高。对于流控系统,在基础线上,我们一般保持每台机器每秒承载3000个左右的并发请求。在百亿级流量场景下,每秒并发请求峰值在几十万级别。所以这个流控集群部署到几十台机器就够了。而公司的kv集群也天然支持超大流量和高并发写入。所以按需扩容kv集群,抗高并发带流量写入不是问题。其实在我们自己的架构层面,我们已经做了很多。优化(存储和计算分离的关键点),所以kv集群的定位基本是onlinestorage,一种在线存储。通过对key和value数据类型的合理巧妙设计,将我们对kv集群的读写请求优化为最简单的key-value读写操作,自然保证高并发读写没问题。另外,稍微剧透一下。后面讲到全链路99.99%高可用架构的时候,这个流控集群会发挥巨大的作用。它是上一个和下一个之间的链接。MQ集群故障前的高可用保证,以及KV集群故障后的高可用保证,都是通过流控集群来实现的。6、数据动静分离架构完成上述重构后,我们进一步优化了核心自研内存SQL计算引擎。因为在实际生产环境的运行过程中,我们发现了一个问题:Slave节点每次都会抽取一个数据分片关联的各种数据,然后进行计算,其实是没有必要的!举个例子,如果你的SQL需要对一些表进行关联计算,其中涉及到一些静态数据,大部分是静态的,而且那些表中的数据一般很少发生变化,所以没必要每次都通过网络时间。从kv存储中提取那部分数据。其实我们可以在Slave节点上为这个静态数据做一个轻量级的缓存,然后只有datashards中对应的动态变化的数据才能从kv存储中提取数据。通过这种数据动静分离的架构,我们基本上把Slave节点对kv集群的网络请求降到最低,性能最大化。大家看下图。七。阶段性总结到目前为止,这个架构基本上演进得比较好,因为可以支持超高并发写入、极速高性能计算、按需任意扩展等各种特性。基本上,从写入到计算,这两个步骤都不是很大的瓶颈。而且,通过自研的内存SQL计算引擎方案,我们的实时计算性能已经提升到毫秒级标准,基本达到了极致。八、下一步期待下一步,我们要看看这个架构的左边,还有一个MySQL!首先,实时计算环节和离线计算环节会将大量的计算结果导入到那个MySQL中。其次,面对几十万甚至上百万的B端商户,如果要实时展示数据分析结果,页面上一般会有规律的JS脚本,每隔一段时间就会发送请求加载最新的数据计算结果。几秒钟。所以,实际上,专供终端用户使用的MySQL也会承受海量数据、高并发写入压力、高并发查询压力。