写点什么

Serverless 架构中的无状态性指的是什么?

2020 年 5 月 29 日

Serverless 架构中的无状态性指的是什么?

每个接触过 Serverless 的人应该都听过这样一句话:“Serverless 是无状态的。”顾名思义,无状态就是没有状态,我们无法使用它来保存状态,用完即销毁。那么,在 Serverless 架构下(这里特指 FaaS 平台),函数的前一次运行和这一次运行,不会有联系呢?前一次运行的结果也不会影响这一次呢?


函数的无状态探索

首先,需要明确的是 Serverless 的关键特征:运行成本更低、自动扩缩容、事件驱动、无状态性。其中,无状态性是说开发者可以直接将服务业务逻辑代码部署,运行在第三方提供的无状态计算容器中。


那么,前一次运行情况是否会影响这一次呢?准确来说,只有在容器没有被复用的情况下是这样的。但是在实际的项目中,为了降低冷启动率,提高瞬时产生的高并发应对能力,往往会采用容器复用,而这可能会让“无状态性“变得比较复杂。


我们以腾讯云的 SCF 为例,在控制台创建一个函数,使用以下的代码测试一下具体情况:


# -*- coding: utf8 -*-import jsondef main_handler(event, context):    print("Test")    return("Hello World")
复制代码



我们可以看到,通过点击测试按钮,输出了日志:Test,接下来,多次点击:




可以看到,随着我们点击测试按钮,每次都在日志准确输出了Test。接下来,我们变换一下代码:


# -*- coding: utf8 -*-import jsonprint("Not in main_handler")def main_handler(event, context):    print("Test")    return("Hello World")
复制代码


同样的方法,连续点击三次测试,并且记录结果:





通过这一组测试,我们发现,这三个结果有点不太一样:只有第一次请求的时候,执行了这条语句:


print("Not in main_handler")
复制代码


为什么后几次都没有执行这条语句呢?是没执行到这里?还是因为容器复用的原因,在接下来的几次跳过了这个步骤?为什么会跳过这个步骤?为了搞清楚具体情况,我们再来做个测试:


# -*- coding: utf8 -*-import jsonprint("此处给tempNumber赋值")tempNumber = 100def main_handler(event, context):    print("temp number: ", tempNumber)    return("Hello World")
复制代码





可以看到,在第一次测试的时候,这个程序先执行了:


print("此处给tempNumber赋值")tempNumber = 100
复制代码


执行完成之后,tempNumber这个变量就会存在,在接下来的几次调用中,都直接取了这个值。



也就是说,函数在复用容器的情况下被执行(或者说是被触发),实际上可以认为是已经有一个进程被启动,每次触发是通过这个进程来调用入口方法,所以在方法之外的各种操作,实际上是冷启动的时候,在启动进程时会被执行。


因此,函数的无状态性并不是前一次操作对后一次被触发没有影响。那么,所谓的无状态到底指的是什么呢?


在 CNCF 发布的 Serverlss 白皮书中,是这样描述的:Serverless 架构通常是无状态、不可变和短暂的。每个函数都以指定的角色和明确定义有限的资源访问权限运行。什么样的程序或者服务适合 Serverless 架构?白皮书中是这样表述的:无状态,短暂的,对瞬间冷启动时间没有过多需求的程序适合使用 Serverless 架构。


所以,函数的无状态实际上可以认为是:函数是运行在第三方提供的无状态计算容器中的,并且在容器无复用、存在冷启动的情况下,函数可以认为是无状态;由于各个厂商的容器降低冷启动方案是不同的,容器复用方案也都是未公开的,所以什么时候可能会复用容器,怎么复用也是未知的,这就要求我们函数的功能本身要保证是无状态的。例如,在函数中,保存某些数据到缓存中,下次触发的时候从缓存中获得对应内容就是容易产生异常的操作,因为云厂商无法保证这次请求是否复用了已有容器,以及复用的已有容器是否就是上次进行缓存的容器。


拓展

根据上面讨论的内容,我们可以进行一些实践化的应用:


1. 通过容器复用,完成初始化操作


刚刚说过了,如果在容器复用的前提下,在函数外面执行的内容是可以直接使用的,所以我们实际上是可以在外层进行一些初始化的,例如:



以上图的代码为例,通过这样的初始化,就不用每次调用函数都进行一次数据库的初始化/链接等,而是可以复用已有的链接。如果是在 main_handler 中进行数据库的初始化/链接,会影响函数性能,在高并发的情况下更容易把数据库的链接打满,造成恶劣影响。


2. 小心容器复用,不要掉进坑里


我之前写过一个 SCF 打包 Python 依赖的小工具,运行在 SCF 中,测试的时候是好好的,但是项目上线之后,我发现了一个问题:只有冷启动的情况下,依赖是可以被打包的,如果出现容器复用的情况,就会出现依赖打包失败的问题。


经过仔细排查才发现,原来是因为一个对象在使用完成之后未被清理,由于容器是被复用,或者说是“这个对象也被复用了”,在执行指定方法的时候,看到对象已存在,就会直接用这个对象,导致本次函数的触发使用了上次残留的对象,发生异常。


所以说,当程序在云函数中连续执行多次的时候,开始成功后来失败,很可能就是由于某些资源复用,导致程序出错。


3. 我就想要一种状态


