最近在学习Redis、Doctor相关技术知识,它们与分布式系统有着很大的关系。
而对于分布式系统,它本身就是随着业务的不断推进,技术架构不断演进而得到发展和实现的。而所谓的分布式系统,实际上就是想办法引入更多的硬件资源,来解决当下的业务问题。
所以,这篇博客记录一下我学习具体的技术栈之前,对业界的技术架构发展的一个认识和简单了解。
市场上绝大多数得产品部署,都是这种单机架构。
所谓的单机架构,就是应用服务和数据库公用一台服务器。
互联网早期或者业务本身低的访问量的时候,所采用的架构。下面以电子商务的架构图举例:
它的工作原理就是应用和数据库在单个服务器上协作完成业务运行。
需要补充的点:
1.计算机硬件发展速度非常快。哪怕只有一台主机,这一台主机性能很高,可以支持非常高的并发与存储。
2.如果业务进一步增长,用户量和数据量水涨船高,一台主机难以应付的时候,此时单机不可,需要过渡到分布式系统进行解决。
因为一台主机的硬件资源始终是有限的。所谓的硬件资源,是有:CPU资源、内存、硬盘、网络...等这些资源的,而此时两个服务在一台主机上跑那就是以进程的形式,同一时刻请求变多了,自然就会导致某个硬件资源不够了(比如一直阻塞等待非cpu资源),这样就会导致服务器的处理请求时间变得很长。
3.针对上述问题如何处理呢?
业界的处理方法分为两种:1.开源,2.节流。
1开源:简单粗暴,增加更多的硬件资源.(存在隐患,还是存在上限-取决于主板的扩展能力)->一台主机扩展到极限,那么引入多台主机了。(不是买了就完事了,需要在软件层面上做出调整和适配)->分布式系统
2节流:软件上优化(凭本事,性能测试找到瓶颈,对症下药)-存在一定难度(水平哦~)
5.引入了多台主机,那么就是”分布式系统“(万不得已,系统的复杂程度会打打提高-指数级增长,出现bug的概率越高)
优点在于部署简单,成本低下。
缺点非常明显:存在严重的性能瓶颈(单机操作系统并发不会太多、请求量变大不好处理)、数据库和应用相互竞争资源(并发上来了),此缺点也为之后的升级为分布式系统埋下了伏笔。
如果是单个服务器,软件(节流)在优化硬盘始终存在瓶颈,而如果访问量增多的话就会出现问题,所以需要选择开源的方式引入更多的硬件资源进行扩展。
我们让应用服务和数据库服务使用不同的服务器就可以解决单个服务器的性能瓶颈问题。
因为单机存在严重的资源竞争,站点变慢。所以我们决定扩展为两个服务器。
工作原理就是:应用服务和数据库在各自的服务器上完成运行,之间通过网络交互。
其他补充:
应用服务器,包含更多的业务逻辑,吃CPU和内存。数据库服务器,需要更大的硬盘空间,更快的数据访问速度。这样,我们可以不同配置的给予资源,可以达到更高的性价比。
优点:成本相对可控、性能对比单机有提升、数据库单独隔离,较为安全。
缺点:硬件成本变高、性能任然存在瓶颈,无法应对海量开发。
如果海量开发的话,可以发现应用程序处理并发的问题还是不够强(应用服务器比较吃CPU和内存,处理海量的着不住),那么我们可以对应用服务器进行开源,扩张更多的应用服务器节点形成应用服务集群,这样处理并发能力大大增加。
我们引入了多个应用服务器节点,并且决策层通过负载均衡决策应用服务,应用以集群的方式运作。
因为原本的单个应用不足以支持海量的并发请求,高并发时候站点相应变慢,所以引进应用服务集群,从而解决上层的高并发问题。
架构原理:应用变成多个(横向扩展),通过负载均衡支持海量的并发。
其他补充:
1.用户请求先到负载均衡器/网关服务器(单独的服务器)。
负载均衡 类似于多线程。多线程局限于一个CPU,负载均衡引入更多的主机和CPU。
对于负载均衡器,有很多 负载均衡 的具体算法。
负载均衡器,对请求的承担能力要远超过应用服务器。(分配任务和执行任务量是不同的),实在不行,再引入更多的负载均衡器。
2.数据量变多,管理成本变高。
3.增加应用服务器,能处理更高的请求量,但是随之存储服务器,要承担的请求量也就更多。
优点:
1.应用服务高可用,满足一个挂掉还存在其他服务
2.应用服务具备一定的高性能。
3.应用服务具备一定的扩展能力。
缺点:
1.数据库成为性能瓶颈,无法应对数据库的海量查询
2.数据库是单点,没有高可用
3.运维工作增多,扩展后部署运维工作增多,需要开发对应的工具进行快速部署。
4.硬件成本较高。
高并发能够处理完毕,但是数据量过大,单个数据库服务器也需要进行扩展。
对于数据库我们也可以采用开源的方式扩展。并且,我们可以注意到一个规律:在一个网站中,往往读取数据比写数据多很多,那么我们可以基于这个点,对数据库进行扩展。
将数据库的读写操作分散到不同的节点上,数据库服务器搭建主从集群,一主一从,多从也行。(主从结构的关系是为了保持数据的一致性,多个同级的话,一致性很难保证)数据库主机负责写操作,从机只进行读操作。
数据库成为瓶颈,而互联网一般读多写少,数据库承载压力大,主要是由这些读请求造成的,那么我们可以将读写操作进行分离。提高数据库的吞吐量。
架构工作原理:数据库服务器变成了多个,数据库主机负责写操作,从机负责读,数据库主机通过复制将数据同步到从机。
其他补充:
1.在应用服务集群架构的基础上,将数据库分为主数据库(写)、从数据库(读)。主从之间可进行数据同步。
实际的应用场景中,读的频率是比写要高的。
主服务器一般一个,从服务器可以有多个。
同时数据库通过负载均衡的方式,让应用服务器进行访问
2.数据库天然存在一个问题,响应速度是很慢的(读取硬盘)。
优点:
1.数据库的读取性能提升
2.读被其他服务器替代,写的效率间接提高
3.数据库存在从库,可用性提高
缺点:
1.热点数据频繁读取导致数据库负载很高
2.当同步挂掉,或者同步延迟大,数据会发生不一致。
3.服务器成本进一步增加。
可以看到,虽然我们将数据库集群化了,但是写的压力还是很大,因为本身存储很多数据的数据库要和硬盘打交道,所以注定响应非常慢。
根据木桶效应,我们势必需要补齐这个坑,根据经验,我们发现中间加个缓存可以非常有效的解决这个问题。而缓存容量小,那么就决定我们存储什么样的数据:根据二八原则(20%的热点数据,80%的冷数据),这样扩展就可以极高的扩展我们的数据读取能力。
引入缓存,实行冷热分离,将热点数据放到缓存(内存)中快速响应。
海量请求导致数据库负载过高,站点响应再度变慢,引入缓存能帮助数据库更好的解决这个问题。
架构工作原理:多了缓存服务器,将热点数据全部放到缓存中去,不常用的数据再去查询我们的数据库。
其他补充:
1.数据库相关服务器再次增加:缓存服务器,在里面放一小部分热点数据。(会被频繁访问到的数据)
二八原则:20%的数据,能够支持80%的访问量。极端的情况:一九
2.原本数据库任然存取完整的全量数据。
3.注意,缓存服务器想要快,就必须要付出代价。--Redis的主要应用场景。注意缓存和存储服务器数据同步,要求:写入时两个都需要写、要么失败同时失败,具体实现查看代码如何实现。
4.不光要考虑请求量,还需要考虑数据量。
5.分布式系统需要同时应对请求量和数据量。
6.据库存不下数据怎么办?而且本身数据过多,查询操作时效率非常低下!
优点:大幅降低对数据库的访问请求,性能提升非常明显
缺点:
1.带来了缓存一致性、缓存击穿、缓存失效、缓存雪崩等问题。
2.服务器成本进一步增加
3.业务体量变大后,数据不断增加,数据库单库、单表体量太大,数据查询会很慢,*数据库再度成为系统瓶颈。
虽然访问速度提升了,但是数据库还是存在一个问题:就是存储的数据会不断变大。数据库的单库和单表太大的化会严重影响效率。
如果我们能够对数据库内部的存储信息分开存储的化,就可以解决很多的问题。
数据库的数据被拆分,数据库数据分布式存储,分布式处理,分布式查询,即分布式数据库架构。
单机的写库会逐渐达到性能瓶颈,需求拆分数据库,数据表的数据量太大,处理压力太大,需要进行分表,为降低运维难度,业界逐渐研发了分布式数据库,库表天然支持分布式。
架构工作原理:数据库是由多个主从库或者存储集群构成,支持分布式大规模并行处理。
其他补充:
1.分库分表:本来一个数据库服务器,这个数据库服务器上有多个数据库(create database),在可以引入多个数据库的服务器,每个数据库服务器存储一个或一部分数据库。(分库后一部分数据库可以存储一部分的表);如果某个表非常大,那么针对表进行拆分;这样数据量在大,数据库也能解决了。
具体的分库分表如何实践,结合实际的业务场景展开。
业务至关重要,业务决定了技术,技术只是给业务提供支持。
2.但是对于应用服务器,一个服务器程序做了很多的业务,这可能会导致这个一个服务器的代码变得越来越复杂。
优点:数据库吞吐量大幅提升,不再是瓶颈。
缺点:
1.跨库join、分布式事务等问题,这些需要对应的解决方案,目前mpp都有对应的解决方案。
2.数据库和缓存结合目前能够抗住海量的请求,但是应用的代码整体耦合在一起,修改一行代码就需要整体重新发布。
此时目光重新回到应用上。因为数据库的瓶颈问题得到解决,但是应用的代码耦合度过高了。并且处理到当前如此高的并发量,服务规模肯定很光,团队人数肯定是增多的。此时开发人员开发代码是对于耦合度高的代码时非常难受的。所以我们需要对应用程序进行一个拆分。
为了更方便于代码的维护,就可以把这样的一个复杂的服务器拆分为更多的,功能更单一,但是更小的服务器(微服务)。服务器的种类和数量就增加了。
微服务是一种架构风格,按照业务板块来划分应用代码,使单个应用的职责更清晰,相互之间可以做到独立升级迭代。
注意之前的架构应用服务在一起的缺陷:
1.扩展性差:应用程序无法轻松扩展,因为每次需要更新应用程序时,都必须要重新构建整个系统。
2.持续开发困难:一个很小的代码改动,也需要重新部署整个应用,无法频繁并轻松的发布版本
3.不可靠:即使系统的一个功能不起作用,可能导致整个系统无法工作
4.不灵活:无法使用不同的技术构建单体应用程序
5.代码维护难:所有功能耦合在一起,新人不知道如何下手
架构工作原理:应用拆分成了多个微服务,微服务相互之间协作完成整个应用服务。
其他补充:
1.针对应用服务器进行拆分(本身处理逻辑复杂 - 耦合度大)
2.微服务本质上是解决“人”的问题。
3.当应用服务器变得复杂了,势必需要更多的人来维护了。人多了就需要配套的管理,需要把人组织好。(分组,分组配对管理,分组后进行分工。)
4.按照功能,拆分为多组微服务,有利于上述人员组织的分配了。
5.引入微服务解决了人的问题,但是付出的代价:
5.1.系统性能下降(想保证性能不下降太多,只能引入更多的机器,更多的硬件资源 = > 充钱)
拆出来的更多服务,多个功能之间要更依赖网络通信
网络通信的速度很可能是比硬盘还慢的
-幸运的是,硬件技术的发展,网卡有W兆网卡(贵!),读写速度已经能超过硬盘读写了。5.2.系统复杂程度提高,可用性受到影响。
服务器更多,出现问题的概率更大了。
需要一系列的手段,保证系统的可用性。
-监控报警、运维人员
优点:
1.灵活性高,服务独立测试,部署升级,发布。
2.独立扩展:每个服务可以各自进行扩展
3.提高容错性:一个服务问题并不会让整个系统瘫痪
4.新技术的应用扩展容易:支持多种编程语言。
5.解决了人的问题
6可以给不同的服务进行不同的部署。
缺点:
1.*运维复杂变高,部署复杂,应用服务环境变得复杂。
2.资源使用变多
3.处理故障困难
虽然应用细化出来了,但是对于运维就非常头疼了。
因为这样的话如果人手动去部署服务非常复杂,并且不同的微服务所在环境也不可能相同,变得非常复杂。那么此时针对这样的情况,我们需要能够让微服务方便部署并且有着自己何时的环境地方。
借助容器化技术(如docker)将应用/服务可以打包为镜像,通过容器编排工具(如k8s)来动态分发和部署镜像,服务以容器化的方式运行。
出现原因:
1.微服务拆分细,服务多部署工作量大,配置复杂,容易出错。
2.微服务数量多扩缩容麻烦,容易出错,每次缩容再扩容重新配置服务对于的环境参数信息
3.微服务之间运行环境可能冲突,需要更多的资源来进行部署或者通过修改配置来解决冲突。
架构工作原理:应用拆分为了多个微服务,如用户服务... 每个微服务打包到一个容器中,相互协作完成系统功能,通过容器编排工具完成部署运维。
对于一个容器打包:
容器:每个包裹之间是隔开的,互不干扰。
docker:类似于将应用打包成一个包裹
镜像:类似于一个包裹
k8s:类似于一个快递公司。
优点:
1.部署运维简单。
2.隔离性好
3.支持滚动更新。(版本更新那种,回退版本、更新版本 :使用镜像替换即可)
缺点:
1.技术栈变多。(k8s/docker/SpringClound/Dubbo)
2.机器还是需要公司本身管理,非大促的时候需要闲置大量的机器资源,机器自身成本和运维成本都极高,资源利用率低,可以通过购买云厂商服务器解决。
这样就可以支持一个海量并发的问题。
在实战的架构中,存在多种的技术和框架需要我们去详细的学习:
1.负载均衡(CLB、SLB)
2.防火墙(WAF)
3.网关(API网关)
4.k8s(TKE, ACK)
5.容器打包(docker, containerd)
6.微服务(spring cloud, ...)
7.统一数据服务层(屏蔽底层差异:利-效率提升、弊-底层掌握不好)
8.Redis[缓存数据]、云Mysql/TDSQL[基础数据]、Oss/COS/minio[视频、图片对象存储]、ES集群[搜索]、MongoDB集群[描述、评论]、Hadoop集群(MaxCompute/EMR)[大数据]
服务器->[购买服务器]->应用->[横向扩展、负载均衡]->数据库->[读写分离、集群化、缓存技术、分库分表、分布式数据库]->应用->[微服务架构]->运维->[容器化技术docker、容器编排技术k8s]->服务器->[云服务器]
1.单机架构(应用程序 + 数据库服务器)
2.数据库和应用分离
应用程序和数据库服务器分别放在不同主机上部署了。
3.引入负载均衡,应用服务器=>集群
通过负载均衡器,将请求比较均匀的分发给集群中的每个应用服务器.(集群中的某个主机挂了,其他主机任然可以承担服务,提高了整个系统的可用性)
4.引入读写分离,数据库主从结构
一个数据库节点作为主节点,其他N个数据库节点作为从节点
主节点负责写数据,从节点负责读数据。(主节点需要将修改的数据同步给从节点)
5.引入缓存,冷热数据分离
进一步提升了服务器针对请求的处理能力。
二八原则。
Redis在一个分布式系统中,通常就扮演着缓存这样的角色。
引入的问题:数据库和缓存之间的数据一致性问题。
6.引入分库分表,数据库能进一步扩展存储空间
7.引入微服务,从业务上进一步拆分应用服务器
从业务功能的角度,把应用服务器拆分为更多功能更单一,更简单,更小的服务器。8.引入容器编排架构,将微服务更加合理并且方便的部署在服务器上,减轻了运维的压力。
上述这样的几个演化的步骤,只是一个粗略的过程,实际上一个商业项目,真实的演化过程,都是和他的业务发展密切相关的。业务是最重要的,技术只是给业务提供服务的。所谓的分布式系统,就是想办法引入更多的硬件资源,来解决当下的业务问题。
综上,需要注意一点:围绕着业务展开的。
1.如何决策要不要演进?结合业务、实际情况去演进。
2.架构必须这么演进么?不是。根据团队的技术栈储备。
3.架构必须是这么几个么?不是。都可以拆开。
4.docker的核心作用。完成了打包操作,能够让服务容器化运行。
对于一些分布式的名词概念,这里可以阐述一下:
应用(Application)/系统(System)
一个应用就是一个/组 服务器程序模块(Module)/组件(Component)
一个应用,里面有很多个功能,每个独立的功能就是一个模块、组件
分布式(Distributed)
引入多个主机/服务器,协同配合完成一系列的工作(物理上的多个主机)
集群(Cluster)
引入多个主机/服务器,协同配合完成一系列的工作(逻辑上的多个主机)可能是多个服务器程序 更广一些...
主(master)/从(slave)zzzq
分布式系统种一种典型的结构。多个服务器节点,其中一个是主,另外的是从。从节点的数据要从主节点的数据同步过来。中间件(Middleware)
和业务无关的服务(功能更加通用的服务)
1.数据库、2缓存、3.消息队列......评价指标:
-可用性(Availability):一个系统的第一要务
系统整体可用的时间/总的时间
(4个9即99.99%)
-响应时长(Response Time RT)
衡量服务器的性能。(适合具体服务要做的业务密切相关的)
越小越好。
-吞吐(Throughput)vs 并发(Concurrent)
衡量系统的处理请求的能力.衡量性能的一种方式。
以上只是对学习的知识点进行了整理,便于后续学习架构能够结合演进的思想进一步的去思考总结。