写点什么

分布式系统关注点——“无状态”详解

  • 2019-01-24
  • 本文字数:2433 字

    阅读完需:约 8 分钟

分布式系统关注点——“无状态”详解

本文中我们开始聊一些让系统更简单,更容易维护的东西——“易伸缩”,首当其冲的第一篇文章就是“stateless”,也叫“无状态”。

一、初识“状态”

我们首先举个例子。


开发 Z 哥对运维 Y 弟喊:“Y 弟,现在系统好卡,刚上了一波活动,赶紧帮我加几台机器上去顶一下。”


Y 弟回复说:“没问题,分分钟搞定”。


然后就发现数据库的压力迅速上升,DBA 就吼了:“Z 哥,你丫的搞什么呢?数据库要被你弄垮了”。


然后客服那边接框也爆炸了,越来越多的用户说刚登陆后没多久,操作着就退出了,接着登陆,又退出了,到底还做不做生意了。


这个案例中的问题,产生的根本原因是因为系统中存在着大量“有状态”的业务处理过程。

二、“有状态”和“无状态”

N.Wirth 曾经在它 1984 年出版的书中将程序的定义经典的概括为:程序=数据结构+算法。(这个概括也是这本书的书名)


这是一个很有意思的启发,受它的影响,z 哥认为程序做的事情本质就是“数据的移动和组合”,以此来达到我们所期望的结果。而如何移动、如何组合是由“算法”来定的,所以 z 哥延伸出一个新的定义:数据+算法=成果。


通过程序处理所得到的“成果”其实和你平时生活中完成的任何事情所得到的“成果”是一样的。任何一个“成果”都是你通过一系列的“行动”将最开始的“原料”进行加工、转化,最终得到你所期望的“成果”。



比如,你将常温的水,通过“倒入水壶”、“通电加热”等工作后变成了 100 度的水,就是这样一个过程。


正如烧水的例子,大多数时候得到一个“成果”往往需要好几道“行动”才能完成。



这个时候如果想降低这几道“行动”总的成本(如:时间)该怎么办呢?


自然就是提炼出反复要做的事情,让其只做一次。而这个事情在程序中,就是将一部分“数据”放到一个“暂存区”(一般就是本地内存),以提供给相关的“行动”共用。



但是如此一来,就导致了需要增加一道关系,以表示每一个“行动”与哪一个“暂存区”关联。因为在程序里,“行动”可能是“多线程”的。


这时,这个“行动”就变成“有状态”的了。



题外话:共用同一个“暂存区”的多个“行动”所处的环境经常被称作“上下文”。


我们再来深入聊聊“有状态”。


“暂存区”里存的是“数据”,所以可以理解为“有数据”就等价于“有状态”。


“数据”在程序中的作用范围分为“局部”和“全局”(对应局部变量和全局变量),因此“状态”其实也可以分为两种,一种是局部的“会话状态”,一种是全局的“资源状态”。


题外话:因为有些服务端不单单负责运算,还会提供其自身范围内的“数据”出去,这些“数据”属于服务端完整的一部分,被称作“资源”。所以,理论上资源可以被每个会话来使用,因此是全局的状态。


本文聊的“有状态”都指的是“会话状态”。


与“有状态”相反的是“无状态”,“无状态”意味着每次“加工”的所需的“原料”全部由外界提供,服务端内部不做任何的“暂存区”。并且请求可以提交到服务端的任意副本节点上,处理结果都是完全一样的。


有一类方法天生是“无状态”,就是负责表达移动和组合的“算法”。因为它的本质就是:


  1. 接收“原料”(入参)

  2. “加工”并返回“成果”(出参)

  3.  

  4. 为什么网上主流的观点都在说要将方法多做成“无状态”的呢?

  5.  

  6. 因为我们更习惯于编写“有状态”的代码,但是“有状态”不利于系统的易伸缩性和可维护性。

  7.  

  8. 在分布式系统中,“有状态”意味着一个用户的请求必须被提交到保存有其相关状态信息的服务器上,否则这些请求可能无法被理解,导致服务器端无法对用户请求进行自由调度(例如双 11 的时候临时加再多的机器都没用)。

  9.  

  10. 同时也导致了容错性不好,倘若保有用户信息的服务器宕机,那么该用户最近的所有交互操作将无法被透明地移送至备用服务器上,除非该服务器时刻与主服务器同步全部用户的状态信息。

  11.  

  12. 但是如果想获得更好的伸缩性,就需要尽量将“有状态”的处理机制改造成“无状态”的处理机制。

三、“无状态”化处理

将“有状态”的处理过程改造成“无状态”的,思路比较简单,内容不多。


首先,状态信息前置,丰富入参,将处理需要的数据尽可能都通过上游的客户端放到入参中传过来。



当然,这个方案的弊端也很明显:网络数据包的大小会更大一些。


另外,客户端与服务端的交互中如果涉及到多次交互,则需要来回传递后续服务端处理中所需的数据,以避免需要在服务端暂存。



(橙色请求,绿色响应)


这些改造的目的都是为了尽量少出现类似下面的代码。


func(){    return i++;}
复制代码


而是变成:


func(i){    return i+1;} 
复制代码


要更好的做好这个“无状态”化的工作,依赖于你在架构设计或者项目设计中的合理分层。


