目录
1. 架构演进
1.1 单机架构
1.2 什么是分布式架构
1.3 数据库和应用分离
1.4 引入负载均衡
1.5 引入数据库读写分离
1.6 引入缓存
1.7 数据库分库分表
1.8 微服务架构
2. 分布式系统下的常见概念
1. 架构演进
1.1 单机架构
单机架构只有一台服务器, 这个服务器需要负责所有的工作.
假定现在有一个电商网站 :
当用户想要查看商品列表的时候, 有以下几个步骤 :
- 应用程序服务器通过 selct 语句发送查询请求给 MySQL 服务器;
- MySQL 服务器处理请求, 查到数据后返回给应用程序;
- 应用程序通过 Http 协议响应给用户, 显示到浏览器界面;
-- 单机架构在某些场景下, 也是可以省去数据库的, 比如说有些网站只是介绍一下这个公司, 或者这个公司的产品, 就不太需要数据库, 但是大部分网站还是需要使用到数据库的.
-- 单机架构虽然没有分布式架构听起来那么高大上, 但是千万不要瞧不起这个东西, 毕竟绝大部分公司的产品都是这种单机架构. 随着计算机硬件的发展, 现在一台主机的性能都是非常高的, 一台主机就可以支持非常高的并发和非常大的数据存储, 应付几万个用户还是绰绰有余的, 但是绝大部分中小型公司的用户可能还达不到这个水平.
1.2 什么是分布式架构
--- 随着业务进一步增长, 用户量和数据量都水涨船高了, 一台主机难以应付了, 这时候就需要引入更多的主机, 引入更多的硬件资源.
一台主机的以下几个主要资源是有限的 :
- CPU
- 内存
- 硬盘
- 网络
服务器每收到一个请求的时候, 都是需要消耗一台主机的主要资源, 如果同一时刻处理的请求多了, 此时就可能会导致某个硬件资源不够用了, 无论是哪个方面不够用了, 都可能会导致服务器处理请求的时间变长, 甚至于处理出错.
遇到资源不够用的情况该怎么解决 :
1. 开源 : 增加更多的硬件资源.
但是一台主机上面能够增加的硬件资源也是有限的, 取决于主板的扩展能力.并且不是说新买来的机器就可以直接解决问题了, 也需要软件上做出对应的调整和适配.
2. 节流 : 做出软件上的优化.
这个就很考验程序员的经验和技术水平, 需要通过性能测试, 找到是哪个环节出现了瓶颈, 再对症下药.
使用上述开源的方法, 一旦引入多台主机了, 咱们的系统就可以称为是 "分布式系统" 了.
-- 引入分布式系统其实是无奈之举, 因为分布式架构下, 系统的复杂程度会大大提高, 出现 bug 的概率会变高, 进而咱们加班的概率以及丢失年终奖的概率也随之提高了!!
1.3 数据库和应用分离
前边由于硬件资源的不够用, 导致处理请求的时间过长, 或者请求错误, 所以接下来我们就可以针对应用服务器和数据库服务器分别部署在两台主机上.
1. 应用服务器里面可能会包含很多业务逻辑, 所以比较吃 "CPU" 和 "内存" 资源. 而硬盘资源使用则相对较少.
2. 数据库服务器则需要更大的硬盘空间, 更快的数据访问速度.
于是我们可以针对不同服务器的类型, 配置不同的硬件类型. 比如说给应用服务器配置机械硬盘(便宜, 慢), 给数据库配置固态硬盘 (贵, 快), 从而达到一个更高的性价比.
1.4 引入负载均衡
由于应用服务器比较吃 "CPU" 和 "内存", 如果把 CPU 或者内存吃没了, 此时应用服务器就顶不住了. 于是我们就需要引入更多的应用服务器, 才能有效的解决上述问题.
当用户发送请求过来时, 请求会先到达负载均衡器(网关服务器), 然后负载均衡器再将请求分发给下面的应用服务器. (上图看起来是两个应用服务器, 实际上可能是多个)
假设有 1w 个用户请求, 有两个应用服务器, 此时在引入负载均衡的前提下, 就可以让每个应用服务器承担 5k 的访问量. 如果应用服务器搞个十台, 八台的, 那不就更加能够降低每一台机器所承担的压力. 看到这, 是不是会觉得 "多线程" 有点像!! 但是多线程还只是局限于一台主机, 局限在一个 CPU 上, 而此处的负载均衡则是引入更多的主机, 引入更多的 CPU, 每一台主机里仍然可以按照多线程的方式去安排任务.
此处的负载均衡器就有点像一个公司的领导, 要负责管理, 要负责把任务分配给每个员工. 而分配任务需要分配的相对均匀一点, 对于负载均衡器来说, 就会牵扯到很多的负载均衡具体的算法. (例如 : 轮询...)
那是否会出现请求量大到负载均衡器也扛不住了呢 ?
-- 虽然负载均衡器是一个 "领导", 只需要布置任务, 一般情况下, 不会说处理不过来, 但是处理不过来也是有可能的, 如果真的处理不过来了, 我们就可以引入更多的负载均衡器.
1.5 引入数据库读写分离
当我们引入更多的应用服务器时, 确实能够处理更高的请求量了, 但随之数据库服务器, 要承担的请求量也就更多了, 那怎么办呢 ? 还是要么开源, 要么节流. 由于节流门槛高, 更复杂, 于是我们可以引入更多的机器.
当我们引入多台数据库服务器时, 数据库服务器又分为两大类, 一种叫做主数据库(master), 一种叫做从数据库(slave). 主数据库负责写 (增删改), 从数据库负责读(查), 并且从数据库中的数据需要从主数据库中同步, 也就是说上面的应用服务器需要读数据的时候, 就从从数据库中读, 需要写数据的时候, 就在主数据库中写, 同时主数据库也会实时地, 定期地将数据同步到从数据库.
这样从一个数据库既负责读又负责写, 过渡到了两个数据库, 一个数据库负责写, 一个数据库负责读, 从而就把每一台机器的压力就降低了.
而且实际应用场景中, 读的频率是比写的频率要高很多的, 所以一般使用到数据库分离时, 主数据库服务器一般是一个, 从服务器可以有多个 (一主多从). 同时这多个从服务器又可以使用负载均衡的方式让上面的应用服务器进行访问, 这样又可以进一步降低每一台从服务器的压力.
1.6 引入缓存
由于数据库天然有个问题, 响应速度 "慢" !! 不管怎么进行分库, 它终究是要从硬盘读取数据, 而读硬盘在某些场景下是接受不了的, 所以为了更进一步的提高数据访问效率, 还可以将数据进行 "冷热" 拆分, 其中热点数据放到缓存中, 而缓存的访问速度往往比数据库快很多.
根据二八原则: 20% 的数据, 能够支持 80% 的访问量. 所以缓存服务器中只是存储了一小部分热点数据, 也就是会被频繁访问到的数据, 而数据库中存储的仍然是完整的全量数据.
既然缓存那么快, 为啥不把数据都存在缓存中呢 ? 前面咱们聊到过, 缓存它虽然快, 但是小, 所以需要缓存服务器和数据库服务器搭配来使用, 这才是在有限成本下的一个比较划算的方案. (Redis 就是出现在缓存服务器这个位置)
后续应用服务器想要读数据的时候, 就可以先从缓存中读取, 如果缓存中存在,, 就不需要读数据库了, 如果缓存中不存在, 那么再去读数据库. 由于二八原则, 所以大部分的应用服务器请求都能在缓存中找到答案, 这就是数据库服务器所承担的压力又进一步减小了.
此时读数据读的又快, 同时数据库服务器压力又小!!
【问题】缓存和数据库中存在数据同步, 数据一致性问题 ?
如果后续应用服务器在数据库服务器中将数据修改了, 比如说缓存中存储某件商品的价格 20 元, 后续搞活动, 应用服务器在数据库中将价格改到 15, 这就需要缓存和数据库进行数据同步了. 但是这件事也不容易, 可能数据库中的数据改成功了, 但是缓存中的数据改失败了; 也可能数据库中的数据改失败了, 而缓存中的数据改成功了. 所以这件事情又变得复杂起来了!!
(如何解决后续我学会了再慢慢交代)
1.7 数据库分库分表
咱们引入分布式系统, 不光要能够应对更高的请求量(并发量), 同时也要能够应对更大的数据量. 请求量咱们目前解决了, 那么是否可能会出现, 一台数据库服务器已经存不下数据了呢 ? 答案无疑是肯定的. 虽然一台服务器存储的数据量可以达到几十个 TB, 即使如此也可能会存不下, 比如 : 短视频. 于是我们就需要针对数据库进行分库分表.
最初我们的架构是一个数据库服务器里头有多个数据库(create database...), 而分库就相当于引入多个数据库服务器, 每个数据库服务器存储一个或者一部分数据库.
【对应上图】 用户表由一个主服务器来存, 然后引入多个从服务器, 商品表由一个主服务器来存, 然后引入多个从服务器......
此时应用服务器想要读取用户表, 就可以访问用户表的服务器, 想要读取商品表, 就可以访问商品表的服务器, 当然读数据之前仍然可以先读缓存, 缓存没有再读数据库(主从).
如果某一张表特别大, 比如交易表大到一台主机存不下, 我们也可以针对表进行拆分. 可以将交易表拆成多张表, 分别存储到不同的数据库服务器上.
注意数据库的分库分表操作解决的是数据量过大的问题, 而不是并发问题. 另外数据库分库分表如何实现, 还是要结合实际的业务场景来展开.
1.8 微服务架构
回到应用服务器上面来, 咱们之前的应用服务器, 一个服务器程序里面做了很多的业务 : 用户,商品,交易等等. 这就可能导致这一个服务器的代码变得越来越复杂. 为了更方便于代码的维护, 就可以把这样的一个复杂的服务器, 拆分成更多的, 功能更单一的, 但是更小的服务器. 于是我们就可以引入微服务!!
由于系统总的功能是一定的, 现在单个服务器变小, 所以服务器的种类和数量就增加了. 用户相关的搞一组服务器, 商品相关的搞一组服务器, 交易相关的再搞一组服务器, 每一组服务器里面可能又有多台服务器来应对更高的请求量, 同时每组服务器各自又有各自的存储集群和缓存模块.
-- 目的 --> 引入微服务是为了解决 "人" 的问题!!
当应用服务器复杂了, 势必就需要更多的人来维护了. 人一旦多了, 就需要配套的管理来把这些人给组织好. 如果管理不到位, 搞了那么多人, 结果都在摸鱼, 或者帮倒忙, 这就会适得其反. 并且如果用户, 商品, 交易相关的人员都坐在一块, 到时候用户这边的人搞出来一个问题, 他们又会觉得是商品或者交易那边没做好导致这边出问题, 就会容易扯皮....
于是我们可以划分组织结构, 将这些人分成多个组, 然后进行分工, 每个组再别配备领导进行管理. 同时呢, 一个组的技术人员就可以专注于一个模块了, 就可以把这个模块把握的更好. 我们的应用服务器就可以按照功能, 拆分成多组微服务, 就可以有利于上述人员的组织结构分配了.
那么啥时候会涉及到人的问题 ?? --> 大厂
如果是小公司, 就那么几个, 十几个开发, 此时搞微服务就没太大的必要了.
【引入微服务的代价1】系统的性能下降
在引入微服务之前, 我们的用户, 商品, 交易这写模块的相互调用, 直接进程内就能调用. 而现在我们需要跨主机通过网络进行通信, 而网络通信这件事情可就比进程内通信慢太多太多了.
要想保证性能不下降那么多, 就只能引入更多的机器, 更多的硬件资源, 换句话来说就是 "充钱"!!, 所以说为什么大厂要搞微服务. 不过目前的硬件水平还是很给力的, 网卡现在有个 "万兆网卡", 它的读写速度已经能超过硬盘的读写速度了, 哪怕是在固态硬盘面前, 万兆网卡依然有优势, 所以有了万兆网卡, 虽然系统的性能会有所下降, 但也不至于下降太多.
-- 万兆网卡 [贵] --
使用万兆网卡虽然有防止性能下降过多的效果, 但是不是光一个万兆网卡就完事了, 首先万兆网卡就很贵了, 其次它还得配备万兆交换机, 万兆路由器, 甚至还要配备万兆带宽的网线, 这一套装备下来可得花不少钱, 所以说微服务可不是一些中小公司折腾的起的, 还得是大厂.
【引入微服务的代价2】系统的复杂程度提高, 可用性受到影响
在微服务环境下, 服务器更多了, 出现问题的概率就更大了, 这就需要一系列的手段来保证系统的可用性了. 比如 : 更丰富的监控报警, 配套的运维人员等等..
🍁微服务的优势
1. 解决了人的问题.
2. 更方便于功能的复用.
比如说用户模块在其他很多模块都需要使用, 那么单独提取出来就可以起到功能复用的好处.
3. 可以给不同的服务进行不同的部署
有的模块对于请求量, 或者数据量处理的不是很多, 那么我们给这个模块部署的时候, 机器就可以少部署点, 就可以配置一些低成本的机器; 然后负载量比较大的模块, 就可以部署更多的机器, 配置更好的机器,这样就有利于硬件资源的一个组合调配.
总言之, 微服务既有它的优势, 也有它的劣势, 具体怎么搞, 还得根据业务场景, 还得根据公司的钞能力!!
2. 分布式系统下的常见概念
应用 (Applicaction) / 系统 (System)
一个应用就是一个组, 或者说服务器程序
模块 Module / 组件 (Component)
一个应用里面有很多个功能, 每个独立的功能, 就可以称为是一个模块/组件
分布式 (Distributed)
引入多个主机/服务器, 协同配合完成系列的工作 (物理上的多个主机)
集群 (Cluster)
引入多个主机/服务器, 协同配合完成系列的工作 (逻辑上的多个主机)
中间件 (Middleware)
和业务无关的服务(功能更通用的服务)
可用性 (Avaliablility)
系统整体可用的时间 / 总的时间 // 一个系统的第一要务
响应时长 (Response Time RT)
处理一次请求需要消耗多长时间. 用于衡量服务器的性能.
吞吐 (Throughput) VS 并发 (Concurrent)
衡量系统处理请求的能力.也是用来衡量服务器的性能的.