Serverless在微店节点领域的探索与应用服务端接口交付方案,使用该方案和提供的系统,可以生成一对包含运行环境定义的项目代码,可以立即运行。最后通过“无服务器平台”实现生成代码的部署、CI、运行、逆向。代理、进程守卫、日志上报、进程组扩展等功能。这样,产品和运营人员就可以使用这样搭建的接口,配合常用的cms系统,实现“独立”等简单的查询需求。推广活动的开发”,代码的可靠性和稳定性由“无服务器平台”提供保障,有效支持多种业务的快速上线,节省后端开发人员的人力和硬件资源(下)大多数需求,nodejs业务在虚拟机上的资源开销小于java业务)。接口搭建系统这里不解释接口搭建系统的原理和实现,只说明它和“某某serverless”的关系上面提到的“平台”。](https://si.geilicdn.com/viewm...这是系统的全貌,由于信息敏感,省略了一些细节。平台用户可以基于各个功能组件构建一套复杂的业务流程。stage,提供在线调试和日志功能,可用于故障排除;在部署CI阶段,可以集成不同的运行时平台,可以是自己实现的运行时,也可以是第三方云平台;在运行阶段,通过使用agenttool工具实时监控当前服务的性能,可以通过traceId查看各个系统中请求的全貌。serverless方案这一节以资源隔离的粒度为衡量标准,介绍了我对三种serverless方案的选择以及为什么选择隔离度更高的kubeless云平台。基于功能隔离的ParseServer解决方案ParseServer提供了基本的功能:基于类和对象的权限控制、基于文档的nosql存储、简单的用户认证、基于hook的自定义逻辑等,但是经过笔者的考察和论证,在最终没有采用ParseServer等基于单进程下功能隔离的方案。有几个原因:ParseServer方案很重,引入了很多不必要的功能,比如权限控制、鉴权、存储等服务隔离。级别低,一个进程运行多个服务,多个服务会在libuv层相互抢占CPU,影响彼此的业务处理级别。产能扩张困难。基于底层express框架无法实现单个服务的扩展,无法满足运行时需求。接口调用链路的跟踪当多个服务同时引入db、es等不同资源时,或者服务创建的对象足够多时,会存在ParseServer主进程溢出的风险。毕竟64位机器的节点堆内存有1.4GB的上限,虽然这个上限是可以配置的,但是ParserServer发布的接口需要通过它的client来调用,这就需要在公司商业情况满足ParseServer官网基于进程隔离的超级代理方案,为了解决多个服务抢占libuv的问题,选择了自研的超级代理方案。顾名思义,它是一个超级代理,但它不仅仅是一个代理,还是一个功能极简的可靠发布系统和运行时容器;是一个分布式应用,节点之间功能分工明确;它还提供实时调试功能。超级代理是一个多角色的分布式系统。它可以看作是一个节点容器或一个无服务器节点实现。它以流程的粒度管理服务。它分为“协调者”和“参与者”。协调器实现应用CI部署、启动、流程维护和管理以及反向代理功能,参与者实现业务请求代理并接受协调器的调度。在超级代理架构中,端口是区分服务的唯一标识符。该端口对客户端是透明的。这层端口资源的隔离由super-agent来完成,所以多个服务可以避免在libuv层相互交互。竞争,提供横向扩张的可能。反向代理超级代理的核心功能是反向代理。由于每个服务都被封装成一个独立的HTTP应用,拥有独立的端口,当用户请求流量经过前端转发层进入超级代理后,会根据相关规则进行二次转发。目前,它支持基于“路径和端口”转发的规则。部署后端应用部署需要“优雅降级、清除流量、健康检查、应用初始化完成检查、流量导入、所有参与节点的部署状态查询”等步骤,需要妥善处理;同时,协调器负责协调所有参与节点。完成部署操作,属于分布式事务,事务出错后需要做好相关业务补偿。关于流程,上图并没有画出节点角色的区别。实际上,只有参与节点才真正接受用户请求。协调器的流量全部来自于系统内部,包括接受“接口构建系统”调用或者其他系统实现的dashboard服务;同时向参与者发送相关信令信息,如部署、扩容、下线、调试等。参与者流量来自内部系统和外部流量,其中大部分来自外部流量。内部流量携带协调器的信令信息。横向扩展服务横向扩展的重要性不言而喻。在超级代理方案中,协调器负责管理服务的扩展和逻辑分组。这里的服务就是通过服务搭建平台拖拽生成的nodejs代码。它是一个包含复杂业务逻辑的函数,可以是多个文件。具体来说,超级代理将服务包装成一个HTTP服务,并在一个单独的进程中执行。因此,如果要横向扩展服务,可以选择多种策略:默认情况下,每个虚拟机或物理机都有一个服务进程。一般在N台机器和N个服务进程扩容时,默认每台机器fork一个服务进程。N台机器2*N个服务进程为了充分利用资源,可以将每台机器划分为逻辑组,同时可以选择某些组内的机器独立扩容。这些策略对下游应用是透明的,只需要选择相关的策略即可。水平扩展的缺点:每个虚拟机或物理机都有资源上限。一个普通节点进程最多消耗1.4GB内存,计算资源共享。在一个8C16G的虚拟机上,最多可以同时运行16个服务。及时,通过组扩容的方式,每当扩容新的虚拟机或物理机时,超级代理需要根据组信息实现进程守卫,每个服务CI部署也是如此。在运维管理方面,需要配合非常清晰的dashboard后台快速定位问题,这在多业务问题中尤为突出。在线调试超级代理提供消息机制。构建平台中的组件开发人员使用提供的serverless-toolkit工具调试相关逻辑,最终可以在超级代理的协调器后台查看实时调试结果。综上所述,super-agent是一种常规的基于业务流程隔离的解决方案。它有效地支持了微店的多项活动和产品。虽然峰值QPS不高(100左右),但也体现了超级代理的稳定性能和可靠性(不意外上线、不重启服务、平滑升级)。但是super-agent还存在几个问题,这让我们不得不另辟蹊径:日常运维难度大,需要开发一系列后台系统辅助运维,需要大量人力费用。这是一个典型的多机应用场景,当部署超级代理时,其上运行的服务会受到影响(重启)。虽然这种影响不影响用户访问(此时流量已经去除),但仍然是一个风险点。横向扩展的实现比较麻烦。基于内核命名空间隔离的kubeless解决方案是最彻底的隔离解决方案。kubeless是构建在K8s之上的serverless框架,因此使用K8s可以实现一些非常有用的特性:敏捷构建——可以根据用户提交的源代码快速构建可执行的功能,简化部署流程;灵活的触发——可以很容易地触发基于各种事件的功能的执行,并且可以方便快捷地集成新的事件源;自动伸缩-无需人工干预,可根据业务需求自动扩缩容。其中,自动伸缩解决了超级代理的痛点。在kubeless中有两个概念和我们息息相关:“函数和运行时”。功能是一个通用术语,包括运行时代码、依赖项和其他配置文件;runtime定义了运行时依赖的环境,是一个docker镜像。接入kubeless平台需要解决以下问题:开发自定义runtime满足商业需求,如trace、日志分片、上报、采集自定义构建镜像,实现基于yaml函数的ts编译、更新、删除进程探索,自动功能部署,包括流量移除,流量导入,业务健康检查中间件日志,业务日志,跟踪日志隔离和挂载功能运行时用户权限问题级别扩展探索和尝试资源申请规范规范和部署规范协议因此,前进的道路依然曲折,很多需求需要从源码中寻找解决方案。在kubeless实现的serverless系统中,function所在的pod中的所有容器共享网络和storagenamespace,但是默认的外网无法访问k8s集群的所有pod,所以需要一层proxy来实现请求转发,即“服务”。Service负责服务发现和转发(iptables第4层)。因此,在Kubeless或者K8s中,不会直接通过podIP访问service,而是通过Service转发四层流量。服务具有由K8s分配的cluserIp。clusterIp是集群内部的虚拟IP,外部无法寻址。相反,Kube-Proxy在容器网络之上抽象了一层虚拟网络。Kube-Proxy负责Service的路由和转发(关于kube-proxy的详细信息,请参见参考资料)。Service后端对应一个或多个pod,这些pod中的一个容器运行着相同的业务代码。那么流量是如何路由到Service的呢?这里涉及到Service的“发布”,常用的是Ingress。Ingress包括一个HTTP代理服务器和一个入口控制器。代理服务器负责根据规则将请求路由到相应的Service。该层需要Kube-Proxy来实现虚拟网络路由;入口控制器负责从K8sAPI中拉取最新的HTTP匹配规则。](https://si.geilicdn.com/viewm...解决自定义镜像问题:这里的镜像包括构建镜像和运行时镜像两部分。运行时镜像需要解决宿主代码的健壮性,提供livenessProbe、readinessProbe、metric接口实现;镜像构建负责构建阶段的操作,如编译、依赖安装、环境变量注入等。具体写法参考implementruntimeimages)。构建镜像参考1关于函数的CRUD操作,笔者先通过命令行走完了整个过程,然后切换到一个基于yaml的配置文件开始。使用yaml启动的优点是:a、可以使用kubeless自带的流量导入和移除策略b、简单的水平扩展c、简单的命令d、模板化配置文件、自动化部署策略。由于业务特点,需要挂载日志,这里不再详述。否则,一旦pod重启,容器中的所有日志都会丢失。虽然会有日志采集操作,但是大部分日志采集过程都是异步进行的,所以会出现日志丢失的情况。因此,必须通过挂载volume的方式将文件映射到K8s节点上。但是在这个过程中,会出现权限问题。这说明下一点的权限问题是kubeless设置了函数的执行权限为非root。这是一个安全和常识性的设置,但有些功能需要root权限,这就需要修改K8s的安全上下文配置,以及基于K8sHPA组件的水平扩展需要慎重处理。目前支持根据CPU、QPS等指标进行扩容。笔者没有专门测试这个内容,因为它足够可靠。资源申请的指定需要符合各公司的实际情况和业务特点。以node技术栈为例,pod中每个容器1C2GB的内存设置是符合实际情况的;在部署规范上,需要结合运行时容器的特点,合理配置K8s节点、pod、function的对应关系。总结一下kubeless中运行的函数和super-agent中运行的代码,不过可以准备一下周边的环境。大不相同。为了让kubeless中的功能能够访问到公司内部的中间件服务,笔者费了一番功夫,主要集中在日志和采集部分。幸运的是,解决方案总是比失败多。进展目前,超级代理方案已承载10+在线应用或活动,已稳定运行4个月,资源使用率符合预期;kubeless方案目前还没有正式接入流量,等待进一步的异常测试。参考kubeless介绍security-contextkube-proxy)
