作者 | 殷铭  颜铺科技架构师

本文整理自架构师成长系列 3 月 19 日直播课程。

关注“阿里巴巴云原生”公众号,回复 “319”,即可获取对应直播回放链接及 PPT 下载链接。

导读:颜铺科技因美业⽽⽣,“颜铺专家”是一款专为美业商家打造的 SaaS 平台,为了能够给商户提供更加安全、稳定、高效的平台,我们在技术方面做了很多尝试,经过几次演进,使系统变得更加稳定可靠。今天主要和大家分享一下颜铺科技的架构演进,以及 Nacos 在颜铺的应用实践。

单体应用时代

上图是我们单体服务时的架构图,分为会员、订单、门店等很多模块,看架构图似乎还算清晰,但是真正看到包结构的时候,真的令人头秃!改起代码特别头痛。单体服务带来的几个挑战:

  • 发布周期慢:虽然当时业务量不算大,但是代码量很大,业务迭代牵一发而动全身,每次发布需要对整个服务进行重新编译打包部署。特别是最开始在没有构建工具的时候,发布过程需要一堆的命令,总有一种 **“一顿操作猛如虎,定睛一看原地杵” **的感觉。

  • 协同效率低:合并冲突多,有时你在前面开心地写代码,而别人在解决冲突时,可能也在开心地删着你的代码,增加了很多的沟通成本。

  • 稳定性差:当服务出现故障时,可能会导致整个系统不可用,并且系统不易扩容,当商户搞促销时,可能活动结束了,服务器还没有扩容完成。

  • 性能差:因为在单体服务内,有些开发人员为了满足自己的业务,很多无关业务间 SQL 联表查询,并且不关注性能问题,导致线上时常出现负载警告。

另外,我们在业务上也遇到了一些挑战:

  • **业务转型: **2018 年 6 月,我们公司决定从泛行业转向美业,需要打造一个专为美业商户提供技术支持的丽人 SaaS 平台。

  • 快速占领市场:业务的转型带来了更多商户的新需求,如果不能快速迭代,则意味着被市场淘汰。因此,提升开发效率,快速占领市场成为我们急需解决的问题。

  • 商户体验差:随着越来越多的商户入住,性能和可靠性的问题逐渐显现,出现问题,不能及时修正,商户体验变得很差,违背我们客户第一的原则。

综上所述,我们认为进行服务化改造刻不容缓。

微服务改造

经过公司开发同学们的讨论,我们最终决定分两步进行改造:

服务化改造 1.0 的目标:

  • 用最小的改造成本先将新、旧商户平台进行打通,做到功能上的快速迁移;
  • 业务抽象,将新旧商户中心的公用部分进行抽象,并优化旧商户中心的代码逻辑,为后续的业务中台建设做好铺垫。

服务化改造 2.0 的目标:初步建设业务中台,让平台的各种能力能够快速复用、快速组合,支持业务更快捷地探索与发展。

服务化改造 1.0 预期效果:

  • 我们希望老商户中心在对外提供服务的同时,还能够作为提供者,对新商户中心提供服务支持;
  • 新商户中心仅对外提供服务,不直连数据库,业务层只对美业的特殊逻辑进行处理。

因此,我们的想法是:新商户中心直接调用旧商户中心通过 Controller 暴露出的接口,进行远程调用,于是我们决定尝试使用 Spring Cloud 。

服务发现选型:

  • Consul 支持服务发现的同时,支持 kv 存储服务,因为我们想做一个配置中心的 KV 存储,所以想利用 Consul 做一个尝试;
  • 服务健康检查相对更为详细;
  • 在我们选型的期间,突然出现了 Eureka 2.x 开源工作宣告停止的消息,虽然后来发现,这个对我们并没有什么太大的影响,但在当时的决策让我们最终选择了 Consul 。

服务化改造 1.0 架构图:

服务化 1.0 我们的技术改造方案是:将旧的商户中心注册到 Consul 上面,新商户中心到 Consul 上获取服务器列表,通过 Feign 进行远程调用,打通了新老商户中心的功能。

经过服务化 1.0 的改造,我们解决了如下几个问题:

  • 功能快速完善:旧商户中心的功能快速迁移到了新的商户中心,并完成对美业的适配;
  • 迭代速度加快:新商户中心大部分功能,能够通过旧商户中心进行修改兼容,为后续的业务中台的抽象打好基础;
  • 性能优化:业务开发的同时,我们对旧商户中心的老代码进行优化,性能和稳定性均有所提高。

但服务化 1.0 改造后,还是有一些挑战没有解决:

  • 发布周期依旧不够快:大部分代码还是在就商户中心,业务迭代依然牵一发而动全身;
  • 协同效率没有提高:在代码冲突多,沟通成本高的同时,又出现了令开发同学头痛的新老业务的兼容问题;
  • 维护成本:Consul 是 Go 语言开发的,不易维护;Spring Cloud 在开发过程中体验不佳,在写业务的同时,还要摸索 Spring Cloud 的最佳实践,花费了一些时间去做 Spring Cloud 的基础建设。

