你一定要知道的分布式架构演化史|干货满满

你一定要知道的分布式架构演化史|干货满满分布式架构的发展壮大正是一批批程序员前赴后继 遇到问题并解决问题 不断迭代得到的技术成果 为所有程序员点赞

一、前言

二、混沌初现

在咱们互联网的最早期,用户量很少,网络速度也很慢,用单节点的服务器搭建一个网站系统没有任何问题。可是随着互联网的普及,用户量越来越多,并发负载也随着越来越高,这时候单节点的服务器就开始承受不了了。

知识点一:为什么单节点服务器承受不了高并发负载呢?

以用户登陆请求Tomcat为例,Tomcat默认的HTTP实现是采用阻塞式的Socket通信,也就是每个请求都需要创建一个线程来处理。默认Tomcat的最大请求数是150,也就是说同时支持150个并发访问。当然这是可以配置的,但是最大并发数与硬件性能和CPU数量都是有很大关系的,所以一般情况下一个进程有500个以上线程在抢夺资源的时候,整体性能就已经非常低了。所以当用户量增多,并发变大,线程越来越多,服务器就会越来越慢,我们称之为负载过大。

那么,如何解决这个问题呢?

由于单进程有最大线程数限制,同时单个server的并发是有上限的,那我们可以在服务器上多启动几个server,也就是多搞几个进程。一个server上限是1000,那我们搞2个不就是2000了吗?这就是最早期的解决方案。

这个问题该如何解决呢?我们接着往下看。



三、负载均衡器诞生

为了解决前面的问题,我们不能让用户直接去访问server,而是需要把用户的所有请求汇总到一起,然后把这些负载均匀的分配给这些server,负责干这件事的程序,我们命名为负载均衡器。

看到均衡分配我们就想到了散列,也就是Hash。咱们技术的世界里,很多都是相通的,均衡分配也是。比如HashMap根据key的Hash值选择对应的数组下标,把数据分配到内置的key数组上,有效的降低了过高的key冲突。再比如redis经典的16384,它把集群的内存分为16384个slots,然后在放数据的时候会根据hash计算要放入的数据对应slots的索引位置,范围是0-16383。说到slots也会想到Flink,其实技术都是相通的。

在实际的使用中,这样的架构还会遇到问题。熟悉Tomcat的小伙伴应该知道session的概念,假如用户a第一次访问咱们的服务器,然后被负载均衡器分配给了server1,用户a的一些信息存放到了server1里面。然后用户a离线,过一会再次访问咱们的服务器,这次可能被分配给了server2。我们知道server1和server2是两个不同的进程,那我们如何拿到上一次登陆时存放在server1里面的数据呢?

这就要涉及到进程间数据交互了,我们接着往下看。



四、分布式架构走向成熟

我们知道进程间数据交互是非常非常慢的,大概比线程间的交互慢了1000倍!同时互联网早期的进程间交互是存在很多问题的,在那个满是C++程序员的年代,Java程序员是非常稀有珍贵的,同时那时候的技术也是非常难的。在一批批程序员的艰难探索下,最终诞生了璀璨的新星–Spring!

知识点三:Spring是怎么诞生的?

为了解决进程间的数据通信问题,我们现在所熟知的RPC协议在2001年的时候Java工程师根据这个协议可以使用RMI规则来实现,但是由于RMI非常非常难,所以那时候会RMI的Java工程师可以说是千里挑一,薪资自然也高,可以拿到2万每月,要知道那时候北京每平米的房价也只有1000多块钱!也正是因为这样,在2001开始Java被越来越多的人重视,开始登上历史舞台,持续至今。

但是由于RMI实在太难了,不利于推广,所以后来sun公司基于RMI封装了EJB框架。虽然EJB相比RMI简单了很多,但是还是不方便学习,也不方便使用。当时的技术圈还是很淳朴的,大家在抨击的同时还能给出自己的建议及解决方案。其中最著名的就是Rod Johnson为了表达自己对EJB的不满,专门出了一本书《Expert One-On-One J2EE Development Without EJB》在抨击的同时还表达了自己的观点和建议,其中最著名的观点就是:如何让应用程序能以超出当时大众所惯于接受的易用性和稳定性与J2EE平台上的不同组件合作

4.1、分布式用户诞生

下面回到咱们的分布式架构的演变上面来,怎么处理前面介绍的进程间数据传输问题呢?一共有三种方案:

  1. 当前server去之前存在用户数据的server上去获取。由于进程间通信过慢,舍弃;
  2. 某个server保存用户数据后,同步保存到别的server里面。由于这样会造成数据的冗余,同时进程间通信不可过于频繁的特性,难以处理用户频繁的数据更改需求,且性能较低,所以也舍弃了。
  3. 用户的请求被分配给某台server后,保存数据到外部的cache server里,同时cache server对所有server共享。 cache server就相当于缓存服务器,数据保存在内存里,面向所有server共享。当用户访问某台server时,它只需要去内存里获取数据就可以了。这时候大家应该会联想到redis,是的,redis处理订单之类的信息的时候,就充当了缓存服务器的作用。

4.2、分布式系统诞生

