
作者 | 陈涛(毕衫)来源|阿里巴巴云原生公众号一、天然云原生的 Serverless1. 云原生时代随着 2013 年以 Docker 为代表的容器技术、CNCF 基金会以及 K8s 的发展等,云原生开始被广大开发者所熟知。云原生时代之前还有两个阶段:一是自建 IDC 机房,二是简单地把原有的应用搬迁到云上。自建 IDC 机房很难获得高可用、高可扩展以及运维提效等能力;而第二个阶段就是云计算时代,相比 IDC 有了一定的进步,但大部分还是在相对原始地用云,很难用好云,这个阶段的资源已经接近无限,但是基于虚拟机及各种自建服务的方式还有待改善。云原生时代指的是在设计应用的时候,就考虑到将来应用会运行在云的环境里,充分利用了云资源的优点,比如云服务的弹性、分布式的优势。如上图所示,云原生可以分为几部分:一是云原生技术,包括容器、K8s、微服务、DevOps。而这些技术只是一个工具,要想真正地用好这些技术,还需要一些最佳的实践和组合,也就是云原生架构。云原生架构是基于云原生技术的一种架构原则和设计模式的集合,是一些指导原则,比如要求做好可观测,只有在做好可观测的前提下才能做好后续的弹性,包括高可用相关的建设及基础设施的下沉,希望对非业务代码的部分进行最大化的剥离,在这样的技术和架构设计的指导下,就可以设计出云原生应用。云原生应用具有轻量、敏捷、高度自动化等方面的特点,可以充分发挥云的优势,在现代数字化转型的时代,更好地适应业务的发展变化。2. Serverless 天然云原生为什么说 Serverless 是天然云原生的呢?虽然 Serverless 出现的时间比云原生更早一些,我们向前追溯,AWS 率先推出初代 Serverless 产品——Lambda,其按请求计费和极致伸缩的特点,非常符合云原生的定义,比如基础设施下沉。在 Lambda 里,不需要管理服务器,它会根据请求去伸缩服务器,实现了高度自动化;它还以函数的形式来组织代码,函数相对于应用来说要更轻量,交付速度也更快。但是这种模式的缺点就是改造成本高,因为很多应用原来是一个巨大的单体或者微服务应用,很难改造成函数模式。3. 认识 SAEServerless 理念及相关产品的推出已经走过差不多 7 个年头,在这个过程中云原生的技术也在不断成熟,包括Docker、 K8s 等。阿里云在 2018 年的时候就开始思考另一种 Serverless 形态,即 Serverless application,也就是 SAE 这款产品,其于 18 年 9 月上线,19 年商业化,至今也走过了 3 个年头。SAE 的特点:不可变基础设施、可观测、自动恢复基于 K8s 底座,背后代表的是镜像之类的不可变基础设施以及可观测、自动恢复,如果检测到请求失败,会自动切流或重启实例。免运维、极致弹性、极致成本托管服务器资源,不需要用户自己运维服务器,同时也相应地具备极致弹性和极致成本的能力。易上手、0 改造、一体化如上图,最上层为客户感知层,是 aPaaS 产品形态,是一个应用 PaaS,经过三年多的实践,最终达到让用户真正易上手、0 改造的效果,而且做了很多一体化的集成。SAE 这样一款以 K8s 为底座、具备 Serverless 的特点、以 aPaaS 为形态的产品,完全符合云原生的特点。在技术层面,底层使用容器、K8s,集成了微服务,包括各种 DevOps 工具。在架构层面,因为底层依赖于这些技术,所以可以非常方便地让用户遵照云原生架构的原则,去设计出自己的应用实践,最终让客户的应用可以最大化地享受到云原生的红利,实现应用的轻量、敏捷以及高度自动化,极大地降低迈入云原生时代的门槛。SAE 产品架构图SAE 是一款面向应用的 Serverless PaaS,0 改造 0 门槛 0 容器基础是它的特点,可以让用户非常方便地享受到 Serverless、 K8s 以及微服务带来的技术红利。同时也支持多种微服务框架、多种部署渠道(包括自己产品的 UI 部署 / 云效 / Jenkins / 插件部署等)、多种部署方式(包括 War / Jar / 镜像部署等)。其底层是一个 IaaS 资源层,上面是 K8s 集群,对用户来说这些都是透明的,不需要自己购置服务器,也不需要理解 K8s,再上一层有两个核心能力:一是应用托管,二是微服务治理,应用托管就是应用生命周期等,微服务治理就是服务发现、优雅下线等,这些在 SAE 里都做了较好的集成。SAE 的核心特点可以总结为三个:一个是 0 代码改造,二是 15s 弹性效率,三是 57% 的降本提效。二、SAE 设计理念1. Kubernetes 底座容器在 K8s 容器编排生态中,最基础的是容器或镜像,依托于镜像,用户就相当于实现了不可变的基础设施,其好处是镜像可以到处分发、复制,相当于实现了可移植性,没有了厂商绑定。另外针对不太熟悉镜像或者不想感受复杂性的用户,我们也提供了 War / Jar 层面的部署,极大降低用户享受红利的门槛。面向终态在传统的运维领域有很多问题比较难解决,比如服务器因为各种各样的原因,突然负载高或者 CPU 高等,这时在传统领域通常需要大量的手动运维操作,而在 K8s 领域结合可观测、健康检查,只需配置好 liveness 和 readiness,就可以实现自动化的运维,K8s 会自动进行切流以及自动化地重新调度,极大地降低了运维成本。资源托管不仅 ECS 机是托管的,K8s 也是内部托管运维的,客户完全不需要购买服务器或者购买 K8s 或者运维 K8s,甚至都不需要懂 K8s,极大地降低了客户的入门门槛和薪资负担。2. Serverless 特性极致弹性我们已经实现了端到端的 15 秒,也就是 15 秒内可以创建出一个 pod,让用户的应用开始启动。在弹性能力上,我们具有基础指标弹性(如 CPU、Memory 等)、业务指标条件弹性(如 QPS、RT 等)和定时弹性。如果手动设置弹性指标,仍有一些门槛和负担,因为客户不知道指标应该设成多少,在这个背景下,我们也在考虑智能弹性,自动帮用户算出弹性指标推荐给用户,进一步降低门槛。精益成本SAE 免去了资源托管和运维成本,在此之前客户需要运维大量的 ECS 服务器,当需要安全升级、漏洞修复,特别是高密部署时,成本会很高。另外 SAE 计费模式是以分钟计费,用户完全可以实现精益成本,比如在业务高峰的 1 小时扩容到 10 个实例,在高峰结束后变成 2 个实例。语言增强在弹性领域,我们针对性地做了一些语言增强。比如 Java,结合阿里的大规模 Java 应用实践,阿里的 JDK——Dragonwell11 相比于其它开源的 JDK,可以让 Java 应用的启动速度提高 40%。未来我们还会在其它语言上探索更多的可能性。3. (application)PaaS 产品形态应用托管应用托管,相当于应用生命周期的管理,包括应用发布、重启、扩容、灰度发布等,其使用的心智和大家在使用应用或其他 PaaS 平台是一样的,上手门槛非常低。一体化集成因为云产品有几百多款,如果要每一款都用好也是额外成本。所以我们对最常用的云服务进行了一体化集成,包括基础监控、业务监控 ARMS、NAS 存储、SLS 的日志收集等各方面,降低用户使用产品的门槛。另外我们还额外地做了微服务增强,包括托管注册中心、优雅上下线和微服务治理等。因为使用微服务通常需要一个注册中心,SAE 内置托管注册中心,用户不需要再重新购置,完全可以把应用直接注册上来,进一步降低用户门槛和成本。SAE 将这些能力组合起来,最终让用户在迁移传统单体应用或者微服务应用时,基本可以实现 0 改造迁移,0 门槛地享受到这款产品背后带来的技术红利。三、SAE 技术架构1. SAE 技术架构图SAE 帮用户托管 K8s 背后的技术架构如上图所示,在 1 个宿主机上,最上层是 SAE 的 PaaS 界面,第二层是 K8s 的 Master(包括 API server 等),最下面一层是 K8s 真正运行资源的宿主机,这些都是完全由 SAE 托管的,用户只需要在自己的 VPC 或网络段内创建 Pod 资源并做一个连通,即可实现应用的正常运行。这里有两个核心问题:一是防穿透,比如我们的 Pod 或容器使用的是像 Docker 这样的传统容器技术,把公有云的 a 和 b 两个用户跑到一个物理机上,其实有非常高的安全风险,b 用户很有可能会侵入到 a 用户的容器里获取用户信息,所以这里面的核心就是要限制用户能力,防止其逃逸。二是网络的连通或者云体系的打通,我们要跟用户的网络体系打通,这样用户才可以方便地和他的安全组、安全的规则、RDS 等连通,这也是一个核心的问题。2. 安全容器在这里具体展开一下防逃逸问题。上图表格是现在大家讨论的比较广泛的安全容器技术,安全容器简单理解就是虚拟机思想。如果使用传统的像 Docker 这样的容器化技术,很难做好安全的防护或隔离,而安全容器可以理解为一个轻量级的虚拟机,既有容器的启动速度,又有虚拟机的安全。目前安全容器已经超脱出了安全,不仅仅有安全的隔离,也有性能的隔离以及故障的隔离,以故障隔离为例,如果采用 Docker 这种容器技术,遇到一些内核问题,就有可能因为一个 Docker 容器的失败而影响到其他用户,整个宿主机都可能会受到影响,而如果采用安全容器技术就不会有这样的问题。SAE 采用了 Kata 安全容器技术,从时间和开源界的事实来说,Kata 是 runV 和 Clear Container 两个项目的结合,相比于 Firecracker 以及 gVisor 方案更加成熟。四、SAE 最佳实践最佳实践 1:低门槛微服务架构转型熟悉微服务的客户都知道,如果要自己运维一套微服务技术架构,需要考虑很多因素,不仅是开源、框架层面,还有资源层面及后续的问题排查,包括注册中心、链路追踪、监控、服务治理等等,如上图左侧所示,在传统开发模式下,这些能力都需要用户自己托管和运维。而在 SAE 中,用户就可以把一些与业务无关的特性交给 SAE,用户只需要关注自己的业务,包括微服务的用户中心、群组中心等,以及和 SAE 的 CI/CD 工具做一个集成,就可以快速实现微服务架构。最佳实践 2:一键启停开发测试环境降本增效有些中大型企业会有多套的测试环境,这些测试环境一般晚上都不使用,在 ECS 模式下,是需要长期保有这些应用实例的,闲置浪费的成本比较高。而如果在 SAE 里就可以结合命名空间,比如一键启停或定时启停的能力,可以将测试环境的应用全部建在测试环境的命名空间下,再配置早上如 8:00 启动测试环境命名空间所有实例,在晚上 8:00 全部停止,停止后的时间段就完全不计费,可以让用户最大化地降低成本。根据计算,在比较极致的情况下,基本上可以节省用户 2/3 的硬件成本,而且也不需要额外付出其他运维成本,只需配置好定时启停的规则即可。最佳实践 3:精准容量+极致弹性的解决方案在今年疫情情况下,大量学生在家进行在线教育,很多在线教育行业的客户面临业务流量暴涨七八倍的情况,如果基于原来自己运维的 ECS 架构,用户就需要在非常短的时间内做架构升级,不仅是运维架构升级,还有应用架构升级,这对用户的成本及精力都是非常大的挑战。而如果依托于 SAE 中各种各样的一体化集成以及底层 K8s 这样高度自动化的平台,就可以简单很多。比如可以结合 PTS 压缩工具评估容量水位;比如压测有问题,可以结合基础监控和应用监控,包括调用链、诊断报告等,可以分析瓶颈在哪里,有没有可能尽短的时间内解决;如果发现是比较难解决的瓶颈,可以使用应用高可用服务,实现限流降级,确保业务不会因为突发洪峰而垮掉。最后 SAE 可以根据压测模型配置相应的弹性策略,比如根据 CPU memory、RT 或者 QPS 等,在有容量模型的情况下设置行业策略,达到非常贴合实际使用量的效果,实现低成本及架构的最大化升级。五、总结数字化转型已经渗透到各行各业,不管是因为时间发展原因还是疫情原因,在数字化转型里,企业要有应用好云的能力,来应对业务上的快速变化及高洪峰高流量场景下的挑战,这一过程包含几个阶段:Rehost(新托管)、Re-platform(新平台)、Refactor(新架构),随着架构改造的深入,企业能够获得的云的价值越高,同时迁移改造成本也会随之上涨,如果只是把应用简单托管到云上,很难获得云的弹性能力,遇到问题时还是很难及时处理。通过 SAE,我们希望能够让用户 0 改造、0 门槛、0 容器基础即可享受到 Serverless + K8s + 微服务的价值红利,最终帮助用户更好面对业务上的挑战。本文整理自【Serverless Live 系列直播】1 月 29 日场直播回看链接:https://developer.aliyun.com/topic/serverless/practicesServerless 电子书下载本书亮点:从架构演进开始,介绍 Serverless 架构及技术选型构建 Serverless 思维;了解业界流行的 Serverless 架构运行原理;掌握 10 大 Serverless 真实落地案例,活学活用。下载链接:https://developer.aliyun.com/topic/download?id=1128
作者 | 雷卷来源|阿里巴巴云原生公众号RSocket 分布式通讯协议是 Spring Reactive 的核心内容,从 Spring Framework 5.2 开始,RSocket 已经是 Spring 的内置功能,Spring Boot 2.3 也添加了 spring-boot-starter-rsocket,简化了 RSocket 的服务编写和服务调用。RSocket 通讯的核心架构中包含两种模式,分别是 Broker 代理模式和服务直连通讯模式。Broker 的通讯模式更灵活,如 Alibaba RSocket Broker,采用的是事件驱动模型架构。而目前更多的架构则是面向服务化设计,也就是我们常说的服务注册发现和服务直连通讯的模式,其中最知名的就是 Spring Cloud 技术栈,涉及到配置推送、服务注册发现、服务网关、断流保护等等。在面向服务化的分布式网络通讯中,如 REST API、gRPC 和 Alibaba Dubbo 等,都与 Spring Cloud 有很好地集成,用户基本不用关心服务注册发现和客户端负载均衡这些底层细节,就可以完成非常稳定的分布式网络通讯架构。RSocket 作为通讯协议的后起之秀,核心是二进制异步化消息通讯,是否也能和 Spring Cloud 技术栈结合,实现服务注册发现、客户端负载均衡,从而更高效地实现面向服务的架构?这篇文章我们就讨论一下 Spring Cloud 和 RSocket 结合实现服务注册发现和负载均衡。服务注册发现服务注册发现的原理非常简单,主要涉及三种角色:服务提供方、服务消费者和服务注册中心。典型的架构如下:服务提供方,如 RSocket Server,在应用启动后,会向服务注册中心注册应用相关的信息,如应用名称,ip 地址,Web Server 监听端口号等,当然还会包括一些元信息,如服务的分组(group),服务的版本号(version),RSocket 的监听端口号,如果是 WebSocket 通讯,还需要提供 ws 映射路径等,不少开发者会将服务提供方的服务接口列表作为 tags 提交给服务注册中心,方便后续的服务查询和治理。在本文中,我们采用 Consul 作为服务注册中心,主要是 Consul 比较简单,下载后执行 consul agent -dev 就可以启动对应的服务,当然你可以使用 Docker Compose,配置也非常简单,然后 docker-compose up -d 就可以启动 Consul 服务。当我们向服务中心注册和查询服务时,都需要有一个应用名称,对应到 Spring Cloud 中,也就是 Spring Boot 对应的 spring.application.name 的值,这里我们称之为应用名称,也就是后续的服务查找都是基于该应用名称进行的。如果你调用 ReactiveDiscoveryClient.getInstances(String serviceId); 查找服务实例列表时,这个 serviceId 参数其实就是 Spring Boot 的应用名称。考虑到服务注册和后续的 RSocket 服务路由的配合以及方便大家理解,这里我们打算设计一个简单的命名规范。假设你有一个服务应用,功能名称为 calculator,同时提供两个服务: 数学计算器服务(MathCalculatorService)和汇率计算器服务(ExchangeCalculatorService), 那么我们该如何来命名该应用及其对应的服务接口名?这里我们采用类似 Java package 命名规范,采用域名倒排的方式,如 calculator 应用对应的则为 com-example-calculator 样式,为何是中划线,而不是点?. 在 DNS 解析中作为主机名是非法的,只能作为子域名存在,不能作为主机名,而目前的服务注册中心设计都遵循 DNS 规约,所以我们采用中划线的方式来命名应用。这样采用域名倒排和应用名结合的方式,可以确保应用之间不会重名,另外也方便和 Java Package 名称进行转换,也就是 - 和 . 之间的相互转换。那么应用包含的服务接口应该如何命名?服务接口全名是由应用名称和 interface 名称组合而成,规则如下:String serviceFullName = appName.replace("-", ".") + "." + serviceInterfaceName; 例如以下的服务命名都是合乎规范的:com.example.calculator.MathCalculatorServicecom.example.calculator.ExchangeCalculatorService而 com.example.calculator.math.MathCalculatorService 则是错误的, 因为在应用名称和接口名称之间多了 math。为何要采用这种命名规范?首先让我们看一下服务消费方是如何调用远程服务的。假设服务消费方拿到一个服务接口,如 com.example.calculator.MathCalculatorService,那么他该如何发起服务调用呢?首先根据 Service 全面提取处对应的应用名称(appName),如 com.example.calculator.MathCalculatorService 服务对应的 appName 则为 com-example-calculator。如果应用和服务接口之间不存在任何关系,那么想要获取服务接口对应的服务提供方信息,你可能还需要应用名称,这会相对来说比较麻烦。如果接口名称中包含对应的应用信息,则会简单很多,你可以理解为应用是服务全面中的一部分。调用 ReactiveDiscoveryClient.getInstances(appName) 获取应用名对应的服务实例列表(ServiceInstance),ServiceInstance 对象会包含诸如 IP 地址,Web 端口号、RSocket 监听端口号等其他元信息。根据 RSocketRequester.Builder.transports(servers) 构建具有负载均衡能力的 RSocketRequester 对象。使用服务全称和具体功能名称作为路由进行 RSocketRequester 的 API 调用,样例代码如下:rsocketRequester .route("com.example.calculator.MathCalculatorService.square") .data(number) .retrieveMono(Integer.class)通过上述的命名规范,我们可以从服务接口全称中提取出应用名,然后和服务注册中心交互查找对应的实例列表,然后建立和服务提供者的连接,最后基于服务名称进行服务调用。该命名规范,基本做到到了最小化的依赖,开发者完全是基于服务接口调用,非常简单。RSocket 服务编写有了服务的命名规范和服务注册,编写 RSocket 服务,这个还是非常简单,和编写一个 Spring Bean 没有任何区别。引入 spring-boot-starter-rsocket 依赖,创建一个 Controller 类,添加对应的 MessagMapping annotation 作为基础路由,然后实现功能接口添加功能名称,样例代码如下:@Controller @MessageMapping("com.example.calculator.MathCalculatorService") public class MathCalculatorController implements MathCalculatorService { @MessageMapping("square") public Mono<Integer> square(Integer input) { System.out.println("received: " + input); return Mono.just(input * input); } }上述代码看起来好像有点奇怪,既然是服务实现,添加 @Controller 和 @MessageMapping,看起来好像有点不伦不类的。当然这些 annotation 都是一些技术细节体现,你也能看出,RSocket 的服务实现是基于 Spring Message 的,是面向消息化的。这里我们其实只需要添加一个自定义的 @SpringRSocketService annotation 就可以解决这个问题,代码如下:@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @MessageMapping() public @interface SpringRSocketService { @AliasFor(annotation = MessageMapping.class) String[] value() default {}; }回到服务对应的实现代码,我们改为使用 @SpringRSocketService annotation,这样我们的代码就和标准的 RPC 服务接口完全一模一样啦,也便于理解。此外 @SpringRSocketService 和 @RSocketHandler 这两个 Annotation,也方便我们后续做一些 Bean 扫描、IDE 插件辅助等。@SpringRSocketService("com.example.calculator.MathCalculatorService") public class MathCalculatorImpl implements MathCalculatorService { @RSocketHandler("square") public Mono<Integer> square(Integer input) { System.out.println("received: " + input); return Mono.just(input * input); } }最后我们添加一下 spring-cloud-starter-consul-discovery 依赖,设置一下 bootstrap.properties,然后在 application.properties 设置一下 RSocket 监听的端口和元信息,我们还将该应用提供的服务接口列表作为 tags 传给服务注册中心,当然这个也是方便我们后续的服务管理。样例如下:spring.application.name=com-example-calculator spring.cloud.consul.discovery.instance-id=com-example-calculator-${random.uuid} spring.cloud.consul.discovery.prefer-ip-address=true server.port=0 spring.rsocket.server.port=6565 spring.cloud.consul.discovery.metadata.rsocketPort=${spring.rsocket.server.port} spring.cloud.consul.discovery.tags=com.example.calculator.ExchangeCalculatorService,com.example.calculator.MathCalculatorServiceRSocket 服务应用启动后,我们在 Consul 控制台就可以看到服务注册上来的信息,截屏如下:RSocket 客户端接入客户端接入稍微有一点复杂,主要是要基于服务接口全面要做一系列相关的操作,但是前面我们已经有了命名规范,所以问题也不大。客户端应用同样会接入服务注册中心,这样我们就可以获得 ReactiveDiscoveryClient bean,接下来就是根据服务接口全名,如 com.example.calculator.ExchangeCalculatorService 构建出具有负载均衡的 RSocketRequester。原理也非常简单,前面说过,根据服务接口全称,获得其对应的应用名称,然后调用 ReactiveDiscoveryClient.getInstances(appName) 获得服务应用对应的实例列表,接下来将服务实例(ServiceInstance)列表转换为 RSockt 的 LoadbalanceTarget 列表,其实就是 POJO 转换,最后将转 LoadbalanceTarget 列表进行 Flux 封装(如使用 Sink 接口),传递给 RSocketRequester.Builder 就完成具有负载均衡能力的 RSocketRequester 构建,详细的代码细节大家可以参考项目的代码库。这里要注意的是接下来如何感知服务端实例列表的变化,如应用上下线,服务暂停等。这里我采用一个定时任务方案,定时查询服务对应的地址列表。当然还有其他的机制,如果是标准的 Spring Cloud 服务发现接口,目前是需要客户端轮询的,当然也可以结合 Spring Cloud Bus 或者消息中间件,实现服务端列表变化的监听。如果客户端感知到服务列表的变化,只需要调用 Reactor 的 Sink 接口发送新的列表即可,RSocket Load Balance 在感知到变化后,会自动做出响应,如关闭即将失效的连接、创建新的连接等工作。在实际的应用之间的相互通讯,会存在一些服务提供方不可用的情况,如服务方突然宕机或者其网络不可用,这就导致了服务应用列表中部分服务不可用,那么 RSocket 这个时候会如何处理?不用担心,RSocket Load Balance 有重试机制,当一个服务调用出现连接等异常,会重新从列表中获取一个连接进行通讯,而那个错误的连接也会标识为可用性为 0,不会再被后续请求所使用。服务列表推送和通讯期间的容错重试机制,这两者保证了分布式通讯的高可用性。最后让我们启动 client-app,然后从客户端发起一个远程的 RSocket 调用,截屏如下:上图中 com-example-calculator 服务应用包括三个实例,服务的调用会在这三个服务实例交替进行(RoundRobin 策略)。开发体验的一些考量虽然服务注册和发现、客户端的负载均衡这些都完成啦,调用和容错这些都没有问题,但是还有一些使用体验上的问题,这里我们也阐述一下,让开发体验做的更好。1. 基于服务接口通讯大多数 RPC 通讯都是基于接口的,如 Apache Dubbo、gRPC 等。那么 RSocket 能否做到?答案是其实完全可以。在服务端,我们已经是基于服务接口来实现 RSocket 服务啦,接下来我们只需要在客户端实现基于该接口的调用就可以。对于 Java 开发者来说,这不是大问题,我们只需要基于 Java Proxy 机制构建就可以,而 Proxy 对应的 InvocationHandler 会使用 RSocketRequester 来实现 invoke() 的函数调用。详细的细节请参考应用代码中的的 RSocketRemoteServiceBuilder.java 文件,而且在 client-app module 中也已经包含了解基于接口调用的 bean 实现。2. 服务接口函数的单参数问题使用 RSocketRequester 调用远程接口时,对应的处理函数只能接受单个参数,这个和 gRPC 的设计是类似的,当然也考虑了不同对象序列化框架的支持问题。但是考虑到实际的使用体验,可能会涉及到多参函数的情况,让调用方开发体验更好,那么这个时候该如何处理?其实从 Java 1.8 后,interface 是允许增加 default 函数的,我们可以添加一些体验更友好的 default 函数,而且还不影响服务通讯接口,样例如下:public interface ExchangeCalculatorService { double exchange(ExchangeRequest request); default double rmbToDollar(double amount) { return exchange(new ExchangeRequest(amount, "CNY", "USD")); } }通过 interface 的 default method,我们可以为调用方提供给便捷函数,如在网络传输的是字节数组 (byte[]),但是在 default 函数中,我们可以添加 File 对象支持,方便调用方使用。Interface 中的函数 API 负责服务通讯规约,default 函数来提升使用方的体验,这两者的配合,可以非常容易解决函数多参问题,当然 default 函数在一定程度上还可以作为数据验证的前哨来使用。3. RSocket Broker 支持前面我们说到,RSocket 还有一种 Broker 架构,也就是服务提供方是隐藏在 Broker 之后的,请求主要是由 Broker 承接,然后再转发给服务提供方处理,架构样例如下:那么基于服务发现的机制负载均衡,能否和 RSocket Broker 模式混合使用呢?如一些长尾或者复杂网络下的应用,可以注册到 RSocket Broker,然后由 Broker 处理请求调用和转发。这个其实也不不复杂,前面我们说到应用和服务接口命名规范,这里我们只需要添加一个应用名前缀就可以解决。假设我们有一个 RSocker Broker 集群,暂且我们称之为 broker0 集群,当然该 broker 集群的实例也都注册到服务注册中心(如 Consul)啦。那么在调用 RSocket Broker 上的服务时,服务名称就被调整为 broker0:com.example.calculator.MathCalculatorService,也就是服务名前添加了 appName: 这样的前缀,这个其实是 URI 的另一种规范形式,我们就可以提取冒号之前的应用名,然后去服务注册中心查询获得应用对应的实例列表。 回到 Broker 互通的场景,我们会向服务注册中心查询 broker0 对应的服务列表,然后和 broker0 集群的实例列表创建连接,这样后续基于该接口的服务调用就会发送给 Broker 进行处理,也就是完成了服务注册发现和 Broker 模式的混合使用的模式。借助于这种定向指定服务接口和应用间的关联,也方便我们做一些 beta 测试,如你想将 com.example.calculator.MathCalculatorService 的调用导流到 beta 应用,你就可以使用 com-example-calculator-beta1:com.example.calculator.MathCalculatorService 这种方式调用服务,这样服务调用对应的流量就会转发给 com-example-calculator-beta1 对应的实例,起到 beta 测试的效果。回到最前面说到的规范,如果应用名和服务接口的绑定关系你实在做不到,那么你可以使用这种方式实现服务调用,如 calculator-server:com.example.calculator.math.MathCalculatorService,只是你需要更完整的文档说明,当然这种方式也可以解决之前系统接入到目前的架构上,应用的迁移成本也比较小。如果你之前的面向服务化架构设计也是基于 interface 接口通讯的,那么通过该方式迁移到 RSocket 上完全没有问题,对客户端代码调整也最小。总结通过整合服务注册发现,结合一个实际的命名规范,就完成了服务注册发现和 RSocket 路由之间的优雅配合,当然负载均衡也是包含其中啦。对比其他的 RPC 方案,你不需要引入 RPC 自己的服务注册中心,复用 Spring Cloud 的服务注册中心就可以,如 Alibaba Nacos, Consul, Eureka 和 ZooKeeper 等,没有多余的开销和维护成本。如果你想更多了解 RSocket RPC 相关的细节,可以参考 Spring 官方博客 《Easy RPC with RSocket》。欢迎加入 alibaba-rsocket-broker 钉钉群:更多详细的代码细节,可以点击链接查看文章对应的代码库!
作者 | Apache Dubbo来源|阿里巴巴云原生公众号2011 年,阿里 B2B 团队决定将项目开源,一年时间就收获了来自不同行业的大批用户2014 年,由于团队调整,Dubbo 暂停更新2017 年,Dubbo 开源重启2019 年,Dubbo 在仅用时 15 个月的情况下从 Apache 基金会毕业2020 年,阿里内部开始 HSF 和 Dubbo 的融合2021 年 3 月,Dubbo 3.0 Preview 即将发布……从 2011 到 2021,Dubbo 已经开源十年。十年,对于风起云涌的云计算领域是漫长且充满变化的,但 Dubbo 在这个时代的浪潮里不仅没有变成被人遗忘的“前浪”,更在云原生时代,迎来内核云原生技术栈全面升级。本文是对阿里集团服务框架负责人北纬的采访,他在阿里同时负责 HSF、Dubbo 和 Spring Cloud Alibaba。本文讲述了他 2017 年接手 Dubbo 后社区的进展,并展望开源十年的 Dubbo 将如何走好云原生之路。2017年,我开始接手 Dubbo 项目后,我们对外表示会重新维护这个项目,就收到了很多积极的反馈,随着对这个项目的深入了解,我发现国内很多大型厂商,甚至传统国企都在广泛使用该项目,才意识到身上的责任。Dubbo 3.0 Preview 版即将在 3 月发布,我们准备了 Dubbo 3.0 前瞻系列电子书(获取方式见文末),也借这个机会大家聊聊 Dubbo 重启开源后被频繁问到的问题:从 Apache 毕业两年不到的时间,我们都做了什么?阿里内部是如何进行 Dubbo 和 HSF 融合的?规模怎么样?如何看待 Spring Cloud 和 gRPC?3.0 有什么值得期待的?同期毕业最快的 Apache 项目,多语言全面发展2017 年,我负责这个项目以来,一些开发者在担心 Dubbo 只是阿里主导的 KPI 开源项目,比较担心这个项目能不能持续发展、会不会断更。既然这样,那我干脆就把它放到中立的位置上,Apache 基金会是一个很好的选择, 正是这一决定让 Dubbo 成为同期五个项目中最快从 Apache 基金会毕业的项目:2019 年 5 月 21 日,Dubbo 在仅用时 15 个月的情况下从 Apache 基金会毕业。事实证明,把 Dubbo 捐给 Apache,让 Dubbo 变成一个社区主导的项目是一个非常正确的决策。根据 X-lab 开放实验室最新发布的《2020 年微服务领域开源数字化报告》,Dubbo 的开源活跃度全球排名 693,在微服务框架中排名第五,参与过社区建设的开发者数量已经超过 1 万多人,来自外部的代码贡献量已经超过阿里员工的贡献量。数据来源 -《2020 年微服务领域开源数字化报告》Dubbo 项目从 Apache 毕业 2 年不到的时间,整个社区拥有 21 名 PMC 成员,61 名 committer,以及多达 370 名贡献者。在过去一年,Dubbo 在多语言建设方面先后从社区收获了 JS、Python、Erlang、PHP、Go 的实现,特别郑重感谢千米网、携程网、乐信以及其他开发者们捐献或者提交了这些多语言版本的绝大多数代码,为社区带来了丰富的多语言支持解决方案。在于雨的带领下,Dubbo-go 可以说是当前众多多语言版本中最活跃的一个分支,有者非常活跃的 go 子社区及持续增长的企业级用户,目前 Dubbo go 已经在 1.5 版本追平 Dubbo Java 2.7 的特性;目前正在和 Java 齐头并进,一起规划 Dubbo 3.0 中云原生的路线图。我们对这个大版本 Dubbo 3 的定义是云原生、阿里背书。计划分为三个版本迭代,在后面 Dubbo 3 的路线图中有详细的描述。Dubbo 3.0 正在紧锣密鼓的开发中,核心功能包括 Dubbo3 协议、应用级服务发现、新版路由规则等,go 与 java 版本预计将以同样的时间节奏兑现以上所有功能,3 月底会有 preview 版本与社区见面。过去 2 年社区的经历更让我相信,单靠核心团队的几位工程师凭着单纯的开源情怀是很难持续的。全国各地有上百数千家企业在使用 Dubbo,仅依靠我们一个小团队的力量远远不够,我们希望社区内的开发者可以更多地参与进来。对 Dubbo 而言,不管开发者最初进入并对项目有所贡献的原因是什么。重要的是,我们希望能够让整个社区保持开放,即便个别工程师仅仅只是为了日后找份工作来参与社区也没有关系,我认为这种想法很正常,毕竟贡献项目会占据开发者很多业余时间,我们也希望这个项目可以对大家有所帮助。Dubbo 和 HSF 融合,阿里先自己用上 Dubbo 再说我面临的第二个最大的质疑是:阿里内部都不用 Dubbo,如何获得开发者的信任?熟悉阿里技术历史的同学可能知道,淘宝的 HSF 项目也是一个中间件服务框架,与 Dubbo 做的事情高度重合。而 Dubbo 在开源过程中很多开发者诟病的也是阿里自己都没有在用 Dubbo。这也是我们一直在苦恼的:阿里内部的自研体系、商业化的产品技术与开源的项目,三方的技术路线一直没有机会融为一体。随着阿里自研体系的上云,融合的机遇终于到来了。2020 年,阿里云提出了“三位一体”理念,即:将“自研技术”、“开源项目”、“商业产品”形成统一的技术体系,最大化技术的价值。HSF 目前以 Dubbo 3.0 为核心,内部特性以 Dubbo 插件的方式存在,并把 HSF 只在阿里集团内部大规模场景下高并发、高性能等优化经验应用到 Dubbo 3.0 核心上,实现了内外功能的统一,使得社区和客户都能用到这些优质经验;另外一方面,Dubbo 3.0 云原生相关的功能借助于社区开发力量得到进一步发展。通过“三位一体”与社区达成开放共赢的局面。我的老领导林昊、阿里人称毕大师,由于设计开发了 HSF 今年获得了中国计算机学会的杰出工程师奖,他在获奖采访中提到:作为工程师来讲,很大的成就感来自于自己所做的技术被公司大范围的使用,并且对这家公司的业务发展能起到很大的支撑作用;更大的成就感来自于自己做所的技术背后的思想、实现思路能影响到中国各大互联网公司、企业去拥抱微服务。随着 Dubbo 和 HSF 的整合,我们在整个开源的体系中更多地去展现了 HSF 的能力,能够让更多的人通过使用 Dubbo 像阿里巴巴之前使用 HSF 一样更好地构建服务化的系统。在 2020 年 双11,Dubbo 3.0 在集团电商业务上已经进入落地阶段,电子书里也会跟大家分享一些我们的实践经验。如何看待 Spring Cloud 和 gRPC?在 Dubbo 沉寂的几年,出来很多新生的服务框架,Dubbo 和 Sping Cloud 是什么关系?是不是二选一就够了?Dubbo 和 gRPC 之间的差别是什么?Dubbo 和 Spring Cloud 如何二选一?长久以来,总有开发者喜欢将 Dubbo 与 Spring Cloud 进行比较,提到这两个名字的第一反应往往是应该选哪个,而不是二者如何配合使用。在我看来,这主要还是技术选型的问题,以及用户对随之而来的切换成本的顾虑。其实这是一种误解,两者的关系不是非此即彼。今天的 Dubbo 已经成为了 Spring Cloud Alibaba 中一个重要的技术组件,Dubbo 服务和 Spring Cloud 服务可以完美地互相调用。未来,Dubbo 3.0 进一步的简化了 Dubbo 和 Spring Cloud 混布场景中服务基础设施的部署。 Spring Cloud 依托于 Spring 已经成为 Java 开发的标准框架,这是不争的事实,并结合大量业界经验逐渐抽象出一套微服务通用架构模式标准。这套标准的好处在于可以让开发者非常便捷地进行微服务软件产品开发,且在整个 Spring 生态的加持下已经成为开发者的“一揽子”解决方案。和 Spring Cloud 不同,Dubbo 在设计之初,扩展性、灵活性就被放在了一个很重要的位置。Dubbo 很容易集成别人,别人也容易集成 Dubbo。同时,Dubbo 经过大量用户生产验证,阿里在服务化领域持续实践的产品。这两点是 Spring Cloud 目前无法做到的。随着 Dubbo 恢复更新,其场景丰富程度与稳定性也有了非常大的提升,目前已经在多家头部公司大规模应用。回到众多开发者对技术选型问题的顾虑:这两套框架并不是非此即彼。相反的,用户可以轻松的在这两套框架之间切换,甚至未来可以完美的在一起协同工 作,这得益于 Spring Cloud Alibaba 的出现。Spring Cloud 拥有一个强大的国际化社区,阿里巴巴作为社区里的重要成员,也贡献出了 Spring Cloud Alibaba 这套实现,这也是目前整个 Spring Cloud 体系下最完善并且在持续更新的实现方案。Spring Cloud Alibaba 出现现在的 Dubbo 2.7 已经可以很好的在 Spring Cloud 体系下工作。通过 Spring Cloud Alibaba 中 Dubbo 的集成,Spring Cloud 应用可以调用原生发布的 Dubbo 服务,Spring Cloud 发布的 Dubbo 服务也可以被原生的 Dubbo 客户端调用。这个得益于 2.7 中服务自省的实验性项目,以及 Spring Cloud 侧对 Dubbo 的适配。在正在开展的 3.0 大版本中,这个实验性的项目进化为原生应用级服务注册机制。通过这个特性,未来 Spring Cloud 应用和 Dubbo 应用可以更加完美的混布。用户可以为 Spring Cloud 和 Dubbo 复用同一套服务发现、服务配置、和服务管理体系,为 Dubbo 和 Spring 互通需要额外搭建网关将成为过去式,用户可以零成本的在两者之间切换,或者视场景不同选择不同的框架,甚至可以在同一个应用中混用。Dubbo 与 Spring Cloud 混布场景中业界常规的 Proxy 集群终于去掉,整个体系的架构更加简单和稳定。在 Dubbo 3.0 版本中,整个团队会继续进化应用级服务注册的想法,期望通过这项工作让 Spring Cloud Alibaba 与 Dubbo 在注册数据的模型上达成高度统一,复用同一套服务注册中心,进一步简化混布场景中的架构。另外,我们团队也在积极发展 Spring Cloud Alibaba 生态。作为国内 Java 界最具影响力的团队之一,阿里中间件团队一直在密切关注 Spring 项目,通过 Spring 的封装提升阿里的中间件开发体验。阿里巴巴电商体系绝大部分应用已经实现 Boot 化。当 Spring Cloud 初具影响力的时候,我们主动通过 Spring Cloud 来集成阿里巴巴开源组件就变成一件自然而然的事情了 目前,Spring Cloud Alibaba 已经支持 Nacos 作为服务注册中心、配置中心,Sentinel 作为限流,Seata 作为分布式事务组件,RocketMQ 作为分布式消息组件,当然还有 Dubbo 作为 RPC 组件,全面取代了已经宣布停止更新的 Spring Cloud Netflix 全家桶。另外,为了加速国内工程师对 Spring Initializr 的访问,团队还通过阿里云上托管的 start.aliyun.com 提供了快速生成 Spring Cloud Alibaba 应用的能力。无论从 GitHub 的项目活跃度数据还是关注度数据来看,毫不夸张地说,Spring Cloud Alibaba 已经成为 Spring Cloud 框架中的事实标准了。如何看待 gRPC?我们从不避讳 gRPC,它是一个令人尊敬的对手,是云原生基础设施之间通讯协议的事实标准。但是 Dubbo 的优势是不单单是一个 RPC,而且是一个 有着强大治理能力的 服务框架。我们认为:Dubbo 是 gRPC with batteries。我们从 gRPC 身上学到最有价值的一点就是反思 Dubbo 2 中协议设计的不足,开始重视云原生支持领域里两个重要的问题:多语言支持和网关/Mesh 解析友好。在 Dubbo 3.0 中,新版本的协议是重中之重,除了解决上述两个问题,对 gRPC 协议的兼容也是新协议的设计目标之一。gRPC 有几项明显的优势:在支持 HTTP/2 协议上走在了前列,提供了非常丰富的多语言库支持,与 Google 主导的许多云原生基础设施无缝打通。gRPC 及时下流行的 Mesh 等云原生技术构建了一套看起来相对完善的微服务技术栈,落地这套技术栈看起来是基于 gRPC 的微服务解决方案。但 gRPC 框架自身而言还是专注在 RPC 通信。相比而言,Dubbo 提供了一站式的微服务开发、治理解决方案,Dubbo 有更易用的面向接口的服务定义模型,有更完善的服务发现、服务治理机制。同时,在即将发布的 3.0 规划中,Dubbo 3 也将提供官方的 Mesh 解决方案支持,继续给社区带来易用的、一站式的解决方案。 Dubbo 3.0 展望:对云原生支持社区中的很多开发者都对 3.0 版本期待已久。Dubbo 3 的主基调就是云原生支持,计划分为三个版本迭代。重点交付云原生友好的新一代 RPC 协议、应用级服务注册发现、K8s 原生服务发布、Mesh 控制面 xDS 协议对接以及分布式服务柔性等重磅级特性。3.0 版本,重点发布应用级服务注册发现、Tripe、新路由规则。3.1 版本,重点发布 K8s 原生服务、Mesh 控制面 xDS 协议对接。3.2 版本,重点发布分布式服务柔性。目前应用级服务发现已经在内部和一些头部用户的场景做试点,后续随着项目的进展,团队会第一时间发布功能实现细节。通过 Dubbo 3.0 的发布,我们期待带来一款向云原生迁移友好的,对云原生基础设施友好的新一代服务框架体系。未来,Dubbo 项目总的发展基调还是坚持合作开放的开源路线不动摇,追求更高质量和功能更完善的路线不动摇。目前,社区发展的重中之重是 Dubbo3.0 演进。在不久后的 9 月份, Dubbo 3.0 应用级注册发现将在阿里巴巴内部和开源侧各公司落地。这不仅是 Dubbo 迈向云原生微服务的第一步,也是对接 K8s 注册发现和跨框架 RPC 互通的前提。就应用方而言,从接口级注册发现到应用级注册发现可以显著降低注册中心和客户端的内存压力。今年 双11,云原生服务治理规则会把 Dubbo 多年以来在大规模高并发服务治理方面的最佳实践融入云原生。下一代协议将基于 http2/protobuf 带来更好的生态和 Reactive 的全面支持,柔性增强所涵盖的自适应策略和分布式负载均衡将会在性能和稳定性上带来更大的突破。回到 Dubbo 重启开源之时,生态相对薄弱 。如今,Dubbo 生态已经日益完善。Dubbo 丰富的扩展实现比如,多语言支持已经达到 6 种,30+ 生态子项目。在 Dubbo 主动集成周边的同时,我们也被第三方开源项目 Spring Cloud Sleuth、Zipkin、Skywalking、Envoy、tengine 等主动集成。我心中的完善是希望能够产出一个官方推荐的 Dubbo Stack,免除用户选择上面的烦恼。至于 Dubbo Stack 中是否都源自阿里,我倒是抱着顺其自然的态度,这还是需要数据说话,谁家的组件在生产系统中运用最广,我们就推荐谁。总的来说,这件事情的决定权在社区和 Dubbo 用户。 最后,感谢十年来 Dubbo 的用户和社区贡献者们,对于 Dubbo 3.0 Roadmap 中的云原生友好的新一代 RPC 协议、应用级服务注册发现、K8s 原生服务发布等重磅级特性,我们梳理了一系列前瞻的文章整理成了电子书。欢迎大家回复关键词 “Dubbo3” 获取。 扫码加入 Dubbo 开源社区钉钉群(或钉钉搜索群号:21976540):
作者 | 徐晓舟(萧元)来源|阿里巴巴云原生公众号背景由于云计算在资源成本和弹性扩容方面的天然优势,越来越多客户愿意在云上构建 AI 系统,而以容器、Kubernetes 为代表的云原生技术,已经成为释放云价值的最短路径, 在云上基于 Kubernetes 构建 AI 平台已经成为趋势。当面临较复杂的模型训练或者数据量大时,单机的计算能力往往无法满足算力要求。通过使用阿里的 AiACC 或者社区的 horovod 等分布式训练框架,仅需修改几行代码,就能将一个单机的训练任务扩展为支持分布式的训练任务。在 Kubernetes 上常见的是 kubeflow 社区的 tf-operator 支持 Tensorflow PS 模式,或者 mpi-operator 支持 horovod 的 mpi allreduce 模式。现状Kubernetes 和云计算提供敏捷性和伸缩性,我们可以通过 cluster-AutoScaler 等组件为训练任务设置弹性策略,利用 Kubernetes 的弹性能力,按需创建,减少 GPU 设备空转。但这种伸缩模式面对训练这种离线任务还是略有不足:不支持容错,当部分 Worker 由于设备原因失败,整个任务需要停止重来。训练任务一般时间较长,占用算力大,任务缺少弹性能力。当资源不足时,除非任务终止,无法按需为其他业务腾出资源。训练任务时间较长,不支持 worker 动态配置, 无法安全地使用抢占实例,发挥云上最大性价比如何给训练任务赋予弹性能力,是提高性价比的关键路径。近期 horovod 等分布式框架逐渐支持了 Elastic Training,即弹性训练能力。也就是允许一个训练任务在执行的过程中动态的扩容或者缩容训练 worker, 从不会引起训练任务的中断。需要在代码中做少量修改适配,可参考:https://horovod.readthedocs.io/en/stable/elastic_include.html。对 Elastic training 的实现原理感兴趣可以看这篇 Elastic Horovod 设计文档, 本文不详细介绍。在 mpi-operator 中,参与训练的 Worker 都是作为静态资源设计和维护,支持弹性训练模式后,给任务增加了灵活性,同时也给运维层带来了挑战,例如:必须通过 horovod 提供的 horovordrun 作为入口,horovod 中 launcher 通过 ssh 登陆 worker,需要打通 launcher 和 worker 之间的登陆隧道。负责计算弹性的 Elastic Driver 模块通过指定 discover_host 脚本获取最新 worker 拓扑信息,从而拉起或停止 worker 实例。当 worker 变化时,首先要更新 discover_host 脚本的返回值。在抢占或价格计算等场景中,有时需要指定 worker 缩容,K8s 原生的编排元语 deployment,statefulset 无法满足指定缩容的场景。解决方法针对以上问题,我们设计开发了 et-operator,提供 TrainingJob CRD 描述训练任务, ScaleOut 和 ScaleIn CRD 描述扩容和缩容操作, 通过它们的组合,使我们的训练任务更具有弹性。将这个方案开源,欢迎大家提需求、交流、吐槽。开源方案地址:https://github.com/AliyunContainerService/et-operator设计TrainingJob Controller 主要有以下功能:维护 TrainingJob 的创建/删除生命周期,以及子资源管理。执行扩缩容操作。容错,当 worker 被驱逐,创建新的 worker 加入到训练中。1. 资源创建TrainingJob 子资源创建顺序如下:创建打通 ssh 所需的密钥对, 创建 secret。创建 workers,包含 service 和 pod,挂载 secret 公钥。创建 configmap, 包含 discover_host 脚本 , hostfile 文件。创建 launcher,挂载 configmap。由于 hostfile 后续会随着拓扑关系修改,所以 hostfile 单独通过 initcontainer 从 configmap 拷贝到单独目录。TrainingJob 相关资源:TrainingJob CR 的配置分为 Lanucher 和 Worker。在 Launcher 中指定任务的镜像和启动执行, 默认 et-operator 会根据 worker 分配情况,生成一个 hostfile 文件和 discover_host 脚本,discover_host 脚本挂载到 Launcher 的 /etc/edl/discover_hosts.sh 文件, 在入口脚本的 horovodrun 执行中通过 --host-discovery-script 参数指定。在 Worker 设置中指定 worker 的镜像和 GPU 占用 ,并可以通过 maxReplicas / minReplicas 指定 workers 的副本数允许范围。apiVersion: kai.alibabacloud.com/v1alpha1 kind: TrainingJob metadata: name: elastic-training namespace: default spec: cleanPodPolicy: Running etReplicaSpecs: launcher: replicas: 1 template: spec: containers: - command: - sh - -c - horovodrun -np 2 --min-np 1 --max-np 9 --host-discovery-script /etc/edl/discover_hosts.sh python /examples/elastic/tensorflow2_mnist_elastic.py image: registry.cn-huhehaote.aliyuncs.com/lumo/horovod:master-tf2.1.0-torch1.4.0-mxnet-py3.6-gpu imagePullPolicy: Always name: mnist-elastic worker: maxReplicas: 9 minReplicas: 1 replicas: 2 template: spec: containers: - image: registry.cn-huhehaote.aliyuncs.com/lumo/horovod:master-tf2.1.0-torch1.4.0-mxnet-py3.6-gpu imagePullPolicy: Always name: mnist-elastic resources: limits: nvidia.com/gpu: "1" requests: nvidia.com/gpu: "1" status: currentWorkers: - elastic-training-worker-0 - elastic-training-worker-1 - elastic-training-worker-2 - elastic-training-worker-3 phase: Succeeded replicaStatuses: Launcher: active: 1 succeeded: 1 Worker: active: 42. Worker 扩容 / 缩容除了 TrainingJob 外,et-operator 同时支持 ScaleOut 和 ScaleIn 两种 CRD,下发训练任务扩容和缩容操作。当下发一个 ScaleOut CR,ScaleOutController 触发 Reconcile, 这里工作很简单,根据 ScaleOut CR 中的 Selector 字段,找到 Scaler 对应的 TrainingJob,设置到 CR 的 OwnerReferences 上。以一个 ScaleOut 操作举例:- apiVersion: kai.alibabacloud.com/v1alpha1 kind: ScaleOut metadata: creationTimestamp: "2020-11-04T13:54:26Z name: scaleout-ptfnk namespace: default ownerReferences: - apiVersion: kai.alibabacloud.com/v1alpha1 blockOwnerDeletion: true controller: true kind: TrainingJob name: elastic-training // 指向扩容对象TrainingJob uid: 075b9c4a-22f9-40ce-83c7-656b329a2b9e spec: selector: name: elastic-training toAdd: count: 2TrainingJobController 中监听到属于 TrainingJob 的 ScaleOut CR 有更新, 触发 TrainingJob 的 Reconcile,遍历过滤 TrainingJob 下 OwnerReference 指向的 ScaleIn 和 ScaleOut, 根据创建时间和状态时间决定执行的扩容或者缩容。apiVersion: kai.alibabacloud.com/v1alpha1 kind: TrainingJob metadata: name: elastic-training namespace: default spec: // ...... Launcher and Worker spec status: currentScaler: ScaleIn:default/scaleout-ptfnk phase: Scaling currentWorkers: - elastic-training-worker-0 - elastic-training-worker-1ScaleOut 任务 CR:ScaleIn 任务 CR:详细工作过程:运行1. 安装 ET-Operatormkdir -p $(go env GOPATH)/src/github.com/aliyunContainerService cd $(go env GOPATH)/src/github.com/aliyunContainerService git clone https://http://github.com/aliyunContainerService/et-operator cd et-operator kubectl create -f deploy/all_in_one.yaml 检测 crd 的安装:# kubectl get crd NAME CREATED AT scaleins.kai.alibabacloud.com 2020-11-11T11:16:13Z scaleouts.kai.alibabacloud.com 2020-11-11T11:16:13Z trainingjobs.kai.alibabacloud.com 2020-11-11T11:16:13Z检测 controller 的运行状态,默认安装在 kube-ai 中:# kubectl -n kube-ai get po NAME READY STATUS RESTARTS AGE et-operator-controller-manager-7877968489-c5kv4 0/2 ContainerCreating 0 5s2. 运行 TrainingJob运行事先已准备好的示例:kubectl apply -f examples/training_job.yaml检测运行状态:# kubectl get trainingjob NAME PHASE AGE elastic-training Running 77s # kubectl get po NAME READY STATUS RESTARTS AGE elastic-training-launcher 1/1 Running 0 7s elastic-training-worker-0 1/1 Running 0 10s elastic-training-worker-1 1/1 Running 0 9s3. 缩容训练任务 Worker执行缩容时,可以通过 ScaleIn CR 中的 spec.toDelete.count 或 spec.toDelete.podNames 字段指定缩容的 worker。通过 count 配置缩容的数量,则通过 index 计算由高到低缩容 Worker。apiVersion: kai.alibabacloud.com/v1alpha1 kind: ScaleIn metadata: name: scalein-workers spec: selector: name: elastic-training toDelete: count: 1如果想要缩容特定的 Worker,可以配置 podNames:apiVersion: kai.alibabacloud.com/v1alpha1 kind: ScaleIn metadata: name: scalein-workers spec: selector: name: elastic-training toDelete: podNames: - elastic-training-worker-1运行一个缩容示例,指定数量缩容 1 个 worker:kubectl create -f examples/scale_in_count.yaml检测缩容执行状态和训练任务:# kubectl get scalein NAME PHASE AGE scalein-sample-t8jxd ScaleSucceeded 11s # kubectl get po NAME READY STATUS RESTARTS AGE elastic-training-launcher 1/1 Running 0 47s elastic-training-worker-0 1/1 Running 0 50s4. 扩容训练任务在 ScaleOut CR 中,通过 spec.toAdd.count 字段指定扩容的 worker 数:apiVersion: kai.alibabacloud.com/v1alpha1 kind: ScaleOut metadata: name: elastic-training-scaleout-9dtmw namespace: default spec: selector: name: elastic-training timeout: 300 toAdd: count: 2运行示例:kubectl create -f examples/scale_out.yaml检测缩容执行状态和训练任务:kubectl get scaleout NAME PHASE AGE elastic-training-scaleout-9dtmw ScaleSucceeded 30s kubectl get po NAME READY STATUS RESTARTS AGE elastic-training-launcher 1/1 Running 0 2m5s elastic-training-worker-0 1/1 Running 0 2m8s elastic-training-worker-1 1/1 Running 0 40s elastic-training-worker-2 1/1 Running 0 40s总结ET-Operator 提供一组训练和扩缩容 CRD 和 Controller, 让我们在 Kubernetes 上方便地运行弹性分布式训练,支持下发分布式训练任务,并通过和分布式框架的集成联动,在训练任务运行过程中动态地扩容和缩容参与运算的 Workers。使我们的训练任务具有弹性能力,结合抢占实例,能够更好的利用云上的资源弹性和性价比优势。
来源|阿里巴巴云原生公众号近日,阿里内部的技术论坛 ATA 发布年度热搜关键词 top 100,Arthas 作为 Java 诊断神器是唯一进入 top 10 的非集团指定产品。Arthas 在阿里内部有多么受欢迎可见一斑。独乐乐不如众乐乐,2018 年 9 月,阿里就开源了这个 Java 诊断神器,两年多的时间,Arthas 的 Github star 数已经达 24.6K,成为 Alibaba Group 下 star 最多的开源项目,可以说是当之无愧的阿里最受欢迎的开发者工具了。Arthas 能做什么?当你遇到以下类似问题而束手无策时,Arthas 可以帮助你解决:这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!是否有一个全局视角来查看系统的运行状况?有什么办法可以监控到 JVM 的实时运行状态?怎么快速定位应用的热点,生成火焰图?Arthas 支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。Arthas 教程上线知行动手实验室,57 个实验助你成为问题排查小能手知行体验预览如果你是 Arthas 新手,我们建议你先从 Arthas 入门实验开始,了解 Athas 的基础用法,再以一个普通的 Spring Boot 应用为例,熟悉 Arthas 命令的详细用法。知行在入门教程的基础上,新增了基础命令、系统命令、增强命令、类命令四大类命令相关实验,大家可以根据自己的实际需求来体验学习,也可以把这些体验场景当成可交互文档来实时查询。在此之上,我们还提供了 14 个典型的案例场景,包括后台异步任务、获取 Spring 上下文、401\404 问题排查等,帮助你快速排查具体业务问题。废话不多说了,点击立即登录知行动手实验室体验 Arthas**。
2021年02月