于是我们决定开启,服务化 2.0 的改造。

服务化改造 2.0 的预期效果:

  • 完成业务中台的初步建设,将模块重新划分,抽象为独立服务;
  • 新、旧商户中心服务仅做自己的业务兼容,并对外暴露接口;
  • 新增专门支持 H5、小程序 的 C 端 WEB 服务。 因 Spring Cloud 体验不佳,我们决定服务化改造 2.0 尝试使用 Dubbo 作为基础服务的 RPC 远程调用框架,因此我们要对注册中心进行选型。

首先,注册中心我认为应该具备的基本功能 :

  • 服务注册及时被发现,异常时的及时下线;
  • 服务管理,能够手动恢复/剔除服务;
  • 健康检查,检测服务是否可用;
  • 元数据管理;
  • 注册中心保证自身的高可用。

Zookeeper :

  • 不能保证每次服务请求都是可达的,当 zk 集群 master 挂掉时,需要进行选举,在选举期间中,服务是不可用的;
  • 不支持跨机房的路由,比如 eureka 的 zone,当前机房不可用时,可以路由到其他机房;
  • “惊群效应”, zk 的节点过多的时候,当 service 的节点发生变更,会同时通知到客户端,瞬时流量有可能将网卡瞬间打满,并且会有重复通知的问题。

Nacos :

  • 注册中心部分更侧重于可用性
  • 服务发现与服务管理
  • 服务元数据的管理
  • 动态配置管理

在此期间,我们也关注到了 Spring Cloud Alibaba。阿里巴巴技术经受多年“双十一”的考验,其性能和稳定性是值得信任的。Spring Cloud Alibaba 的组件开源社区活跃度很高,并且比起国外开源项目更容易交流。其组件由 Java 语言开发,对我们来说更易维护,在出现问题时能够更快地定位问题进行修复。而且与阿里云配合,更加容易上云,比如 Nacos 可以与阿里云的 MSE 和 ACM 配合,将注册中心及配置管理全部上云。 

因此,我们决定拥抱阿里技术栈。

服务化改造2.0架构图:

我们将之前的模块直接抽到基础服务之中,新增了 会员、订单、门店 等服务作为Provider,暴露自己的Service,并注册到 Nacos 上。新商户中心服务做美业业务逻辑的处理,旧商户中心服务做泛行业的业务处理,C端服务同理对外提供服务。通过 Dubbo 进行远程调用。

通过服务化 2.0 的改造,效果如下:

  • 服务器成本降低30%:20+台服务器,由4核16G 降配到2核8G;
  • 系统可靠性提升80%:load 告警明显减少,线上的问题修正能够快速修复,完成部署;
  • 代码冲突减少75%:因为边界有了基本各自维护,冲突显著减少;
  • 发布迭代效率提升50%:之前5个人每个迭代开发评估可完成30个点,现在可完成45个点左右。

Nacos 落地实践与问题分析

Nacos 在我们公司处理做注册中心之外,配置管理也对我们提供了很好的服务。下面说一下,Nacos 我们的使用情况,以及我们遇到的问题。

首先是使用情况:

  • 部署方式:开发/测试环境单机部署,生产环境 3 台集群部署;
  • 版本:生产环境从 0.9.0 开始使用,目前生产环境使用的版本为 1.1.4 ;
  • 使用时间:2019 年 3 月份开始在生产环境下使用;
  • 服务数量:线上 20+ 台服务器,提供了 600+ 个服务;
  • 稳定性:一年的时间里没有出现大的问题,并且平滑升级;
  • 兼容性:新老服务,在我们公司无论是 Spring 4.3+ 的工程,还是 Spring Boot 的工程均兼容良好。

Nacos 注册中心:

  • 服务注册:将后端服务注册到 Nacos,通过 Dubbo 进行调用。目前开发环境中我们正在测试Seata,并且也将 Seata 服务注册到 Nacos 上;
  • Namespace:服务统一注册到 public 中。

Nacos 配置管理:

每个服务设置独立的 Namespace 。

  • 服务的配置文件信息:application.properties 全部配置到 Nacos,工程的配置文件仅保留 Nacos 相关配置;
  • 业务层的 KV 配置:比如业务开关,属性默认值,定时任务配置等;
  • MQ Topic 的动态配置:Binlog 服务采集动态发送到在 Nacos 配置的 topic 及其需要的表信息;
  • Sentinel 的规则配置:Sentinel 限流规则持久化到 Nacos 。

问题描述:

