ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

【架构师从入门到进阶】第六章:服务集群优化——第二节:集群并发无状态集群

2026/9/6 16:11:04 拓冰建站 浏览量
【架构师从入门到进阶】第六章:服务集群优化——第二节:集群并发无状态集群 【架构师从入门到进阶】第六章服务集群优化——第二节集群并发无状态集群集群并发集群的缺点无状态节点集群什么是无状态与有状态对比如何保证系统无状态协作的问题本篇文章我们来学习使用集群当中的集群整体并发和无状态节点的集群。集群并发当网站遇到高并发挑战的时候一般情况下第一反应是什么呢我们做好一个网站上线了然后用户激增然后网站达到了系统的性能瓶颈我们一般第一反应应该是通过负载均衡技术构建由多个服务器组成的服务器集群将并发访问的请求分发到多台服务器上处理避免单一服务器因负载压力过大而造成响应缓慢的问题使用户具有更好的响应延迟的特性。比如说我们项目上线之后有两个服务器然后最开始请求只有100个服务器处理起来轻轻松松突然之间来了一万个请求服务器就处理不过来了导致了大量的请求的堆积并且用户体验也不好服务器磁盘满了、内存也满、CPU也满服务器面临着崩溃那么这个时候第一解决办法就是不停的通过部署服务器来构建一个集群当然前面会有负载均衡。这种模式是最常用的模式就是大家在做架构设计的时候一旦遇到这种问题第一思路就是扩展服务器。好多同学说这太没有技术含量了吧要是我的话就会今天晚上加班我来优化代码。但是大家想一下如果说优化代码其实你说100个到一万这种量级你怎么优化代码能让你的代码的效率提高到100倍好多人这样体现技术但是几乎很难达到并且时间也不允许。可能你在优化代码的时候用户来请求感觉你的网站不好用就撤了说这什么破网站不用了就走了损失了用户。所以说第一反应花钱买机器部署集群。包括好多大厂最开始也是这么做的大家也不用觉得说这种方式太低级。好了集群是实现系统内分流的一种最简单的方法。在集群系统中每个节点都是同质的这些服务器节点基本上部署的代码都是一样的机器也是一样的配置实际工作中有可能是不一样的配置可能有的服务器的配置高一些有的服务器的配置低一些这个不强求但是最好是一样的然后对外提供的服务也是一样的然后前面就通过一个叫做负载均衡组件的东西一般会用Nginx、OpenResty、或者Kong、或者Gateway都可以做得到。集群的缺点那么集群的缺点有哪些呢比如说用户发出两个请求一个请求是a另外一个请求呢是b。比如说a是执行update操作但不一定是改数据库里的有可能是改别的地方只要能改数据的地方。然后b就是做查询的query查询一些数据然后先发出a再发出b这样的话就相当于b依赖于a。如果用户先发出a再发出b我们期望的结果是按照这个顺序b查出来a修改后的结果。但是如果a和b被分配到不同的两个结点上有可能就是a去了这个节点b去了另一个节点另一个节点可能效率高一些处理快一些有可能是b先执行a在后面执行。那这样的话结果就会有误差就是不正确的。又或者a用了一个map里面put了一个值然后这个map存在于一个服务器的内存当中b在另外一个服务器上就是查不到的这样的话数据还是不一样的。所以这就是说通过集群的方式遇到这种有顺序的请求的时候大家应该能想到的一些问题。无状态节点集群我们来看后面的无状态节点集群。前面我们讲了集群中a和b有请求的先后顺序的问题解决方案就是无状态节点集群。什么是无状态我们先来说一下什么是无状态。假设有一个用户比如说先后发出了a和b两个请求然后无论a和b的请求是否落到同一个服务器上都不影响b的结果的准确性。我们前面讲过这个问题a和b有先后顺序比如说a落到了一号服务器上b落到了二号服务器上而此时的b也能拿到正确的结果这就是无状态的服务。就是后面的请求不依赖于前面的请求每次请求到一个服务器服务器都把它当成一个完整的请求。我们这里来总结一下无状态就是没有特殊状态的服务各个请求对于服务器来说统一无差别的处理。就是不管你什么时候来请求对我来说都一样。请求自身携带了服务端所需要的所有的参数就是每次来都带着“你是谁”然后服务端自身不存储你请求来了别在我这个服务器里面存东西。好多同学说了那存在数据库里不也是通过数据库服务器存的吗数据库是一个公共的存储这里所说的服务不存东西是指服务器上面不存东西。就像我们前面所讲的map的例子也就是说服务器中连map都不存。其实在一些代码的优化当中是可以存map但是这种存map肯定是存那种几乎不会变的map比如说一些几乎不变的模板类的数据。与有状态对比跟有状态再对比一下会更加加深我们的理解什么是有状态呢比如说一个服务器它的内存里有个map如果前面的请求a落在了节点一上修改了某个程序中的map的值。但是b读取的时候它就落到了另外一个节点上这个时候就是有状态的。b依赖于前面a的这个请求这就是有状态的服务。类似于什么呢比如说一个登录请求登录完之后这个服务器里有一个session记录了我的登录状态然后我又来一个请求结果请求打到了另一个服务器上另一个服务器上没有我的session那么就判断我是一个未登录的状态。也就说后面这个请求依赖于前面的这个请求这就是有状态的。如果说登录完之后服务器自己不存储这个session而是给用户发了一个令牌你每次来带着这个令牌来我看到这个令牌就知道你登录了然后b请求哪怕落到了其他节点上落在了不是他登录的那个节点上只要他每次来带上他的令牌服务器都认为他是已经登录过的。也就是说请求来的时候自己带上自己所要的参数别让服务器自己去帮他记这个就是无状态就是不要让服务器去做额外的事情。通过这个例子大家应该就能比较深刻的理解无状态和有状态的区别。如何保证系统无状态要想让系统保证无状态必须保证所有的接口都是恒等类的接口。即接口被调用前后系统状态不能发生任何改变。系统的状态指的是一台服务器web程序的状态严格意义上来说并不考虑外部的存储不论你是redis也好mysql也好公共的这种外部的存储不算。如果从特别严格意义上的角度来说只有查询类的接口满足这个条件但是我们在我们的项目中不可能所有的接口都是查询类的接口可能有增删改查只是一方面。那么我们这个时候就会让多个服务器部署同样的代码然后大家都连着一个公共的存储。通过共享存储来实现我们服务器满足无状态条件的同时还满足了我们对业务的增删改的操作。协作的问题如果通过我们刚才的讲解我们做到了无状态那么还会有协作的问题。比如说在我们的项目中部署了很多个服务每个服务代码都是一样然后每个服务里面都有一个功能叫做定时发短信就是到了12点给一个用户发一个信息。这样的话所有的节点到了12点都会发出这个信息这样的话是不是就重复操作了第一浪费了系统的资源第二对用户造成了骚扰那么这个问题该怎么解决呢一个是从从内部解决一个是从外部解决。遇到这种问题需要跟别人协作的的这种场景呢需要从外从内部解决。内部基本上是用锁来实现的。就是我保证只执行一次那么执行一次的时候我去第三方外面找一个地方加一把锁然后我去做做完之后在外面再存储一个状态就说我已经做过你再来执行的时候首先你要判断这个地方有没有上锁如果有上锁了。要么是等着锁要么是别做还有一个就是来执行这个发短信任务的时候看看这个存储里面有没有人给他发过如果有发过那么自己的任务就不要执行了如果没有人给他发过自己再加锁去执行。还有外部的方式。我通过一个外部的服务来唤醒到了某一个时间点点外部服务给他发个信息说你去执行这个任务然后外部服务把它这个请求发给执行任务的服务。也就是说自己就不要想着谁去执行了而是让外部来唤醒谁去执行这样的话就不存在问题了。其实我们在工作中会有很多类似于这样的使用场景就是说每个服务器的代码中都有一个定时任务都会想着怎么去做可能会遇到各种各样的稀奇古怪的问题就刚才所说的这种重复发送的问题。那么通过我们这两种方式都是可以做到的。这个就是我们所说的无状态的集群通过公共的存储来实现当并发量上来的时候我可以额外的再多加几个机器只要让它们都连着我的公共存储就OK了。但是这种情况下我们一定要记住我们的服务器是无状态的只有无状态才能更方便的去做水平扩。