联席作者:吴毅挺 任浩军 张彬彬 廖梦鸽 张金星 胡振建
郑重鸣谢:Nacos – 彦林,Spring Cloud Alibab – 小马哥、落夜,Nacos 社区 – 张龙(pader)、春少(chuntaojun)
前言
在高速倒退的时候,公司规模越来越大,老师人数越来越多,这时候公司不能铺太多人去做经营与服务,必须进步每个人效,这就须要技术驱动。因而掌门教育转变成一家技术驱动型的公司,如果被迫成为一家靠资金驱动的公司就活不下去了。
— 张翼(掌门教育创始人兼 CEO)
掌门教育自 2014 年正式转型在线教育以来,秉承“让教育共享智能,让学习高效高兴”的主旨和愿景,经验云计算、大数据、人工智能、AR / VR / MR 以及现今最火的 5G,始终保持用科技赋能教育。掌门教育的业务近几年失去了疾速倒退,特地是往年的疫情,使在线教育成为了新的风口,也给掌门教育新的时机。
随着业务规模进一步扩充,流量进一步暴增,微服务数目进一步增长,使老的微服务体系所采纳的注册核心 Eureka 不堪重负,同时 Spring Cloud 体系曾经演进到第二代,第一代的 Eureka 注册核心曾经不大适宜当初的业务逻辑和规模,同时它目前被 Spring Cloud 官网置于保护模式,将不再向前倒退。如何抉择一个更为优良和实用的注册核心,这个课题就摆在了掌门人的背后。通过对 Alibaba Nacos、HashiCorp Consul 等开源注册核心做了深刻的调研和比拟,最终选定 Alibaba Nacos 做微服务体系 Solar 中的新注册核心。
背景故事
1. 掌门教育微服务面临的挑战
1)第一次生产事变
2020 年疫情暴发后的几个月后,掌门教育的微服务实例数比去年猛增 40%,基础架构部乐观的认为注册核心 Eureka 服务器能够抗住该数量级的实例数规模,Eureka 服务器在阿里云 PROD 环境上执行三台 8C16G 普通型机器三角结构型对等部署,运行了好几年都始终很稳固,但劫难还是在 2020 年 3 月某天早晨来临,当天早晨大略 9 点 30 分左右,其中两台 Eureka 服务器无征兆的 CPU 占用迅速回升到 100%,同时大量业务服务掉线,告警零碎被触发,钉钉机器人告警和邮件告警铺天盖地而来。基础架构部和运维部紧急重启 Eureka 服务器,但没多久,CPU 仍旧没抗住,而且更加来势凶猛,关上的文件描述符数霎时达到 8000+,TCP 连贯达到 1 万 +,业务服务和 Eureka 服务器的通信产生大面积的 TCP CLOSE_WAIT 事件,且伴有大量 Broken pipe 异样。
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
运维人员尝试把机器升级成增强型 8C16G,折腾一番后,于 23:00 左右恢复正常。
2)第二次生产事变
微服务实例数仍旧在增长,Eureka 服务器安稳运行了大略半个月后,劫难又一次来临,CPU 再次飙升到 100%,过程就不表述了。解决形式,把机器升级成增强型 16C32G,并把 Eureka 服务器的版本升级到 Spring Cloud Hoxton 版,并优化了它的一些配置参数,此后事件再也没呈现。
2. 掌门教育新微服务演进思考
尽管 Eureka 服务器目前运行安稳,但咱们仍旧放心此类事变在将来会再次发生,于是痛定思痛,通过深刻的调研和比拟一段时间后,通过由基础架构部牵头,各大业务线负责人和架构师参加的专项注册核心架构评审会上,CTO 拍板,做出决定:抉择落地 Alibaba Nacos 作为掌门教育的新注册核心。
Talk is cheap,show me the solution。基础架构部说干就干,Nacos 部署到 FAT 环境后,打头阵的是测试组的同学,对 Nacos 做全方位的性能和性能测试,毕竟 Nacos 是阿里巴巴拳头开源产品,迭代了 2 年多,在不少互联网型和传统型公司都曾经落地,咱们抉择了稳固的 1.2.1 版本,得出结论是性能稳固,性能上佳,对于性能和性能方面的相干数据,具体参考:《掌门 1 对 1 微服务体系 Solar | 阿里巴巴 Nacos 企业级落地下篇》。
然而,如何迁徙 Eureka 上的业务服务到 Nacos 上?业务服务实例数目泛滥,迁徙工作量微小,须要全公司业务部门配合,同时 Eureka 对注册的业务服务名大小写不敏感,而 Nacos 对注册的业务服务名大小写敏感,那么对于业务服务名不标准的业务部门须要革新。而对于基础架构部来说,Nacos Eureka Sync 计划如同一座大山横亘在咱们背后,是首先须要迈过去的坎,纵观整个过程,该计划选型还是折腾了一番,具体参考:《掌门 1 对 1 微服务体系 Solar | 阿里巴巴 Nacos 企业级落地中篇》。
阿里巴巴 Nacos 企业级落地的优化代码,在不久的未来会通过开源的形式回馈给业界。
官网介绍
1. Nacos 简介
阿里巴巴中间件部门开发的新一代集服务注册发现核心和配置核心为一体的中间件。它是构建以“服务”为核心的古代利用架构 (例如微服务范式、云原生范式) 的服务基础设施,反对简直所有支流类型的“服务”的发现、配置和治理,更麻利和容易地构建、交付和治理微服务平台。
- Nacos Landscape
- Nacos Map
摘自官网 What is Nacos:https://nacos.io/en-us/docs/what-is-nacos.html
2. Spring Cloud Alibaba 简介
阿里巴巴中间件部门开发的 Spring Cloud 加强套件,致力于提供微服务开发的一站式解决方案。此我的项目蕴含开发分布式应用微服务的必须组件,不便开发者通过 Spring Cloud 编程模型轻松应用这些组件来开发分布式应用服务。依靠 Spring Cloud Alibaba,您只须要增加一些注解和大量配置,就能够将 Spring Cloud 利用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用零碎。
摘自官网 Spring Cloud Alibaba Introduction:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-docs/src/main/asciidoc-zh/introduction.adoc
对于 Nacos 和 Spring Cloud Alibaba 如何应用,它的技术实现原理怎么等,官网文档或者民间博客、公众号文章等能够提供十分详尽且有价值的资料,这些不在本文的探讨范畴内,就不一一赘述。笔者尝试联合掌门教育现有的技术栈以及中间件一体化的策略,并着眼于弱小的 Nacos 和 Spring Cloud Alibaba 技术生态圈开展阐释。
Nacos 开发篇
1. Nacos Server 落地
1)Nacos Server
- Nacos Server 环境和域名
掌门的应用环境分为 4 套,DEV | FAT | UAT | PROD 别离对应开发、测试、准生产环境、生产环境,因而 Nacos Server 也分为 4 套独立环境。除了 DEV 环境是单机部署外,其余是集群形式部署。对外均以域名形式拜访,包含 SDK 形式连贯 Nacos Server 和拜访 Nacos Server Dashboard 控制台页面。
- Nacos Server 环境隔离和调用隔离
Nacos Server 能够创立不同的命名空间,做到同一个应用环境的根底上更细粒度的划分,隔离服务注册和发现。在某些场景下,开发本地有须要连贯测试环境的 Nacos Server,但其余测试服务不能调用到开发本地,这时候能够将 NacosDiscoveryProperties 的 enabled 属性设置为 false。
- Nacos Server 集成 Ldap
Nacos Server Dashboard 集成公司的 Ldap 服务,并在用户首次登录时记录用户信息。
2)Nacos Server 界面
- Nacos 界面权限
Nacos Server Dashboard 用户首次登陆时,默认调配普通用户(即非 ROLE_ADMIN)角色,对查问以外的按钮均无操作权限,免得呈现误操作导致服务非正常高低线。
- Nacos 界面显示服务概览
Nacos Server Dashboard 页面减少服务总数及实例总数的统计,该信息每 5 秒刷新一次。
3)Nacos 监控
【Nacos Server 监控】
- 规范监控
基于公司现有的 Prometheus、Grafana、AlertManager 从零碎层监控 Nacos。
- 高级监控
依据 Nacos 监控手册,联合 Prometheus 和 Grafana 监控 Nacos 指标。
【Nacos Eureka Sync Etcd 监控】
从如下界面能够监控到,业务服务列表是否在同步服务的集群上出现一致性 Hash 平衡散布。
4)Nacos 日志
- 日志合并及 JSON 格式化
将 Nacos 多模块的日志对立按 info、warn、error 级别合并,定义 schema 字段标记不同模块,按 JSON 格局滚动输入到文件,供 ELK 采集展现。
5)Nacos 告警
【Nacos Server 告警】
- 业务服务高低线的告警
- Nacos Eureka Sync 告警
- 服务名大写告警
- 业务服务同步结束告警
2. Nacos Client 落地
1)Solar Nacos SDK 环境初始化
利用接入 Solar Nacos SDK 在启动时须要初始化实现 Nacos Server 的连贯配置,即 spring.cloud.nacos.discovery.server-addr 参数的赋值。不同环境下连贯的 Nacos Server,因而须要读取机器所在的 env 环境参数,来抉择绝对应的 Nacos Server 地址。
初始化逻辑代码如下:
public class NacosClientConfigApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {private static final Logger logger = LoggerFactory.getLogger(NacosClientConfigApplicationContextInitializer.class);
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
try {Properties props = new Properties();
String path = isOSWindows() ? CommonConstant.SERVER_PROPERTIES_WINDOWS : CommonConstant.SERVER_PROPERTIES_LINUX;
File file = new File(path);
if (file.exists() && file.canRead()) {FileInputStream fis = new FileInputStream(file);
if (fis != null) {
try {props.load(new InputStreamReader(fis, Charset.defaultCharset()));
} finally {fis.close();
}
}
}
String env = System.getProperty("env");
if (!isBlank(env)) {env = env.trim().toLowerCase();} else {env = System.getenv("ENV");
if (!isBlank(env)) {env = env.trim().toLowerCase();} else {env = props.getProperty("env");
if (!isBlank(env)) {env = env.trim();
} else {env = NacosEnv.DEV.getCode();
}
}
}
String serverAddr = NacosEnv.getValueByCode(env);
Map<String, Object> nacosClientPropertySource = new HashMap<>();
nacosClientPropertySource.put(CommonConstant.NACOS_DISCOVERY_SERVER_ADDR, serverAddr);
applicationContext.getEnvironment().getPropertySources().addLast(new MapPropertySource("solarNacosClientPropertySource", nacosClientPropertySource));
} catch (Exception e) {logger.error(e.getMessage());
}
}
@Override
public int getOrder() {return Ordered.LOWEST_PRECEDENCE;}
private boolean isOSWindows() {String osName = System.getProperty("os.name");
return !isBlank(osName) && osName.startsWith("Windows");
}
private boolean isBlank(String str) {return Strings.nullToEmpty(str).trim().isEmpty();
}
}
2)Solar Nacos 蓝绿灰度公布和子环境隔离
在 Nacos 和 Eureka 双注册核心过渡状态下,Solar SDK 反对跨注册核心调用的蓝绿灰度公布和子环境性能。上面的图片,只以 Eureka 为例:
咱们只须要把 Eureka SDK 换到 Nacos SDK 即可,实现如下性能:
-
Solar 蓝绿灰度公布
- 版本匹配灰度公布
- 版本权重灰度公布
-
Solar 多区域路由
- 区域匹配灰度路由
- 区域权重灰度路由
-
Solar 子环境隔离
- 环境隔离
- 环境路由
-
Solar 版本号和区域值,子环境号策略
- DEV 环境,Git 插件主动创立灰度版本号
- DevOps 环境设置
Solar 蓝绿灰度公布架构图:
Solar 基于版本维度的蓝绿灰度公布架构图:
Solar 子环境隔离架构图:
更多功能参考:
掌门 1 对 1 微服务体系 Solar 第 1 弹:全链路灰度蓝绿公布智能化实际,掌门教育曾经实现通过灰度蓝绿公布形式,实现对流量的准确制导和调拨。
Nepxion Discovery 开源社区:https://github.com/Nepxion/Discovery
3)Solar Nacos 集成 Sentinel
4)Solar Nacos 集成灰度蓝绿埋点到 Skywalking
5)Solar Nacos 集成 Sentinel 埋点到 Skywalking
- 微服务上的 Sentinel 埋点
- 网关上的 Sentinel 埋点
6)Solar Nacos 集成 DevOps 公布平台
- 集成携程 VI Cornerstone 实现服务拉入拉出
Solar Nacos SDK 的服务,在利用公布时须要做服务的拉入拉出,目标是为了公布时流量无损。掌门应用 VI Cornerstone 实现拉入拉出性能。具体实现是在初始化 NacosDiscoveryProperties 对象时设置 instance.enabled 属性值为 false,在服务齐全初始化后,通过公布零碎调用 Solar Nacos SDK 的 API 接口再批改为 true 来被内部发现并提供服务。
public class NacosApplicationContextInitializer implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironment, SpringApplication springApplication) {Boolean bootstrapEnabled = configurableEnvironment.getProperty("devops.enabled", Boolean.class, false);
if (bootstrapEnabled) {Properties properties = new Properties();
properties.put("spring.cloud.nacos.discovery.instanceEnabled", "false");
PropertiesPropertySource propertiesPropertySource = new PropertiesPropertySource("devopsEnabledNacosDiscoveryProperties", properties);
MutablePropertySources mutablePropertySources = configurableEnvironment.getPropertySources();
mutablePropertySources.addFirst(propertiesPropertySource);
}
}
}
spring.factories 配置文件:
org.springframework.boot.env.EnvironmentPostProcessor=\
com.ctrip.framework.cs.spring.NacosApplicationContextInitializer
7)Solar Nacos SDK 接入
【Solar 版本定义】
- Solar 2.3.x & 1.3.x,基于 Nacos SDK
- Solar 2.2.x & 1.2.x,基于 Eureka SDK
【Solar 版本关系】
- Solar 版本与 Spring Boot 技术栈的关系
- Solar 版本与注册核心的关系
【Solar SDK 接入】
- 设置 Parent
<parent>
<groupId>com.zhangmen</groupId>
<artifactId>solar-parent</artifactId>
<version>${solar.version}</version>
</parent>
- 增加到 pom.xml
只需引入一个 Jar 包,对接老本极低,只做根本组件封装,十分轻量级。
微服务:
<dependency>
<groupId>com.zhangmen</groupId>
<artifactId>solar-framework-starter-service</artifactId>
<version>${solar.version}</version>
</dependency>
网关:
<dependency>
<groupId>com.zhangmen</groupId>
<artifactId>solar-framework-starter-zuul</artifactId>
<version>${solar.version}</version>
</dependency>
- 入口类增加注解
@EnableSolarService,@EnableSolarZuul 封装了规范 Spring Boot / Spring Cloud / Apollo 等大量注解,升高业务的应用老本。
微服务:
@EnableSolarService
public class DemoApplication {public static void main(String[] args) {new SpringApplicationBuilder(DemoApplication.class).run(args);
}
}
网关:
@EnableSolarZuul
public class DemoApplication {public static void main(String[] args) {new SpringApplicationBuilder(DemoApplication.class).run(args);
}
}
8)Solar Nacos SDK 和 Solar Eureka SDK 降级和回滚
降级和回滚计划非常简单,此形式同时实用于网关和服务,见下图:
作者信息
吴毅挺,掌门技术副总裁,负责技术中台和少儿技术团队。曾就任于百度、eBay、携程,曾任携程高级研发总监,负责从零打造携程公有云、容器云、桌面云和 PaaS 平台。
任浩军,掌门基础架构部负责人。曾就任于安全银行、万达、惠普,曾负责安全银行平台架构部 PaaS 平台 Halo 根底服务框架研发。10 多年开源经验,Github ID:@HaojunRen,Nepxion 开源社区创始人,Nacos Group Member,Spring Cloud Alibaba & Nacos & Sentinel & OpenTracing Committer。
参加 Nacos 落地的基础架构部成员,包含:童子龙,张彬彬,廖梦鸽,张金星,胡振建,谢璐,谢庆芳,伊安娜
“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术畛域、聚焦云原生风行技术趋势、云原生大规模的落地实际,做最懂云原生开发者的公众号。”