2019 年 12 月 31 日,下午 3 点 15 分左右,线上突然出现大量服务告警,Dubbo 服务出现报错,整个过程持续约 3 多分钟。各个业务组当天均没有任何发布,数据库状态也良好。

通过日志发现,报错原因是门店服务无法调用。而门店服务日志,出现问题的时间段内,没有任何的调用记录。系统恢复正常时,出现了很多服务注册的通知。

因此,我们将问题瞄准了 Nacos。查看 Nacos 的日志发现,在系统恢复过程中,有大量的服务正在上线。

就在排查的过程中,线上突然又出现了之前相同的告警,Nacos 上的服务列表开始大量变成不健康的状态,于是我们紧急重启了线上的 Nacos ,在这期间又经历了一个 3 分多钟的惊魂后,再次恢复了平静。

问题分析:

  • 两次出现的问题均是门店服务,但出现问题期间 JVM 和数据库的运行状态均良好;
  • 报错信息都是 Dubbo 调用超时,且出现问题期间,门店服务没有任何流量进入;
  • 出现问题时,注册在 Nacos 上的服务开始大量不健康。恢复正常时,这些服务又开始上线,说明出现问题时,服务被下线又重新上线。

综上,我们开始怀疑是网络原因造成的。

问题确认:

经过排查,发现我们的服务大多部署在 阿里云华东 1 可用区 B ,只有门店服务和 Nacos 集群没有部署在可用区 B ,说明这段时间可用区 B 与其他区之间的发生了网络隔离。

于是,我们在可用区 B 紧急部署了门店服务,之后没有再出现问题。

经过与阿里云的沟通确认于北京时间 2019 年 12 月 31 日 14:05 分左右开始,部分用户反馈阿里云华东 1 地域可用区 B 部分网络出现异常,影响部分云资源访问。

问题复盘:

  • 问题出现:下午 3 点多,突然连续出现的服务告警, Dubbo 服务出现报错;
  • Nacos:Nacos 服务列表里大量服务出现不健康的状态;
  • 网络不通:可用区 B 与其它区网络不通,导致服务无法调用;
  • 紧急部署:在 B 区部署缺失的 门店服务;
  • 恢复正常。

问题思考:

  • 服务部署:应用服务和Nacos建议多机房部署,即使在云上可用区之间也需要考虑;
  • 容灾:问题出现时,可用区 B 并没有部署 Nacos,但可用区B内的服务之间依然能调通,且能够读到 Nacos 上的配置。因此,我们认为 Nacos 以及 Dubbo 的容灾策略都是值得信赖的。

回顾与展望:

“颜铺专家”经过不断地快速迭代,帮助美业商家⾼效快捷地管理门店,进行经营数据分析,数据化管理门店,建⽴完善的会员周期管理体系,为美业商家在经营管理中,提供⼀体化的解决方案,将美业传统的门店经营模式进⾏互联网升级。截止到目前我们累计服务 3000 多个品牌,1.1W + 个⻔店。我们提供了店务管理系统、会员管理系统、营销拓客系统、大数据决策系统、供应链管理系统、员工绩效管理系统6⼤系统能力,同时⽀持 PC 端、手机 APP 、 pos 机、 iPad 操作,满⾜⻔店多端操作需求,覆盖⻔店经营管理中的所有场景需求。

未来规划

提升系统高可用

  • Seata :目前我们公司的分布式事务主要依赖 MQ 的补偿,今年准备引入 Seata 来完善分布式事务,保证数据一致性,减少开发修数据的情况;

  • Sentinel :目前 Sentinel 我们只是在商户做活动时启用,因此我们要配置出适用于我们公司的最佳实践,保证系统的高可用;

  • 全链路跟踪:我们公司现在定位问题主要靠日志和告警,做不到全链路的跟踪,所以我们要把这部分做好,做到故障快速定位,各调用环节性能分析,以及数据分析;

  • 异地容灾:随着来自全国各省的商户越来越多,我们需要对商户的数据保障,避免数据丢失,确保服务的可靠性。

社区回馈

因为我们的公司体量现在不大,我们能够做到的是尽可能地使用最新的版本,及时尝试新特性,对发现的问题提 issues,但我们也希望能够对 Nacos 开源社区尽一份我们的力量。

作者信息:殷铭,颜铺科技架构师,负责颜铺 SAAS 平台中间件的应用和实践,主导了平台架构在颜铺向分布式演进的全过程,目前也负责大数据在颜铺平台的实践和落地。

阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的公众号。”