有的人在使用云函数的时候,可能真的需要有一种状态来记录某些事情,例如博客系统判断管理员用户是否登录,本来可以直接放到缓存中的操作,此时不能放进去,那应该怎么处理,如何记录管理员是否已经登陆了后台,或者说如何确定这个用户是否为管理员?


这种情况是很常见的,我们可以融合两套方案:


  • 方案 1: 采用 Token 机制

  • 方案 2: 采用缓存机制


所谓的采用 Token 机制和缓存机制融合方案,就是在管理员用户登陆之后,会生成一个 Token,这个 Token 就记录到数据库中,同时这个 Token 也会被写到缓存中。当用户请求发起后,函数会先尝试在缓存中获取结果,如果没获取到,就连接数据库进行获取。


总结

Serverless 架构可以被看成是一个新的技术,一种新的框架,很多时候,我们不能用已有的态度去衡量新鲜事物。同样,一个特性也很难直接用好坏去形容,就无状态性来说,真的是有几种钟爱,就有几种迷茫。


作者介绍:


刘宇,腾讯 Serverless 团队后台研发工程师。毕业于浙江大学,硕士研究生学历,曾在滴滴出行、腾讯科技做产品经理,本科开始有自主创业经历,是 Anycodes 在线编程的负责人(该软件累计下载量超 100 万次)。目前投身于 Serverless 架构研发,著书《Serverless 架构:从原理、设计到项目实战》,参与开发和维护多个 Serverless 组件,是活跃的 Serverless Framework 的贡献者,也曾多次公开演讲和分享 Serverless 相关技术与经验,致力于 Serverless 的落地与项目上云。


2020 年 5 月 29 日 08:463749

评论 1 条评论

发布
用户头像
干货,有用!
2020 年 05 月 29 日 18:53
回复
没有更多了
发现更多内容

5年Java高工经验,我是如何成功拿下滴滴D7Offer的?

Java架构追梦

Java 学习 架构 面试 滴滴

Locust快速上手指南

行者AI

《迅雷链精品课》第十三课:PBFT算法

迅雷链

区块链

软件测试中需要使用的工具

测试人生路

软件测试

得物App亮相QCon全球软件开发大会,分享百倍增长背后的技术力量

得物技术

效率 技术 得物 得物技术 Qcon

LeetCode题解:42. 接雨水,动态规划,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

小程序市场的「App Store」来了!你准备好吃“螃蟹”了吗?

蚂蚁集团移动开发平台 mPaaS

小程序生态 mPaaS appstore

高光时刻!美团推出Spring源码进阶宝典:脑图+视频+文档

996小迁

spring 源码 架构 笔记

半个多月时间4面阿里,已经成功拿下offer,分享一下个人面经

Java成神之路

Java 程序员 架构 面试 编程语言

华为全栈AI技术干货深度解析,解锁企业AI开发“秘籍”

华为云开发者社区

AI 全栈 开发

拼多多五面面经(Java岗),全面涵盖Java基础到高并发级别

Java成神之路

Java 程序员 架构 面试 编程语言

15天成功拿到阿里offer 我是如何逆袭成功?全靠“Java程序员面试笔试通关宝典”真够可以!

比伯

Java 编程 架构 面试 程序人生

jenkins实现接口自动化持续集成(python+pytest+ Allure+git)

行者AI

为什么要在以太坊上构建去中心化缓存层?到底要怎样做呢?

CECBC区块链专委会

以太坊

盘点 2020 |协作,是另外一种常态

Winfield

领域驱动设计 DDD 协作 远程协作 盘点2020

双循环背景下的全球供应链机遇与挑战

CECBC区块链专委会

供应链物流

XDAG技术详解1

老五

【得物技术】如何测试概率性事件-二项分布置信区间

得物技术

测试 开发 概率 得物 得物技术

数字货币交易所系统开发,区块链交易所搭建

薇電13242772558

区块链 数字货币

接口自动化传值处理

行者AI

浅谈 WebRTC 的 Audio 在进入 Encoder 之前的处理流程

阿里云视频云

音视频 WebRTC 音频技术 音频

资深码农:拿下软件测试,只需掌握好这两种方法!

华为云开发者社区

软件 工具 测试

自定义TBE算子入门,不妨从单算子开发开始

华为云开发者社区

算法 算子 自定义

接口自动化测试的实现

行者AI

阿里三面,复盘总结55题:java基础+分布式+网络+架构设计

Java成神之路

Java 程序员 架构 面试 编程语言

腾讯五面、快手三面已拿offer(Java岗位),分享个人面经

Java成神之路

Java 程序员 架构 面试 编程语言

Rust太难?那是你没看到这套Rust语言学习万字指南!

华为云开发者社区

rust 语言 开发语言

普本开发三年,每天两小时面试备战,2个月后五面阿里定级P7

Java架构之路

Java 程序员 架构 面试 编程语言

AOFEX交易所APP系统开发|AOFEX交易所软件开发

开發I852946OIIO

系统开发

如何从危机中提炼总结,做好2020年的复盘?

CECBC区块链专委会

复盘 经济

3面抖音犹如开挂,一周直接拿下offer,全靠这份啃了两个月「Java进阶手册」+[Java面试宝典]

云流

编程 程序员 计算机 java面试

Serverless 架构中的无状态性指的是什么?-InfoQ