目前微店中台团队为了知足公司大部分产品、运营以及部分后端开发人员的尝鲜和试错的需求,提供了一套基于图形化搭建的服务端接口交付方案,利用该方案及提供的系统可生成一副包含运行时环境定义可当即运行的工程代码,最后,经过 “某种serverless平台” 实现生成后代码的部署、CI、运行、反向代理、进程守、日志上报、进程分组扩容等功能。前端
这样,产品和运营人员可基于此种方式搭建的接口配合经常使用的cms系统实现简单查询需求如活动大促的自主“研发”上线,代码的可靠性、稳定性由中台研发侧提供的“某种serverless平台”保障,有效支撑了多个业务快速上线,节省后端开发人员的人力与硬件资源的开销(大多数需求下,nodejs业务对虚拟机的资源开销小于java业务)。java
此处并不讲解接口搭建系统的原理与实现,只说明其与上文提到的 “某种serverless平台” 的关系。node
这是系统的全貌,部分细节因为敏感信息而省略。平台使用方可基于每一个功能组件搭建出一套复杂的业务流,在搭建阶段,提供在线debug和日志功能,可用于排错;在部署CI阶段,可集成不一样的运行时平台,既能够是自主实现的运行时,也但是第三方云平台;在运行阶段,经过使用agentool工具实时监控当前服务的性能,并可经过traceId一览请求在各系统的全貌。git
本节以资源隔离粒度为度量,介绍了我对三种serverless方案的取舍以及最终为什么选择了隔离程度更高的kubeless云平台。github
Parse Server提供了基础功能:基于类与对象的权限控制、基于document的nosql存储、简易的用户身份认证、基于hook的自定义逻辑等,但通过笔者的调查与论证,最终并无采用相似单进程下基于函数隔离的Parse Server及相似方案,这有几点缘由:sql
Parse Server官网docker
为了解决多个服务抢占libuv的问题,我选择了自主研发的 super-agent方案,经过其名称即可知它是一个超级代理,但它不只是代理,仍是一个具备极简功能且可靠的发布系统和运行时容器;它是一个分布式应用,节点间功能划分明确;它同时提供实时调试功能。express
super-agent是一个多角色分布式系统,它便可以看作node容器,也可当作serverless的node实现,它以进程为粒度管理服务。它分为“协调者”和“参与者”,协调者实现 应用CI部署、启动、进程维护与管理和反向代理功能,参与者实现 业务请求代理、接受协调者调度。后端
super-agent最核心的功能在于反向代理。因为每一个服务都被包装成有单独端口的独立HTTP应用,所以当用户请求流量通过前端转发层后进入super-agent,由其根据相关规则作二次转发,目前支持基于 “路径、端口”规则的转发。安全
后端应用部署须要进行 “优雅降级、流量摘除、健康检查、应用初始化完毕检查、流量导入、全部参与节点的部署状态查询” 等步骤,须要妥善处理;同时,协调者负责协调众多参与节点所有完成部署操做,这是一个分布式事务,须要作好事务出错后的相关业务补偿。
上图并未画出节点角色的区别,实际上只有参与者节点才真正接受用户请求。
协调者流量所有来自于内部系统,包括接受 “接口搭建系统”调用或者其余系统实现的dashboard服务;同时其会向参与者发送相关信令信息,如部署、扩容、下线、debug等。
参与者流量来自于内部系统和外部流量,其中大部分来自于外部流量。内部流量则承载协调者的信令信息。
服务的水平扩容重要性不言而喻。super-agent方案中,协调者负责管理服务的扩容与逻辑分组。
此处的服务是经过服务搭建平台经过拖拽生成的nodejs代码,它是一个包含复杂业务逻辑的函数,能够是多文件。具体的,super-agent经过将该服务包装成一个HTTP服务在单独的进程中执行。所以,若是要对服务进行水平扩容,提供多种策略的选择:
这些策略对下游应用透明,只需选择相关策略便可。
水平扩容的缺点:每台虚拟机或物理机资源有上限,一个正常的node进程最多消耗1.4GB内存,计算资源共享,在一台8C16G的虚拟机上,最多可同时运行16个服务。及时经过分组扩容的方式,每当扩展新的虚拟机或物理机,都须要由super-agent根据分组信息实现进程守护,同时每次服务CI部署也一样如此。运维管理上须要配合很是清晰明了的dashboard后台才能快速定位问题,这点在多服务的问题上尤为突出。
super-agent提供消息机制,由搭建平台中组件开发人员使用提供的serverless-toolkit工具debug相关逻辑,最终可在super-agent的协调者后台查看实时debug结果。
super-agent是符合常规的基于业务进程隔离的解决方案,它有效的支撑了微店的几个活动及产品,虽然峰值QPS不高(100左右),但它也论证了super-agent的稳定性及可靠性(线上无事故,服务无重启,平稳升级)。
可是,super-agent仍然存在几个问题,它让咱们不得不另觅他法:
基于kubeless的方案则是隔离最为完全的解决方法,kubeless是创建在K8s之上的serverless框架,所以它能够利用K8s实现一些很是有用的特性:
其中,自动伸缩则解决了 super-agent 的痛点。
kubeless中与咱们紧密相关的有两个概念:“function和runtime” ,function是一个统称,它包括运行时代码、依赖以及其余配置文件;runtime则定义运行时依赖的环境,是一个docker镜像。
若要接入kubeless平台,咱们须要解决以下几个问题:
所以,前进的道路仍然很曲折,并且不少需求须要本身从源码上去寻找解决方法。
kubeless实现的serverless体系中,function所在pod中的全部容器共享网络和存储namespace,可是默认外网是不可访问k8s集群的全部pods,所以须要经过一层代理实现请求的转发,这就是“Service”。Service负责服务发现及转发(iptables四层),所以在Kubeless或者K8s中不会直接经过pod IP来访问服务,而是经过Service转发四层流量完成。Service有K8s分配的cluserIp,clusterIp是集群内部虚拟IP,没法被外部寻址,而是经过Kube-Proxy在容器网络之上又抽象了一层虚拟网络,Kube-Proxy负责Service的路由与转发(关于kube-proxy细节,请看参考资料)。
Service后端对应是一个或多个pods,这些pods中的一个容器则运行相同的业务代码。那么流量是如何路由至Service上来呢?这就涉及到Service的“发布”,经常使用的是Ingress。Ingress包括HTTP代理服务器和ingress controller,代理服务器负责将请求按照规则路由至对应Service,这层须要Kube-Proxy实现虚拟网络的路由;ingress controller负责从K8s API拉取最新的HTTP匹配规则。
运行在kubeless 中的函数和运行在super-agent的代码没有什么不一样,但是周边的环境准备可大大不一样。为了让kubeless中的function能够接入公司内部中间件服务,笔者费了很多功夫,主要集中在日志及收集部分。好在事在人为,解决的办法老是多于失败的方法。
目前,super-agent方案已承载了10+个线上应用或活动,稳定运行4个月,资源使用率符合预期;
kubeless方案还未正式接入流量,等待进一步作相关异常测试。