基于SpringCloud微服务的服务平台搭建的一些总结

工作上项目的后台进行微服务改造后已经平稳运行将近1年了,起初项目为若干个单体web应用组成,之后由于上线App,需求的多样性和对于需求的响应速度有了更高的要求,因此为了快速响应需求变化,将后台进行微服务化改造。总的来说,改造初期由于既有系统我都非常熟悉,因此改造和迁移都比较顺利。在微服务架构的帮助下,新接入业务可以更专注于服务的实现,同时各个服务的功能也可以进行快速整合。目前平台的研发告一段落,后期工作可能调整,因此趁有时间把最近一年的改造设计、研发、部署、迁移、运维等各个部分的经验大致整理一下,不说虚的,不列名词,具体代码尽量不说(网上一堆),只说经验与想法。

1. 业务梳理

1.1 切换的基本原则

由于是生产中正在运行的系统,因此有如下几个要求必须满足:

  1. 对于既有的接口定义不能改变,或至少是实现兼容
  2. 系统运行不能长时间中断
  3. 涉及数据结构变化、数据源变化的需要将旧数据转换为新的数据结构转存

1.2 既有系统功能整理

对于既有后台的若干服务的功能和模块进行整理,首先应该梳理出公共功能部分,可以作为独立的服务模块对外提供服务,其次对于其它功能梳理出关键功能(必须切换、必须保证过度、历史数据不能丢失……),对于非关键功能,在时间紧张的时候可以先维持既有系统运行,在微服务平台切换后期再进行研发,并转入新的后台中。

以我现在的项目为例,

1)公共服务包括:

  • 消息服务(短信、钉钉通知)
  • 用户服务(用户认证、用户组、角色管理)
  • 集中式Id生成(SnowFlake等算法具体实现)
  • 通信加解密服务(原系统在每个业务系统中分别实现,新系统中独立为服务)
  • 基础数据服务(平台所需业务无关的基础数据,这里不具体说明是什么)

2)关键服务包括:

  • 目前正在运行的内容管理服务
  • 设备接入服务
  • 网络规则维护服务
  • 消息评论服务
  • 内容采集服务

3)非关键服务包括:

  • 日志采集服务(各服务、设备的日志统一集中在一个服务中处理)
  • 内容采集服务(不切换也不影响既有业务运行)

综上,我们根据梳理的服务类型,优先实现公共服务和关键服务,在合适的时候进行整体迁移。在主体服务迁移完毕,平稳运行后即可进行后续功能的迁移与改造。

1.3 准备迁移方案

系统研发过程中,应充分考虑既有系统的兼容性,并准备好关键数据的转移方案。对于有大量修改的系统和数据,考虑通过兼容接入服务处理旧的应用请求,而新的业务请求直接根据新的数据和逻辑开发。

2. 基础环境搭建

2.1 基础组件部署

在平台改造时,应该充分考虑能力冗余。数据库、缓存、消息队列、分布式文件系统、目录服务、负载均衡、ElasticSearch集群等服务平台的基础组件应该进行资源的合理划分。比如:

  • 对于分布式文件系统、数据库、消息队列、ElasticSearch数据节点等部署的服务器应充分考虑:磁盘空间、磁盘挂载配置、磁盘阵列配置等
  • 对于缓存、负载均衡、目录服务、ElasticSearch计算节点等部署服务器应充分考虑内存大小、CPU性能等
  • 同时对于同是消耗大量磁盘IO资源的应用(数据库、文件存储)等服务尽量不要部署在同一台机器上,对于大量消耗内存、CPU资源的应用也不要部署在同一服务器上,当然独立的服务器部署最好
  • 对于消息队列、ElasticSearch等分布式系统的不同节点尽量不要部署在同一个物理机架上
  • 对于不同业务的数据库实例尽量分开,另外关键业务的数据库最好单独部署和进行冗余配置,对于查询压力大的数据库进行水平扩展,必要时候结合缓存服务

2.2 平台层级划分

用户设备端通过互联网最终到达内部应用服务需要经过多道关卡,通过合理的层级划分,可以对各层功能进行划分,也有助于整理平台结构。

从外到内的层级如下:

互联网-> CDN -> 防火墙 -> 负载均衡 -> Api网关 -> 接入层服务 -> 内部服务

1) CDN

在这里配置外部CDN数据、资源缓存,可以有效减轻源站压力。

2) 防火墙

在这里配置安全防护设施,风控平台等组件。用于拦击恶意访问行为。

3) 负载均衡

在外部通道、端口有限的情况下,通过负载均衡进行端口转发,将不同应用请求分配到不同的应用实例上,同时也起到在高可用部署下将请求有效分配至有效节点的作用。

4) Api网关

在这里我们使用的是Spring Cloud全家桶,因此网关选用Zuul。 在我们的场景下,网关的作用包括:

  • 二级负载均衡:将应用请求分配到对应的接入服务实例中
  • 统一加解密处理:将加密的参数解密后再传给接口服务,这样解密步骤就不用在各个业务服务中重复实现,同时也便于统一升级
  • 用户认证、权限控制:通过自行实现的Filter,利用JWT Token将需要用户权限的接口进行防护,对于无效Token直接在网关层面进行拦截。后台接入服务直接从网关转发的请求头中获取有效的用户信息

5) 接入层服务

