工作上项目的后台进行微服务改造后已经平稳运行将近1年了,起初项目为若干个单体web应用组成,之后由于上线App,需求的多样性和对于需求的响应速度有了更高的要求,因此为了快速响应需求变化,将后台进行微服务化改造。总的来说,改造初期由于既有系统我都非常熟悉,因此改造和迁移都比较顺利。在微服务架构的帮助下,新接入业务可以更专注于服务的实现,同时各个服务的功能也可以进行快速整合。目前平台的研发告一段落,后期工作可能调整,因此趁有时间把最近一年的改造设计、研发、部署、迁移、运维等各个部分的经验大致整理一下,不说虚的,不列名词,具体代码尽量不说(网上一堆),只说经验与想法。
由于是生产中正在运行的系统,因此有如下几个要求必须满足:
对于既有后台的若干服务的功能和模块进行整理,首先应该梳理出公共功能部分,可以作为独立的服务模块对外提供服务,其次对于其它功能梳理出关键功能(必须切换、必须保证过度、历史数据不能丢失……),对于非关键功能,在时间紧张的时候可以先维持既有系统运行,在微服务平台切换后期再进行研发,并转入新的后台中。
以我现在的项目为例,
1)公共服务包括:
2)关键服务包括:
3)非关键服务包括:
综上,我们根据梳理的服务类型,优先实现公共服务和关键服务,在合适的时候进行整体迁移。在主体服务迁移完毕,平稳运行后即可进行后续功能的迁移与改造。
系统研发过程中,应充分考虑既有系统的兼容性,并准备好关键数据的转移方案。对于有大量修改的系统和数据,考虑通过兼容接入服务处理旧的应用请求,而新的业务请求直接根据新的数据和逻辑开发。
在平台改造时,应该充分考虑能力冗余。数据库、缓存、消息队列、分布式文件系统、目录服务、负载均衡、ElasticSearch集群等服务平台的基础组件应该进行资源的合理划分。比如:
用户设备端通过互联网最终到达内部应用服务需要经过多道关卡,通过合理的层级划分,可以对各层功能进行划分,也有助于整理平台结构。
从外到内的层级如下:
互联网-> CDN -> 防火墙 -> 负载均衡 -> Api网关 -> 接入层服务 -> 内部服务
1) CDN
在这里配置外部CDN数据、资源缓存,可以有效减轻源站压力。
2) 防火墙
在这里配置安全防护设施,风控平台等组件。用于拦击恶意访问行为。
3) 负载均衡
在外部通道、端口有限的情况下,通过负载均衡进行端口转发,将不同应用请求分配到不同的应用实例上,同时也起到在高可用部署下将请求有效分配至有效节点的作用。
4) Api网关
在这里我们使用的是Spring Cloud全家桶,因此网关选用Zuul。 在我们的场景下,网关的作用包括:
5) 接入层服务
直接对接用户设备或者第三方服务器,不直接访问数据库等基础设施,而是通过访问内部微服务整合数据,最终对外提供服务。同时在新老系统过渡期间也可以起到兼容适配的作用。在这里需要应用必要的安全防护措施,对于接口类型的服务,若在网关之后则无需另外配置,若是独立的Web应用,则应该搭配Spring Security等组件进行使用。
6) 内部服务
外部网络无法直接访问内部服务的接口。内部服务仅能被接入层服务、内部其它服务调用。
eureka, config-server, zipkin, hystrix-dashboard,spring-admin(这个我们没有采用,但是装了无妨) 都是有必要部署的。
其中有些需要注意的地方,配置不合理可能影响平台内的应用性能。
1) zipkin
2) config-server
3) eureka
4) hystrix
1) 数据库
基本需要做到读写分离、定期增量备份、定期全量备份即可,暂时没有遇到极端性能要求的场景。但是最好隔离应用,并把关键应用的数据库独立部署。
2) redis
做好cluster和高可用配置,同时在应用层面做好redis失效时候正常提供服务的准备。
3) 消息队列
我的场景下安装了RabbitMq和Kafka,各个业务应用根据实际需求使用不同的队列即可。在我的场景下,对于应用之间的结偶和缓冲我使用的RabbitMq。Kafka仅作为ELK中的队列部分。
4) 日志采集
采用ELK方案: ElasticSearch + Logstash + Kibana的方案,同时logstash的Producer和Consumer间采用kafka队列。这里 FireBeat应该是更好的选择。
服务平台涉及多个应用服务,需要基本的Maven配置,将各个类型的服务应用进行划分,以减少各个应用开发时候的配置工作量,同时也避免了不必要的组件应用。
我们的场景中分为: parent, common, aop, front-end, service, api, util等项目类型。
参看阿里巴巴的规范文档即可,在多人协作开发的情况下是十分必要的。
人员配置允许的情况下,像3.1中的api项目最好由有经验的开发人员统一设计,对各个业务服务的对外接口进行抽象和整合,同时严格遵守接口的版本定义规范,以最大限度的达到服务在接口层面的稳定。否则api若频繁变动,连带的调用服务都得跟着升级,非常不利于系统稳定,同时也很容易出现由于人员疏忽造成的服务间api版本不统一而出现服务异常。
不论何种类型的部署,最好在接入层之上配置好nginx,这样实现基本的流量切换、灰度测试等功能,实现平滑过渡。
对于新增业务可以直接在测试环境/生产环境部署,不会影响到既有应用的运行。
在nginx之下的服务(比如网关)可以直接重启,若要保险一点,则应该先把nginx的upstream中需要升级的服务踢掉再重启。
在微服务体系内的其它服务由于是客户端的负载均衡,因此不能直接重启,这样会导致其它应用调用时候至少出现一次调用异常。正确的方法应该是发送Shutdown命令至服务,这样服务可以在关闭的同时删除eureka中自身的信息,其余的应用就不会再调用这个实例。
由于老系统接口数据结构不同,可以在接入层进行数据转换适配后提供服务。