构建安全可靠的微服务 | Nacos 在颜铺 SaaS 平台的应用实践的更多相关文章

  1. 深入解析DC/OS 1.8 – 高可靠的微服务及大数据管理平台

    深入解析DC/OS 1.8 – 高可靠的微服务及大数据管理平台 大家好,欢迎大家参加这次DC/OS的技术分享. 先做个自我介绍,刘超,Linker Networks首席架构师,Open DC/OS社区 ...

  2. [转] Akka实战:构建REST风格的微服务

    [From] http://www.yangbajing.me/2015/11/27/akka%E5%AE%9E%E6%88%98%EF%BC%9A%E6%9E%84%E5%BB%BArest%E9% ...

  3. 在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务

    在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务 https://procodeguide.com/programming/polly-in-aspnet-core ...

  4. 微服务nacos服务注册与发现

    一,以上一篇为基础 微服务从nacos配置中心获得配置信息 给service1, service2添加依赖 <dependency> <groupId>com.alibaba. ...

  5. 【分布式微服务企业快速架构】SpringCloud分布式、微服务、云架构快速开发平台源码

    鸿鹄云架构[系统管理平台]是一个大型 企业.分布式.微服务.云架构的JavaEE体系快速研发平台,基于 模块化.微服务化.原子化.热部署的设计思想,使用成熟领先的无商业限制的主流开源技术 (Sprin ...

  6. 基于.net的微服务架构下的开发测试环境运维实践

    眼下,做互联网应用,最火的架构是微服务,最热的研发管理就是DevOps, 没有之一.微服务.DevOps已经被大量应用,它们已经像传说中的那样,可以无所不能.特来电云平台,通过近两年多的实践,发现完全 ...

  7. 如何在Python中使用ZeroMQ和Docker构建微服务架构

    @Container容器技术大会将于6月4日在上海光大会展中心国际大酒店举办,来自携程.PPTV.蚂蚁金服.京东.浙江移动.海尔电器.唯品会.eBay.道富银行.麻袋理财等公司的技术负责人将带来实践经 ...

  8. 用Helm3构建多层微服务

    Helm是一款非常流行的k8s包管理工具.以前就一直想用它,但看到它产生的文件比k8s要复杂许多,就一直犹豫,不知道它的好处能不能抵消掉它的复杂度.但如果不用,而是用Kubectl来进行调式真的很麻烦 ...

  9. Spring Cloud Alibaba学习笔记(12) - 使用Spring Cloud Stream 构建消息驱动微服务

    什么是Spring Cloud Stream 一个用于构建消息驱动的微服务的框架 应用程序通过 inputs 或者 outputs 来与 Spring Cloud Stream 中binder 交互, ...

随机推荐

  1. 第二章 表与指针Pro SQL Server Internal (Dmitri Korotkev)

    聚集索引 聚集索引就是表中数据的物理顺序,它是按照聚集索引分类的.表只能定义一个聚集索引. 如果你要在一个有数据的堆表中创建一个聚集索引,如2-5所示,第一步要做的就是SQL服务器创建另一个根据聚集索 ...

  2. GO - if判断,for循环,switch语句,数组的使用

    1.if - else if - else的使用 package main import "fmt" func main() { // 1.简单使用 var a=10 if a== ...

  3. springboot 解决实体类值为null或者数组为空,不返回前台

    一个注解解决问题 @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_NULL)

  4. 关于HTTP那些事

    写这篇文章的原因 记录前端性能优化用到的关键概念 简化大家对HTTP的学习 大家或许面试的时候可以用得到哦 HTTP是什么 Web的应用层协议(超文本传输协议HyperText Transfer Pr ...

  5. Canvas 使用及应用

    Canvas canvas 是 HTML5 当中我最喜欢的所有新特性中我最喜欢的一个标签了.因为它太强大了,各种有意思的特效都可以实现. 1. canvas 的基本使用方法 - 它是一个行内块元素 - ...

  6. vue+element 表单封成组件(1)

    作为一名刚接触vue不到一个月的菜鸟,思想还没有从操作DOM转变为数据驱动,看vue的代码处处别扭.组里为了让我熟悉vue交给了我一个将element 表单封装成组件的练手任务.由于开发过程中遇到的表 ...

  7. JZOJ 1492. 烤饼干

    1492. 烤饼干 (Standard IO) Description NOIP烤饼干时两面都要烤,而且一次可以烤R(1<=R<=10)行C(1<=C<=10000)列个饼干, ...

  8. Flutter的盒子约束

    由Expanded widget引发的思考 设计稿如下 布局widget分解 很常见的一种布局方式:Column的子widget中包含ListView @override Widget build(B ...

  9. 内网渗透之信息收集-Linux系统篇

    linux 系统信息 grep MenTotal /proc/meminfo #查看系统内存总量 cat /etc/issue #查看系统名称 cat /etc/lsb-release #查看系统名称 ...

  10. 痞子衡嵌入式:恩智浦SDK驱动代码风格、模板、检查工具

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是恩智浦 SDK 驱动的代码风格. 上周痞子衡受领导指示,给 SE 同事做了一个关于 SDK 代码风格的分享.随着组内新人的增多,这样的培训 ...