一个完整的系统肯定是有很多功能的,比如订单模块,商品模块,支付模块,后台管理模块。如果我们和前面一样把所有这些模块放在一个服务器资源里,由于不同模块的线程肯定是不一样的,比如5万个用户在看商品,2个管理员在看后台管理。

这时候2个人的线程肯定是抢不过5万个人的线程的,那这个问题该如何解决呢?

为了解决这个问题,同时考虑到单服务器性能存在瓶颈,扩展成本高昂。所以最好的办法就是水平扩展,多搞几台服务器还是比较容易实现的,且成本比较低。我们只能把服务器给拆开了,采用多台机器来提供服务,每个模块分配到不同的机器上,这样就不会存在线程争夺资源的情况了!

线程的问题解决了,还会有带宽的问题,比如我们的多台机器共享某个贷款,商品模块这个机器用户量非常大,带宽占用很高,这时候即使别的机器用户少,也会出现阻塞的现象,所以把服务器拆分后,我们还要把网络给拆分,采用不同的带宽来彻底解决用户分布不均匀的问题。

这种把一个系统拆分为多台服务器上运行的多个子系统的架构就是分布式系统。大致如下图所示:
在这里插入图片描述

同时我们把不同模块通用的功能给单独抽取出来,采用前面介绍的负载均衡器来均衡负载给各个模块集群就可以了,这种模式其实就是现在流行的微服务的概念。这时候采用负载均衡器有两种方案:服务端负载均衡和客户端负载均衡。

为了实现客户端负载均衡,引入了注册中心的概念。以登陆为例,客户端向注册中心发送登陆请求,然后注册中心告诉客户端可以访问哪台机器上的服务,然后客户端采用轮询的方式去对应机器上访问即可。大致的结构图如下:
在这里插入图片描述
比如eureka,zookeeper等都可以作为注册中心如上图所示那样来使用。不过咱们联系一下redis,它是没有这类注册中心或者负载均衡器的,那么它就相当于采用去中心化的方式来处理的数据。

知识点四:什么是去中心化?

五、总结

如果您对我的文章感兴趣,欢迎关注点赞收藏,如果您有疑惑或发现文中有不对的地方,还请不吝赐教,非常感谢!!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232678.html原文链接:https://javaforall.net

(0)
上一篇 2025年9月22日 下午6:01
下一篇 2025年9月22日 下午6:22


相关推荐

  • 支付宝AR抢红包?前端轻松就激活成功教程~

    支付宝AR抢红包?前端轻松就激活成功教程~近期阿里搞了各 LBS AR 实景的红包玩法 小伙伴们在公司里都玩疯了 有时候为了抢一个红包 会跑到另一个地方去拍照 虽然略麻烦 但整体的互动还是很有意思的 不过对于机智的前端童鞋来说 只需要简单的一段代码就能激活成功教程 AR 红包 当然成功率也不是 100 激活成功教程原理见 上线仅一天 支付宝 AR 红包惨遭技术流激活成功教程 感谢这位设计师童鞋 我们要做的事情其实很简单 把系统自带的小横条都去掉

    2026年3月17日
    2
  • 分子生物学词汇(P~R)[通俗易懂]

    分子生物学词汇(P~R)[通俗易懂]                Pelement P因子[果蝇的可动遗传因子,会造成杂种不育,可用作外源基因的载体]                Pnucleotide P核苷酸[见于免疫球蛋白及T细胞受体等基因,为重排中根据模板信息所插入]                pacemaker 起搏点,起搏器                pacemakerenzyme 定步酶   

    2022年7月27日
    9
  • C++实现邮件群发的方法

    这篇文章主要介绍了C++实现邮件群发的方法,较为详细的分析了邮件发送的原理与C++相关实现技巧,非常具有实用价值,需要的朋友可以参考下本文实例讲述了C++实现邮件群发的方法。分享给大家供大家参考。具

    2021年12月27日
    39
  • ViewStub延迟加载

    ViewStub延迟加载在项目中,难免会遇到这种需求,在程序运行时需要动态根据条件来决定显示哪个View或某个布局,最通常的想法就是把需要动态显示的View都先写在布局中,然后把它们的可见性设为View.GONE,最后在代码中通过控制View.VISIABLE动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源,虽然把View的初始可见View.GONE但是在Inflate布局…

    2022年6月28日
    25
  • 《Android平台开发之旅》学习笔记

    《Android平台开发之旅》学习笔记第三章:Android应用程序组件3.2Android应用程序组件Activity活动–形象大使Service服务–老黄牛BroadcastReceiver广播接收器–倾听者ContentProvider内容提供者3.3组件应用机制3.1.1组件之间的交互机制Intent(意向)组件实现组件之间的交互,马上要执行的动作3..1.2未决意意向Pending…

    2026年4月16日
    6
  • java定义byte类型,详解java中的byte类型[通俗易懂]

    java定义byte类型,详解java中的byte类型[通俗易懂]介绍byte,即字节,由8位的二进制组成。在Java中,byte类型的数据是8位带符号的二进制数。在计算机中,8位带符号二进制数的取值范围是[-128,127],所以在Java中,byte类型的取值范围也是[-128,127]。取值范围分析一直在想为什么不是-128到128呢?今天分析了一下这个问题。首先我们得明白一件事情,那就是运算规则:########################…

    2022年6月18日
    33

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号