支撑 “千万设备日活” 的创米数联 7 年微服务架构演进之路

作者:金兆旭 上海创米数联智能科技发展股份有限公司云服务开发及 SRE 工程师 负责公司云端基础设施构建及消息网关等研发工作;十眠

创米数联是小米生态链首批亿元俱乐部成员,主营业务为智能家居产品的研发、设计、生产和销售,致力于成为以居家安全为核心的产品和服务提供商,提供多品类的全屋智能家居产品及服务。公司以居家安全为核心,洞察用户在居住环境下的智能化需求,建立物理安全、环境安全、系统安全三类场景及服务体系,主要产品包括智能摄像机、智慧门、智能猫眼、智能门铃、智能插座等。公司旨在实现“看得见的全屋智能”,以智能家庭安全为切入点,提供多品类覆盖的智能家居解决方案。截至 2021 年 12 月 31 日,创米数联已经在全世界 150 多个国家,销售了超过 5500 万台设备,拥有了 1600 万设备和 500 万设备用户日活。

作为小米生态链的一员,创米采用微服务架构支撑其千万日活的 IOT 设备。随着智能家居市场的快速迭代,创米面临着发布和迭代的稳定性挑战,同时需要解决多方 IOT 接入面临的性能和安全挑战。本文将为您一一道来创米是如何应对这些挑战的。

云计算时代的蹒跚学步

创米云服务从 2016 年创始之初就选择了云计算+微服务的技术路线,以应对面临的大量线上用户和设备带来的流量挑战。构建微服务之初,市面上可选用的解决方案并不多,我们自主实现了一些微服务组件,如 frontend 业务网关和配置中心,并在小米生态云上部署容器服务来处理设备消息、设备插件 API 和微信公众号等相关业务,并利用 HPA 及 CronHPA 等容器弹性伸缩策略来应对动态的海量线上流量。

image.png

自此创米数联在云计算时代踏上了探索服务容器化的第一步。

新业务及新挑战

从 2019 年伊始,创米数联提出了研发自有 APP 和适配自有 APP 的智能家居设备的发展战略。云服务部将研发重心转向自有 APP 云端业务,并逐步接入自有品牌设备。为了实现全球业务,创米云服务部将相关服务部署在阿里云的 4 个 Region 的 ACK Pro 专有版 Kubernetes 集群上。阿里云 ACK 为创米云提供了可靠稳定的基础设施,向下封装好的数十款云产品,降低了云端运维人员的运维压力,快速对接其他云产品的能力也对开发人员十分友好,能够让创米云服务在极短的时间内搭建一套线上可用的环境。

在自有业务研发开始阶段,我们选择了 Spring Cloud、Eureka 和 Apollo 等技术栈来搭建我们的微服务基础架构。然而,经过一年半的摸索,我们发现当前的混合架构存在着不稳定、上线部署风险大以及高人力维护成本等问题。

因此,从 2021 年开始,创米云服务决定改变现有的微服务架构,逐步拥抱云原生。我们的目标是在满足稳定性和低维护成本等需求的基础上,实现所有组件的可观测性、全链路的流量治理以及更加便捷高效的 DevOps 流程。

云原生体系探索

首先我们将当前的 Spring Cloud 体系全面转向 Spring Cloud Alibaba,使用 Nacos 替换 Eureka,以解决 Eureka 服务端压力过大的问题,并满足单注册中心多环境分组的需求。由于 Apollo 在某些情况下存在容器磁盘压力大的问题,我们逐步将配置中心从 Apollo 替换为 Nacos。针对之前定制化的 Apollo 配置同步和本地特殊配置缓存,同样我们也对 Nacos 客户端进行了部分定制化改造。

image.png

初版上线时,考虑到注册中心和配置中心的高可用性、热升级、成本、可观测配套等因素,我们没有选择自建有状态的开源 Nacos 服务,而是直接使用了阿里云 MSE Nacos 专业版服务。至今,该服务一直稳定运行,没有出现可用性问题。

全链路流量治理

