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

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

1. 业务梳理

1.1 切换的基本原则

因为是生产中正在运行的系统,所以有以下几个要求必须知足:git

 

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

1.2 既有系统功能整理

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

以我如今的项目为例,redis

1)公共服务包括:算法

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

2)关键服务包括:spring

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

3)非关键服务包括:sql

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

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

1.3 准备迁移方案

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

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 既有应用升级

因为老系统接口数据结构不一样,能够在接入层进行数据转换适配后提供服务。