尽量将会话状态相关的处理上浮到最前面的层,因为只有最前面的层才与系统使用者接触,如此一来,其它的下层就可以将“无状态”作为一个普遍性的标准去做。


与此同时,由于会话状态集中在最前面的层,所以哪怕真的状态丢失了,重建状态的成本相对也小很多。


比如三层架构的话,保证 BLL 和 DAL 都不要有状态,代码的可维护性大大提高。


如果是分布式系统的话,保证那些被服务化的程序都不要有状态。除了能提高可维护性,也大大有利于做灰度发布、A/B 测试。


题外话:在这里,提到做分层的目的是为了说明,只有将 IO 密集型程序和 CPU 密集型程序分离,才是通往“无状态”真正的出路。一旦分离后,CPU 密集型的程序自然就是“无状态”了。


如此也能更好的做“弹性扩容”。因为常见的需要“弹性扩容”的场景一般指的就是 CPU 负荷过大的时候。


最后,如果前面的都不合适,可以将共享存储作为降级预案来运用,如远程缓存、数据库等。然后当状态丢失的时候可以从这些共享存储中恢复。


所以,最理想的状态存放点。要么在最前端,要么在最底层的存储层。


四、总结

任何事物都是有两面性的,正如前面提到的,我们并不是要所有的业务处理都改造成“无状态”,而只是挑其中的一部分。最终还是看“价值”,看“性价比”。


比如,将一个以“状态”为核心的即时聊天工具的所有处理过程都改造成“无状态”的,就有点得不偿失了。


2019-01-24 09:307517

评论 3 条评论

发布
用户头像
那像flink这样的有状态的流式计算,是不是就是 io密集和cpu密集没有分开呀
2019-09-30 22:29
回复
用户头像
写的很好,不知道什么时候能出下一期?
2019-04-16 21:18
回复
用户头像
学习了
2019-03-05 08:50
回复
没有更多了
发现更多内容

FL Studio21最新版编曲DJ舞曲制作软件

茶色酒

FL Studio FL Studio 21

精选2022年大厂高频Java面试真题集锦(含答案),面试一路开挂

程序知音

java面试 大厂面试 java架构 后端技术 Java面试八股文

有限状态机

芯动大师

Verilog 11月月更 Melay FSM

2022年华为Java面经,还没搞懂JVM

钟奕礼

Java 程序员 Java 面试 java编程

如何召回流失用户

穿过生命散发芬芳

11月月更 流失召回

赞不绝口!仅靠阿里P9分享的 Redis 工作手册,拿到60W年薪Offer

程序知音

Java 数据库 redis 后端技术 Redis 6.0

CorelDraw2023主要功能特性

茶色酒

CorelDraw2023 CorelDraw

Camtasia2023免费电脑录屏视频软件使用教程

茶色酒

Camtasia Camtasia2023

ABBYY FineReader16最新版PDF编辑器功能介绍

茶色酒

abbyy

算法题学习---链表的奇偶重排

桑榆

算法题 11月月更

8年Java开发含泪刷题,架构岗现在好难进,有点崩溃

钟奕礼

Java 程序员 java面试 java编程

CleanMyMac2023Mac系统电脑磁盘优化软件

茶色酒

CleanMyMac CleanMyMac2023

LeetCode题解:783. 二叉搜索树节点最小距离,栈,JavaScript,详细注释

Lee Chen

JavaScript 算法 LeetCode

架构实战营模块 5 作业

陌生流云

架构实战营

亿级万物互联新时代的物联网消息中间件EMQX调研

宋小生

物联网 mqtt emqx

Scrum Patterns:产品的自豪感(Product Pride)

Bruce Talk

Scrum 敏捷 Agile Scrum Patterns

一篇文章彻底理解 HDFS 的安全模式

明哥的IT随笔

hadoop hdfs

聊聊香港优才-续篇(58/100)

hackstoic

香港优才

霸榜巨作!阿里内部顶级大佬整理(Redis 5设计与源码分析)

钟奕礼

Java 程序员 java面试 java编程

架构误区系列5:滥用分布式锁

agnostic

分布式锁

GitHub标星75k,阿里15W字的Spring高级文档(全彩版),真的太香了

程序知音

Java spring ssm java架构 后端技术

这20道微服务面试题,阿里、字节、美团、百度面试都问了

钟奕礼

Java 程序员 java面试 java编程

OSPF路由协议三

初学者

网络 11月月更

云原生系列 二【轻松入门容器基础操作】

叶秋学长

云原生 华为云 沙箱实验 11月月更

网络核心笔记(二)

lxmoe

学习笔记 网络 11月月更

Redis分布式锁剖析和几种客户端的实现

C++后台开发

redis 分布式 后端开发 C++开发

API渗透测试4个关键步骤

阿泽🧸

11月月更 API渗透测试

阿里、百度、美团、面试题大集合,愿你更轻松拿下大厂offer

钟奕礼

Java java面试 java编程 程序员、

2022成功入职阿里:阿里的三套Java研发岗面试题总结(文末有答案)

钟奕礼

Java java面试 java编程 程序员、

三到五年互联网公司Java面试题大全

钟奕礼

Java 程序员 java面试 java编程

网络核心笔记(一)

lxmoe

学习笔记 网络 11月月更

分布式系统关注点——“无状态”详解_后端_张帆_InfoQ精选文章