之前我读到一篇文章里面的一个概念我觉得和服务器架构的发展非常符合:
服务器的发展以规模化、集群化为导向。(多个服务器资源整合为逻辑上的一个资源池)
云服务架构发展以提高资源利用率为导向。(一个资源池中存在多个不同的有效资源消耗者)
下面我写一下我对于云服务的发展的理解,和出现Serverless架构的各种基础和前提。
这里我定义一下效益资源利用率的概念,效益资源利用率是指资源产生效益的时间比上资源从分配到结束的时间,效益资源利用率越大说明所浪费的时间资源越少。
云服务发展
无云时代
在无云时代,用户需要自己购买服务器物理机,自己搭建机房,自己维护服务器硬件,同时需要根据业务量、峰值计算存储资源的增涨扩容或添置服务器,这样的模式让企业自己承担经济、安全等风险,同时企业需要配置专业的运维团队对整个服务器集群进行管理。但从实际来讲,比如一个电商网站,大部分时间服务器资源占用其实不是很高,只有在特定的时间和场景下才会出现流量激增的情况,而企业在无云时代则需要以这个峰值来配备服务器,造成服务器资源大部分时间处于闲置状态,没有为企业带来效益。
有云时代
下面开始进入云服务时代,云服务的本质就是向云提供商购买其数据中心池化物理资源的使用权,这里的资源不仅限于服务器计算资源,还包括网络虚拟化、存储虚拟化等。在虚拟化平台上,可以将计算资源(即虚拟CPU、GPU等计算组件及内存)、存储资源(即硬盘)、网络资源(即服务器上下行带宽及所属NAT网络等)看成三个互相独立的资源。以我可以接触到的例子就是Vmware vCenter中可以将某台虚拟机的计算资源从一台服务器迁移到另一台服务器,同时存储资源可以在非Vmware系统下的群辉等文件服务器上(企业架构应该是SFP光网 10Gbps以上相连的企业内部网络和存储资源服务器)。同时这种池化资源的模式可以非常容易的进行资源扩容,甚至是在虚拟机运行时将计算资源从一个资源池迁移到另一个资源池,或者实现HA(从我接触到的来说就是Vmware的vMotion,但我的硬盘和内部交换机比较垃圾,这种模式的资源分配会导致硬盘读写延迟很高就没有试过了)。
IaaS
云服务的发展从最开始的IaaS基础设施即服务,用户需要向云服务商购买Infrastructure,实际上这里的基础设施指的是一台在云提供商数据中心虚拟化平台的资源池中虚拟化出来的一台虚拟机(BareMetal另说)。因为该服务器是虚拟机,因此可随时向虚拟化平台申请资源,而这个申请资源的过程我们就称为扩容,而这种模式我们就称为弹性计算(ElasticComputing)。在IaaS模式下,企业虽然仍然需要维护服务器,但已经将硬件维护分离了出来,这一部分精力和资源将会用于业务逻辑的开发,提高了企业的效率和效益。
IaaS模式的效益资源利用率不是很高。首先因为IaaS模式从逻辑上来讲提供商就是把一台配置好硬件和网络的机器租给用户,因此你需要从零开始配置系统和开发运行所需要的的环境,这种模式从用户大部分情况都是长期保有该云服务器,因为每次释放后都需要重新进行配置环境。而这样的模式服务器大部分时间都可能处于低资源使用率,有大部分资源都没有被有效利用,因此这种方法的效益资源利用率不是很高。
PaaS
第二个阶段是PaaS即平台即服务,这个Platform不是很好理解,其实如果比较熟悉.Net、PHP、Python、Java和Node.js这种你需要将一个软件安装到系统上才可以运行的框架(Runtime),那就比较好理解。可以看成Cloud Provider提供了一个配置好这些运行时的服务器给你使用,你就不需要再去维护硬件、操作系统和运行时了。同时这种模式将部署这部分流程交给了云提供商,因此云提供商可以通过将这部分服务和其他云服务资源整合提供更加完备的全开发流程服务,例如持续集成、自动测试、性能预警、安全审计等方面。因此我认为从PaaS开始云服务的效能才真正与实际的软件开发者想关联。IaaS更多的是与运维人员相关。从PaaS开始,开发者可以将大部分项目前期的搭建复杂度和消耗的资源全部转移到云服务上,大大提高项目启动的效率并缩短写Demo验证技术可行性的时间。同时还可以享受云服务提供商专业的运维工具和自动化运维监控平台。
同时PaaS按量付费的模式提高了效益资源利用率。
PaaS对于资源的使用效率就高了很多,在IaaS阶段,在用户购买云服务器后需要进行大量的配置,如果该服务器具有短期使用的特点,那么在每个周期都需要重新对云服务器进行重新配置,而这些配置行为其实大部分都是在对业务代码的运行时和相关依赖进行配置。而PaaS则将配置做为预设提供给用户,甚至可以直接定义一种资源配置语言,通过某种格式定义好整个应用从网络、数据库到存储和计算资源的几乎所有云资源,因此将部署效率也提高到了一个新台阶。
从PaaS开始我认为具有的最大特点就是真正可以Painless的进行云资源的快速部署和释放,因为大部分配置都作为了一种预设或者可以通过云资源配置语言进行预先设计好,只需要向某个API发送一条命令或者页面上的按钮点击一下就可以快速在云端拉起一个运行环境。而这种环境可以分为线上环境和开发测试环境,对于开发测试环境来说因为可以快速拉起服务,因此在闲置的时候可以直接将资源释放降低成本,而后在需要的时候进行快速拉起。也从一定程度上节约了企业成本。
但PaaS也有一些缺点例如不同云服务提供商所提供的运行时版本不同,大部分就只有几个比较稳定的版本,同时同时这些版本提供策略都不是很激进,有些甚至是几年前的版本,因此打算使用PaaS类型的服务就需要注意CloudProvider提供的运行时版本。
还有一个对于企业来说比较重要的就是PaaS包含了中间件,因此可以很方便的部署分布式应用,但我没有详细的了解过中间件和微服务设计和通讯,因此就跳过了。但FaaS有很多设计模式和规则都是继承自微服务设计理念。
对我来说,我最开始使用的云服务时阿里云的ECS,而后面也没有过多的了解过PaaS,在前几年也就尝试着搭建了下Wordpress,但后来自己有服务器之后也没有使用云服务搭建WP了。我最近使用PaaS类型的服务是云函数服务,从某种意义上来说这也算一种PaaS,但是将原PaaS应用分割为的云原生的模式,即所有的组件,逻辑都是以上云为目标,设计之初就以最大化利用云服务的便利性为目的。
当然PaaS的底层也可能是IaaS,而且我认为应该这是一种普遍的架构。
SaaS
SaaS我了解的就不是很多了,因为作为个人开发者来说这种规模的东西就只有企业能做到,SaaS 软件即服务,是指SaaS提供商向企业提供一个单纯的软件入口,企业不需要任何开发人员和维护人员,只需要购买SaaS应用的使用权。SaaS实际就是一种软件租赁服务。
但SaaS仍然可能是以上面的PaaS或者IaaS为基础形成,例如可能SaaS提供商自己开发的软件然后购买PaaS后部署上去,然后作为一种软件服务再租赁出来。
以上三个层次总体是对一个应用从底层硬件到顶层的业务逻辑不断抽象融合的过程,开发者的关注点不断从其他的硬件、环境等关注点转移到业务逻辑上,不断节约企业成本、提高开发效率。
Serverless
Serverless是最近比较火的一个概念,翻译过来是无服务器架构,但以我的理解其实是相当于服务器硬件维护、基础服务架构和弹性扩容作为一种服务,相当于将整个软件从物理层到虚拟机层(这里是我的理解,我把虚拟机层定义为跨物理层为上层软件提供扩容、网络等服务的虚拟层,类似与Vmware ESXi这种虚拟化平台,但拥有低延时扩容资源的能力)。实际上这里的服务器只是对开发者来说不可见,而将这部分的维护、扩容等任务都交给了云提供商专业的运维团队,开发者只需要将所有精力都集中在业务领域,不需要花费额外的精力在这些和实际业务领域无关的部分,专注业务逻辑和真正给公司带来绩效的代码部分,大幅提高开发的效率。
有了上面的三个层次的概念基础,我们现在来看看Serverless的架构,首先Serverless是一种云原生的架构,即以某几个云提供商的云环境做为运行环境,举一个栗子(这里我就直接使用FaaS架构了,后面再解释FaaS的概念),当然由于我的技术广度有限因此这个架构并不是最好的架构,甚至是一种BadPractice,但作为一种体现Serverless架构在云端上分配各种资源的案例还是可以的:
现在有一个初创公司经营一个购物网站,这个网站拥有三个用户角色:买家、卖家、网站管理员。因此我需要针对三个不同的角色提供不同的服务。首先买家我只提供一个APP软件进行商品浏览、购买、售后等。卖家提供手机和电脑端双端,网站管理员提供数据大屏、电脑端两种服务。这个网站的平时访问量不是很高,只有在节假日和活动期间拥有较大流量。同时网站拥有类似于抢红包的功能。网站拥有大量的图片数据。
以我比较熟悉的云提供商阿里云为例:
1.数据
这里我们使用阿里云的RDS Mysql作为主要的存储数据库,所有的数据都存储在一个Mysql服务器集群中,并开启数据备份(每天3点左右进行一次数据备份)。
然后使用Redis集群作为数据缓存服务器,所有的在线信息、排行榜、高频访问商品信息及红包等热数据都存储在Redis中。
消息队列使用RabbitMQ,实现抢红包之类的高并发请求实现流量削峰。
2.业务代码
业务代码我们使用云函数的方式构建,将每一个相对独立的模块都抽象编写为云函数,例如商家提供的商品视频就会被VideoUploader云函数存储到OSS中,然后push一个转码任务到转码队列中,而转码队列的消费者Transcode云函数则会被启动然后开始进行转码服务,并将转码结果存储到OSS中。而VideoUploader和Transcode都是并行启动多个云函数实例的函数模板,因此可以非常方便的进行Auto-Scale。
大部分生产环境下由于云函数冷启动的问题,因此推荐函数代码包大小越小越好,同时可以保有一到两个云函数实例不释放,对于低频API的响应效率提高是非常有用的。
3. API网关
API网关作为一个对内部API的整合平台使用,将后端多种不同服务的API统一到一个域名下的不同API接口上。例如存在一些老旧的服务必须要从公司的服务器上调用,这里就可以使用API网关作为一个代理服务使用,将对应API绑定到统一域名下的一个API上然后代理到公司服务器上。同时API网关也可以绑定其他云服务,但我最常用的还是在API网关上直接绑定云函数。
API网关还有一个功能可以提供一些校验服务,比如我在使用的Serverless架构的校验模式就是使用JWT校验,因为阿里云在API网关提供JWT校验插件,可以直接通过API过滤掉一些没有权限的请求。
4. CDN
这个配置不是很复杂,对于一个图片、视频比较多的网站CDN是一个非常必要的服务。CDN设置我只用过比较基础的(不会优化),就不丢人现眼了。
架构简图
下面是一个简单的图示,不是很标准,但还是可以将整个应用架构表现出来:
这里我还加了一些可能使用的云服务,例如Kubernetes集群跑微服务,裸金属服务上跑的一些大规模计算业务。
订单处理函数将订单信息确认库存校验信息后就将订单放到Redis中并15mins删除然后返回订单编号和变更的状态信息。然后用户请求付款就会调用付款请求处理函数,付款请求处理函数再去获取第三方支付服务提供商的API完成具体的操作(我没有接入过支付服务,对这方面没有了解)。
Serverless概念分解
首先我们看一下这个单词:Serverless,这个单词由两部分组成,第一部分是Server即服务器,第二部分less修饰第一部分,表示没有或者不需要服务器,这里的不需要实际上是对开发者而言是不需要,相当于将这部分的运维和控制权完全交给了云提供商,开发者把硬件和服务器维护当成一种服务来租用,一个现实生活的例子就是共享单车,共享单车提供商将这种单车租赁当成一种服务,且可以按需付款,用户只需要付使用共享单车时长所产生的费用,对于不需要长期使用的用户来说是非常有用的。在没有上云的时候就相当于开发者需要自己购买自行车,自己维修自行车,自己保证自行车各个部件的安全性。而在Serverless模式下,单车由共享单车提供商进行购买和维护,用户只需要租赁使用就可以了,这种模式对于新兴公司非常友好。
如果以XaaS来说Serverless就是Backend as A Service,后端作为一种服务。简单理解就是Serverless将硬件、操作系统、运行时都交给Cloud Provider维护,而用户只需要直接使用云提供商提供的各种软件架构上的基础设施比如队列、对象存储、云数据库、Auth、云函数等。
总结一下就是Serverless架构拥有通过将开发者焦点集中在业务逻辑提高开发效率、最大资源利用率的特点,同时我认为这是未来的一种发展趋势。
Serverless优点
Serverless模式对于大部分应用来说都可以非常平滑的进行过渡,因为可以将原来老旧API通过API网关聚合为一个统一的访问接口,而新的API则可以不断的通过云函数、API代理等方式完成添加,因此从传统应用完全转变为Serverless模式的成本虽然很大,但从现在开始将未来的所有新增模块以Serverless模式进行规划是非常简单的。
Serverless模式拥有按量付费的特点,这种模式对于大部分应用来说都可以节省大部分云资源占用造成的开支,具体的例子上面已经讲过这里就不赘述了。
Serverless模式可以将开发者焦点最大限度转移到业务逻辑上,因为开发者不需要管理硬件、操作系统、环境等方面的配置,只需要将业务逻辑部分的代码上传到云提供商对应的服务上。
Serverless模式可以降低错误检查逻辑的复杂度,这部分主要针对的是云函数等幂性在Serverless架构带来的优点。
Serverless缺点
Serverless模式也不是任何情况都适用,Serverless模式由于所有的服务都需要上云如果一些安全性要求比较高的应用就无法使用Serverless模式,毕竟谁也不希望将数据放到自己无法管控的硬件上,同时由于一个Serverless架构应用和厂商有巨大的绑定性,每个厂商提供的同种类服务可能会有API和版本删改的巨大差异,因此如果想将应用从一个云提供商迁移到另一个云提供商上就需要花费精力将整个Serverless架构修改为新提供商所提供服务构成的架构,因此一开始选择云提供商需要谨慎,否则后期迁移会非常痛苦。
Serverless还有一个问题就是无法满足高实时性需求,由于Serverless模式中各个模块都是分解为了不同的云服务,即使在云提供商同地区的同数据中心,不同服务之间的数据交换也会有延时和抖动,因此Serverless模式不适合高实时性要求的应用。
Serverless模式由于高度依赖云提供商的服务,因此大部分数据库和运行时都需要使用云提供商内置的版本,而大部分云提供商对于这类框架、服务、数据库版本的更新策略都比较保守,因此在选择云提供商时需要将这部分因素考虑进去。
Serverless核心服务FaaS
说到Serverless就不得不提FaaS即Function as A Service函数即服务,FaaS模型为Serverless架构中业务逻辑代码提供了非常完美的载体,FaaS中开发者可以根据单一职责原则,将整个应用拆分为一个个相对独立的函数(云函数),每个函数可以进行单独开发和迭代,而FaaS模型下的函数大部分为事件驱动型函数,即接收的参数为触发该函数的事件,因此如果需要创建一个订单则需要一个订单创建事件触发订单创建云函数。
云函数设计原则
1.云函数均为Stateless函数,即函数内部不存储任何状态数据的纯函数,这样每一个云函数就可以在需要的时候拉起多个实例而不需要的时候直接将闲置的实例销毁,这种短生命周期的实例搭配按量付费模式可以大幅度降低企业在低业务量下的资源占用开销。这也是云函数最大的优点。但云函数可以通过外部缓存例如Redis、Queue等云数据服务来面向整个云函数实例群体缓存数据。
而Stateless设计也可以保证函数具备进行Auto-Scale的能力,而不需要依赖任何内部状态。
云函数实例从空闲再到销毁这段时间根据不同云提供商的策略而有所不同,但如果不进行特殊配置(长期保有1~2个函数实例)大部分云提供商都不能保证空闲函数实例的保留的具体时长,这也是为什么在FaaS模型下需要重点注意冷启动时长,因为这是云函数模型下对于效率、经济等方面具有最大影响的变量。
2.云函数需满足幂性原则。等幂性原则要求”同一个请求“只会的到同样的输出,,因此如果客户端发现某一个请求发生错误,只需要重新将请求发送一次即可,多次尝试直至超过重试次数或成功,这样的方法降低了客户端错误校验逻辑的复杂度,减轻客户端负担。
3.保证应用业务分割得当,由于使用云函数需要对传统应用业务逻辑进行分割,因此这个分割的细粒度就需要进行精确的把控,不能一个云函数包含非常大的模块也不能让云函数仅包含业务逻辑上的一个单独的函数,而是需要对云函数的范围进行一个比较适当的细粒度确定和划分。这里这个细粒度就需要开发者根据业务逻辑而适当掌控了。
4.云函数及其依赖应尽量减小体积,云函数在云提供商上运行的实质是拉起一个个运行用户代码的容器实例,而拉起的过程需要一定时间,这段从云函数实例开始拉起到实例可用的时间被称为冷启动时长,这也是云函数性能优化的重点。而冷启动最直接的优化方法就是缩减云函数代码包(在部署云函数时上传的代码包Deployment Artifact)的大小,越小的代码包则云函数拉起容器实例初始阶段从云存储服务上加载代码包的时间也越短,而我们也很清楚这种大IO是最占时间的操作。在我的测试下阿里云云函数在代码包30MB左右时拉起时间约为200ms(但我测试的函数仅包含Prisma ORM Mysql引擎和GraphQL Appollo Server代码)。
5.云函数应尽量减少同步依赖(Synchronous Dependencies),这里的同步依赖值需要将函数执行阻塞的API调用,云函数需要被阻塞在该API调用逻辑处而后等待响应或超时,而云函数费用计算主要和时间挂钩,因此这样的同步依赖过多会导致云函数会产生非常多额外的开销。同时对于响应效率也是非常大的降低。需要非常多同步依赖的业务逻辑不应当使用云函数模式实现,而是通过其他云服务,例如容器服务(Kubernetes)、弹性计算服务等实现。
6.云函数可以链式触发,即一个云函数可以触发多个云函数执行。由于每一个云函数都负责单一的职责,因此一个Workflow可能被分割为多个云函数,而这个Workflow则可以通过云函数内部触发或者云提供商的其他Workflow工具链式触发。
7.云函数设计应注意其计算资源占用量。由于云函数实例创建之初云提供商会根据用户设置的Memory Limit和CPU Limit限制其资源占用,因此需要预先对云函数资源占用进行测试,否则可能导致云函数启动时没有足够的资源而无法使用,客户端不断重试时创建新的函数实例而进入一个死循环,导致非常多的不可用函数实例创建出来。
云函数优缺点
云函数作为Serverless架构中最为核心的部分,为业务代码提供了最为合适的云环境载体,同时云函数在经济性方面相对于IaaS、PaaS来说提升是非常明显的,使用云函数运行业务代码的效益资源利用率非常高,用户只需要付真正产生效益的资源占用费用。同时由于云函数以独立的业务逻辑代码为单位,因此可以在不影响其他云函数的前提下非常简单高效的进行迭代和回滚,为快速迭代流程提供了良好的架构基础。
但云函数也有一些缺点,例如云函数的冷启动和同步依赖导致这种模型不适合高实时性的应用,同时不同云提供商内置的云函数运行时有一定差异,在编写代码时就需要考虑这些问题,(虽然现在很多云提供商提供了自定义运行时(自定义容器镜像))。
本文对Serverless架构发展历程和实际案例作出了简单描述,但由于作者能力精力有限,难免会有错漏,因此如果读者发现有我理解错误或文字错漏的地方请在评论区反馈。
v1.0 wep Serverless架构简述及简单案例