针对全链路的流量治理,由于创米云服务所处的 AIoT 行业不同于传统互联网行业,我们在南北向流量时不仅需要治理下游用户手机端 APP 及 Web 端的 HTTP 请求,还需要处理来自设备端的 MQTT、第三方 AMQP 和 HTTP 2 长连接 Push 消息的流量治理。这些消息通常经由统一的上游消息网关(消息总线)监听,经过多级过滤器,如消息来源、消息限流和产品或特定设备级别的白名单等,对消息进行分类和打标签,然后对消息 Topic 正则路由并进行 HTTP 异步或 rpc 请求。只有经过这些请求后,我们才能对其进行流量治理。

image

因此,创米云服务的流量治理整体较为复杂。我们曾考虑过采用侵入式代码和自定义负载均衡器,并开发控制台来实现高度自定义的流量方案。我们还考虑过使用 Istio Service Mesh 的方案治理流量。然而,前者在当前百万级别设备消息的情况下性能严重受限,后者由于设备消息链路较长、打标较多,导致实现全链路灰度时配置文件实现较为复杂,而且 Envoy 代理无法完整拦截消息总线请求等问题,因此我们否定了这两种方案。之后在选型过程中,我们采用了 MSE 微服务治理。

我们传统的 API 业务流量治理选用了多域名、多租户环境、节点隔离加多业务网关的方案配合 MSE 微服务治理来实现多个环境服务的测试开发及线上灰度部署。我们使用多域名加 DNS 流量划分的方式对服务重构后的业务网关新路由进行测试,保证服务重构后的安全上线。我们利用多个 K8s 集群、K8s namespace 以及多个 namespace 的注册配置中心的隔离构建了不同的线上环境,分别用来线上开发、线上测试、灰度以及基线环境部署。对于同一集群不同 namespace 的应用 pod 使用多集群隔离、应用节点亲和性、反亲和性以及节点污点等集群调度手段保证环境的安全性,避免不同环境间出现的资源异常导致基线环境不可用的情况。基线环境和灰度环境同属不同命名空间的相同节点池内,测试和开发环境应用 pod 部署在不同的 K8s 集群或节点池中。我们的整体流程通常是在 feature 及 bug 修复后涉及的服务在开发环境联调完毕,在每次测试流程前将 feature 服务部署至测试环境,通过蓝绿测试将测试人员的流量导向测试环境,在多轮的覆盖及回归测试完成后,将服务部署至灰度环境,再将测试人员及 Beta 测试用户的流量导向灰度环境,经过一定时间的检验后,逐步将线上基线流量导向灰度环境,灰度环境流量完成 100% 灰度后,替换基线环境镜像,最后逐步将灰度流量倒流至基线环境。

image

在核心业务接入 MSE 微服务治理之后,创米云服务对部分多云部署及老项目通过 DNS 流量切分+全链路灰度的方式进行灰度,逐渐将自有 APP 及自有设备的所有业务重构迁移至新项目中并全部接入 MSE 微服务,实现了云上 API 业务的 100% 安全发布。

在设备消息业务的流量治理的推进过程中,为了解决无法拦截消息请求的问题,我们首先将消息总线拆分为控制器和路由器两部分。控制器监听各个通道的消息后仅对消息进行打标签和分类,然后通过异步 HTTP 请求经由统一的路由器转发到各个服务中。我们将路由器服务定义为流量治理的入口,从而解决了消息无法治理的问题。然后,我们使用统一的全链路灰度对打标签后的 HTTP 请求进行蓝绿和灰度的流量治理,并将其分发到指定的命名空间的指定服务中进行消息处理。

MSE 微服务治理接入非常简单,只需要在 Helm 或组件中心安装 ack-onepilot 组件,重启服务便可自动注入服务,除此之外 MSE 提供了较为友好的全链路灰度配置界面,较 Istio 方案更加易于配置和上手。通过这样的流程,创米云服务成功实现了设备服务的更新、云云设备的对接以及固件 OTA 版本的迭代过程中的安全发布。

无损上下线解决发布扩缩容流量损失问题

image

无损下线逻辑图