直接对接用户设备或者第三方服务器,不直接访问数据库等基础设施,而是通过访问内部微服务整合数据,最终对外提供服务。同时在新老系统过渡期间也可以起到兼容适配的作用。在这里需要应用必要的安全防护措施,对于接口类型的服务,若在网关之后则无需另外配置,若是独立的Web应用,则应该搭配Spring Security等组件进行使用。

6) 内部服务

外部网络无法直接访问内部服务的接口。内部服务仅能被接入层服务、内部其它服务调用。

2.3 微服务基础搭建

2.3.1 基础组件

eureka, config-server, zipkin, hystrix-dashboard,spring-admin(这个我们没有采用,但是装了无妨) 都是有必要部署的。

其中有些需要注意的地方,配置不合理可能影响平台内的应用性能。

1) zipkin

  • 没有特殊需求的用默认的内存即可,但是存储时间有限, 有条件的话zipkin采用ElasticSearch存储,但是不要使用Mysql等传统数据库存储数据,性能很差。
  • zipkin的监控数据尽可能通过RabbitMq等消息队列进行传递,而不是直接指定zipkin服务器通过Http方式传递消息,不然在高频访问的时候可能造成应用性能问题。若采用的Mq的方式传递,zipkin的采样率什么的采用1.0也无所谓。

2) config-server

  • 采用git或者svn方式配置,不要使用文件形式管理,避免了配置管理服务的单点故障问题。
  • config-server有坑,目前不知道怎么处理,就是持续运行一段时间后可能出现对于新提交的配置无法更新或者查询的问题,这时候只能重启config-server。
  • 结合Eureka可以做到 生产/测试环境 的配置隔离,做到简化服务配置流程。

3) eureka

  • 最好部署多个实例,并且划分为生产/测试两套环境
  • 结合2)提到的配置中心设置,就可以做到围绕eureka进行环境隔离的作用

4) hystrix

  • 作为熔断监控,不要滥用,必要的时候做到服务降级可以有效提升用户体验,但是不必要的调用步骤做了降级反而不利于调试。

2.3.2 基础软件

1) 数据库

基本需要做到读写分离、定期增量备份、定期全量备份即可,暂时没有遇到极端性能要求的场景。但是最好隔离应用,并把关键应用的数据库独立部署。

2) redis

做好cluster和高可用配置,同时在应用层面做好redis失效时候正常提供服务的准备。

3) 消息队列

我的场景下安装了RabbitMq和Kafka,各个业务应用根据实际需求使用不同的队列即可。在我的场景下,对于应用之间的结偶和缓冲我使用的RabbitMq。Kafka仅作为ELK中的队列部分。

4) 日志采集

采用ELK方案: ElasticSearch + Logstash + Kibana的方案,同时logstash的Producer和Consumer间采用kafka队列。这里 FireBeat应该是更好的选择。

3. 项目研发

3.1 Maven项目组织

服务平台涉及多个应用服务,需要基本的Maven配置,将各个类型的服务应用进行划分,以减少各个应用开发时候的配置工作量,同时也避免了不必要的组件应用。

我们的场景中分为: parent, common, aop, front-end, service, api, util等项目类型。

  • parent:用于二级项目类型的划分,是一个POM项目,同时为每个类型的项目指定必须引入的maven组件
  • common:用于封装基础的输入输出封装、工厂类、全局共用的静态变量、枚举等代码。
  • aop:业务无关的工具类注解的项目
  • front-end: 接入层项目(web,api)服务
  • service:内部服务,必须包括swagger等组件便于内部调试和文档展示(可以选配spring-data)
  • api:服务间接口独立出来的项目,在服务提供方被Controller实现,在服务调用方被FeignClient继承。(详见《SpringCloud微服务实战》)
  • util:工具类项目

3.2 编码规范

参看阿里巴巴的规范文档即可,在多人协作开发的情况下是十分必要的。

3.3 统一的Api设计

人员配置允许的情况下,像3.1中的api项目最好由有经验的开发人员统一设计,对各个业务服务的对外接口进行抽象和整合,同时严格遵守接口的版本定义规范,以最大限度的达到服务在接口层面的稳定。否则api若频繁变动,连带的调用服务都得跟着升级,非常不利于系统稳定,同时也很容易出现由于人员疏忽造成的服务间api版本不统一而出现服务异常。

4. 系统部署与新老系统过渡

不论何种类型的部署,最好在接入层之上配置好nginx,这样实现基本的流量切换、灰度测试等功能,实现平滑过渡。

 

4.1 新增业务

对于新增业务可以直接在测试环境/生产环境部署,不会影响到既有应用的运行。

4.2 业务升级

在nginx之下的服务(比如网关)可以直接重启,若要保险一点,则应该先把nginx的upstream中需要升级的服务踢掉再重启。

在微服务体系内的其它服务由于是客户端的负载均衡,因此不能直接重启,这样会导致其它应用调用时候至少出现一次调用异常。正确的方法应该是发送Shutdown命令至服务,这样服务可以在关闭的同时删除eureka中自身的信息,其余的应用就不会再调用这个实例。

4.3 既有应用升级

由于老系统接口数据结构不同,可以在接入层进行数据转换适配后提供服务。

猜你喜欢

转载自blog.csdn.net/tzdwsy/article/details/80999368