在之前的服务发版部署或 pod 弹性伸缩过程中经常会有部分请求出现超时或不可用的情况,由于创米云服务承载了大量的用户设备请求,这些流量损失轻则导致设备消息重试,严重时会影响部分用户设备的可用性,后续我们了解了 MSE 微服务治理提供了无损上下线及服务预热功能,决定将相关服务全部接入了 MSE 微服务治理的无损上下线,并调整对应服务的就绪检查,在后续的服务上下线过程中经观察再未出现因为流量损失导致的请求不可用的情况,一定程度上避免了由部署发布和服务缩容引起的线上流量损失问题。

image.png

新启动 Pod 的预热流量分布

可观测体系

为了实现可观测性,我们早期就将阿里云 SLS 日志服务集成到自有业务框架中。然而,我们遇到了业务索引不规范、唯一 RequestId 索引异步丢失以及 Spring Cloud Gateway 等 Reactive 框架应用日志异步写入 Location 导致 CPU 占用过高等问题。因此,我们对当前的日志规范进行了改进,并在多个链路追踪方案中选择了 Skywalking。我们将 Skywalking 的 TraceId 写入 SLS 日志索引中,并通过对 ThreadLocal 的改造实现了异步线程的日志索引信息传递。我们的服务挂载了 Skywalking Agent,并自定义了可选插件,然后接入了阿里云链路追踪服务。相比自建 ElasticSearch 集群,阿里云链路追踪服务更经济实惠且免维护,链路追踪服务可以直接将项目关联到指定的 SLS logstore 中,更方便进行链路问题排查。在上线的第一个月里,链路追踪服务帮助我们解决了多个项目中的接口性能问题。

创米云服务的指标信息的观测主要依赖于 ARMS ACK、ARMS ACK Pro、ARMS 云服务等多个开箱可用的 Grafana Dashboard,它们提供了相当完善的集群、Node、Pod 等多个维度的指标信息,除此之外我们依然会使用阿里云云监控或自定义一些 Grafana Dashboard 用来关注其他部分指标。创米云服务为了快速预警,设置了云产品、SLS 日志、K8s 事件等多个维度的告警配置,对报警进行降噪调优,根据告警等级设置了电话、短信、邮件和飞书群多个通道的报警通知,建立了相当全面的服务告警体系,以便相关人员及时发现问题,避免线上损失。

CI/CD 提效

早些时候由于多云部署的问题,我们并没有统一的全自动 CI/CD 解决方案,为了解决云端 DevOps 构建部署和上线安全性等问题,我们将所有的 Devops 流程开始全面转向阿里云云效。首先,我们将云服务代码从自建的 Gitlab 完全同步到阿里云 CodeUp 代码库中,并将之前的 Gitlab CI/CD 和 Jenkins 的 CI/CD 方案全部迁移到阿里云云效流水线。我们建立了单 Region、多 Region、多云项目的多条流水线,实现了从代码提交、手动或自动触发构建,到自动部署到指定的 K8s 集群和命名空间的全流程。每次构建和部署完成后,我们会发送飞书通知并调用 Newman 自动化测试脚本的 WebHook,根据自动化测试结果报告,评估每次服务版本发布是否满足安全规范。

稳定性评估与演练

对于线上环境稳定性评估,创米云服务选用了混沌工程的方式来检验服务的可用性,创米云服务根据自身业务对 Java 应用 OOM、缓存击穿、网络延迟、K8s Pod 资源、K8s 系统组件、关键云服务等多个维度对自身环境的服务进行全方位的演练排查,并检验可观测性中告警配置的灵敏度。我们在没有造成线上损失的情况下发现并修复了部分漏洞、完善了多 AZ 的云服务资源的建设、调整了未触发告警的配置,使自身架构更加健壮。在一定程度上帮助创米云服务在及时弥补了在 HA 方面不足,并在后续的架构设计中提出了高可用优先的原则。

未来展望

未来创米云服务将业务网关逐渐转型为云原生网关+WASM 插件方案,代替繁重的 Spring Cloud Gateway 业务网关,进一步提升网关性能、灵活性和可扩展性,并接入现有可观测体系。我们将继续致力于创新和技术升级,为用户提供更优质的产品体验。

posted @ 2023-06-28 16:51  阿里云云原生  阅读(15)  评论(0编辑  收藏  举报