移动医疗公司顺能网络从单体服务拆分成微服务的实战经验分享,内容包含微服务框架选型、CI/CD、容器编排的经验,旨在帮助大家低成本、快速落地微服务,在刀刀见血的互联网大潮中,快速迭代,快速交付。
相关趋势图
首先给大家看一张百度指数上,关于微服务、Spring Boot、Spring Cloud、Dubbo 的趋势图:
从图中可见,Dubbo 的搜索量增势放缓,Spring Boot 从 16 年中下旬开始发力,一路高涨。学习了 Spring Boot 再学习 Spring Cloud 几乎顺理成章。
Spring Boot 旨在解决 Spring 越来越臃肿的全家桶方案的配置地狱(讽刺的是,Spring 刚出道是扯着轻量化解决方案大旗一路冲杀,现在自己也开始慢慢胖起来了),提供了很多简单易用的 starter。特点是预定大于配置。
Dubbo 放缓是源于,阿里巴巴中间断更将近三年(dubbo-2.4.11 2014-10-30, dubbo-2.5.4 2017-09-07),很多依赖框架和技术都较为陈旧,也不接纳社区的 PR(当然,最近开始恢复更新,后面会有说到),导致当当另起炉灶,fork 了一个: https://github.com/dangdangdotcom/dubbox(现在已断更)。
而且 Dubbo 仅相当于 Spring Cloud 的一个子集,可参考文章《微服务架构的基础框架选择:Spring Cloud 还是 Dubbo?》:http://blog.csdn.net/kobejayandy/article/details/52078275
另外我们可以看看 k8s、kubernetes 、docker 的搜索趋势:
上面两图意在说明,微服务相关和容器相关越来越流行了,不再是一个特别新的、不成熟的技术。那单体服务和微服务的对比如何呢?
微服务 vs. 单体应用
单体应用好处:
开发简单
容易测试
易于部署
事务回滚容易
无分布式管理,调用开销
重复功能/代码较少
单体应用缺点:
迭代缓慢
维护困难
持续部署困难:微小改动,必须重启,不相干功能无法提供服务
牵一发而动全身:依赖项冲突,变更后,需要大量测试,防止影响其他功能
基础语言、框架升级缓慢
框架语言单一,无法灵活选用
微服务好处:
敏捷性:按功能拆分,快速迭代
自主性:团队技术选型灵活(PHP、python、java、C#、nodejs、golang),设计自主
可靠性:微服务故障只影响此服务消费者,而单体式应用会导致整个服务不可用
持续集成持续交付
可扩展性:热点功能容易扩展
微服务的缺点:
性能降低:服务间通过网络调用
管理难度增大:增加了项目的复杂性
事务一致性
扩展阅读《Introduction to Microservices》:https://www.nginx.com/blog/introduction-to-microservices/
框架选型
下面分享一下我司在落地微服务时的框架选型方面的一些经验。
我们公司主要使用 java,所以决定使用 Spring 框架中的 Spring Cloud 作为微服务基础框架,但是原生 Spring Cloud 学习曲线比较陡峭,需要学习 feign、zuul、eureka、hystrix、zipkin、ribbon…需要老司机坐副驾驶,不然容易翻车。
最后考虑团队的技术水平和学习成本,多方面考察,我们最后采用了国外的开源框架 JHipster http://www.jhipster.tech/。其实国内用 Dubbo 的较多,用 JHipster 的较少。我们不用 Dubbo 的原因,前面提到过,一个是中间断更,以及阿里说不更就不更的优良传统,还有 Dubbo 从功能来说,只是 Spring Cloud 的一个子集。
从 JHipster 官方资料看,登记在册的使用 jhipster 的企业有 224 家,其中不乏 Google、Adobe 一类的大厂。可参见 http://www.jhipster.tech/companies-using-jhipster/
此处列举一下 JHipster 的技术栈(开箱即用):
客户端技术栈:
angular4,5 or angularv1.x
Bootstrap
HTML5 Boilerplate
兼容 IE11+及现代浏览器
支持国际化
支持 sass
支持 spring websocket
支持 yarn、bower 管理 js 库
支持 webpack、gulp.js 构建,优化,应用
支持 Karma、Headless Chrome 和 Protractor 进行前端单元测试测试
支持 Thymeleaf 模板引擎,从服务端渲染页面
服务端技术栈:
支持 spring boot 简化 spring 配置
支持 maven、gradle,构建、测试、运行程序
支持多配置文件(默认 dev,prod)
spring security
spring mvc REST + jackson
spring websocket
spring data jpa + Bean Validation
使用 liquibase 管理数据库表结构变更版本
支持 elasticsearch,进行应用内搜素
支持 mongoDB 、Couchbase、Cassandra 等 NoSQL
支持 h2db、pgsql、mysql、meriadb、sqlserver、oracle 等关系型 sql
支持 kafka mq
使用 zuul 或者 traefik 作为 http 理由
使用 eureka 或 consul 进行服务发现
支持 ehcache、hazelcast、infinispan 等缓存框架
支持基于 hazelcast 的 httpsession 集群
数据源使用 HikariCP 连接池
生成 Dockerfile、docker-compose.yml
支持云服务商 AWS、Cloud Foundry、Heroku、Kubernetes、Openshift、Docker …
支持统一配置中心
不过真正用了后,就会发现,这个列表不全,JHipster 支持的不止列表中描述的这些,大家也可以参考我以前写的《JHipster 开发笔记》: https://jh.jiankangsn.com/
JHipster 是基于 yoman 的一个快速开发的脚手架(国内前几年流行的名字叫代码生成器),需要 nodejs 环境 ,并且使用 yarn 搭建环境。当然不会也没事,它非常简单,如果实在想用,可以用《JHipster Online》:https://start.jhipster.tech/。类似 Spring 的http://start.spring.io/
值得一提的是 JHipster 也支持通过 JHipster rancher-compose 命令来生成 rancher-compose.yml 和 docker-compose.yml,具体可参考《[BETA] Deploying to Rancher》:http://www.jhipster.tech/rancher/
对于小团队落地微服务,可以考虑使用 JHipster 来生成项目,能够极大的提高效率。基本上可以视作 JHipster 是一套基于 Spring Boot 的最佳实践(不仅支持微服务,也支持单体式应用)。对于想学习 Spring Boot 或者 Spring Cloud 的也建议了解一下 JHipster,好过独自摸索。
JHipster 依赖的技术框架版本基本都是最新稳定版,版本更新比较及时,基本上一月一个版本,对 GitHub 上的 issues 和 PR 响应比较及时(一般在 24 小时内)。
10 分钟搭建微服务
下面我将分享如何 10 分钟搭建一套微服务(不含下载 nodejs、安装 maven 等准备环境的时间)。
安装 nodejs、yarn 的指南可参见我在《JHipster 开发笔记》中的一篇【安装】:https://jh.jiankangsn.com/install.html
需要注意的是,如果是 windows nodejs,需要安装 v7.x,因为注册中心和网关需要用到 node-sass@4.5.0,但是 github 上的 node-sass 的 rebuild 只有 v7.x(process 51) 版本的,而自己构建太反人类了。如果是 linux,可以尝试高版本的,建议装 nodejs v7.x,除非你想玩刺激,自己 build 一个 node-sass。
为了加速下载,建议用 npm 的淘宝镜像:
安装 jdk8、maven、maven 加速这些就不说了,可自行百度。
下载注册中心
JHipster-registry github 地址 :https://github.com/jhipster/jhipster-registry)
浏览器访问 http://localhost:8761,初始用户名密码均为 admin。
注册中心的页面
Spring Config Server,统一配置中心,可以统一管理不同环境的数据库地址、用户名、密码等敏感数据。
JHipster Registry 对应 SC(Spring Cloud)的 eurake+spring config server。
创建网关
创建 api 网关,参见
【Creating an application】:http://www.jhipster.tech/creating-an-app/
【The JHipster API Gateway】: http://www.jhipster.tech/api-gateway/
访问http://localhost:8080/,默认用户名密码均为 admin。
创建服务
创建服务可参考:http://www.jhipster.tech/creating-an-app/
访问http://localhost:8080/#/docs 默认用户名密码均为 admin ,使用 swagger 管理 api 文档,开发时,仅需要添加对应的注解,即可自动生成文档,解决了传统通过 word、pdf 等管理接口时,文档更新不及时等问题。并且可以通过 try it 直接调用接口,避免了接口调试时使用 curl、postman 等工具。
至此,已经创建了一个简单微服务(JHipster-registry 是注册中心,gateway 是网关,foo 是具体的功能模块)。
创建实体
JHipster 支持通过命令行创建实体,也支持 uml 或 jdl 生成实体,为了省事,此处使用官方 jdl-studio 的默认 jdl 文件https://start.jhipster.tech/jdl-studio/。
重启 foo 服务,再次访问http://localhost:8080/#/docs,发现多了很多接口
通过 swagger ui,找到 region-resource,找到 POST /api/regions,创建一个名为 test 的 regison。
点 try it out! ,然后浏览器打开 h2 数据库http://localhost:8081/h2-console
查询 REGION 表,数据已经插入成功。
至此,一个虽然简单、但是可用的微服务已经弄好。
将服务发布到 Rancher
JHipster 支持发布到 Cloud Foundry、Heroku、Kubernetes、Openshift、Rancher、AWS、Boxfuse。
我们建议使用 Rancher,因为 Cloud Foundry 、Heroku、AWS、Boxfuse 都是云环境,而 k8s 和 openshift origin 太复杂了,而 Rancher 则很容易上手,功能完备,也是完全开源,其联合创始人还是 CNCF 的理事会成员。
服务发布可以参见文档:http://www.jhipster.tech/rancher/
RANCHER-COMPOSE.YML
DOCKER-COMPOSE.YML
docker-compose.yml 中给的 JHipster-registry 是本地模式的,可以根据注释部分内容,改成从 Git 拉。好处是维护方便,坏处是容易造成单点故障。使用 Git 模式,就可以将 registry-config-sidekick 部分去掉。
JHipster 使用 liquibase 进行数据库版本管理,便于数据库版本变更记录管理和迁移。(rancher server 也用的 liquibase)
把 docker-compose.yml 和 rancher-compose.yml 贴到 rancher 上,就能创建一个应用 stack 了。
不过,好像漏了点啥?少了 CICD。Rancher 和 docker 的 compsoe.yml 有了,但是,还没构建镜像呢,镜像还没 push 到 registry 呢,对吧?
CI/CD
自建 GitLab
我司用 GitLab 管理源码,我在 Docker Hub 上发布了一个汉化的 GitLab:https://hub.docker.com/r/gitlab/gitlab-ce/tags/
如果要用官方镜像,参见https://hub.docker.com/r/gitlab/gitlab-ce/tags/
GitLab CI
我们的 CI 用的是 GitLab-CI,参见【GitLab Continuous Integration (GitLab CI)】: https://docs.gitlab.com/ce/ci/README.html
为啥不用 Jenkins?这个萝卜白菜各有所爱,我是出于压缩技术栈的考虑:
GitLab-CI 够简单,也够用
它和 GitLab 配套,不用多学习 Jenkins,毕竟多一套,就多一套的学习成本
搭建镜像伺服
老牌 sonatype nexus oss 可以管理 Bower、Docker、Git LFS、Maven、npm、NuGet、PyPI、Ruby Gems、Yum Proxy,功能丰富:https://www.sonatype.com/download-oss-sonatype
GitLab Container Registry administration,GitLab Registry 跟 GitLab 集成,不需要额外安装服务:https://docs.gitlab.com/ce/administration/container_registry.html#gitlab-container-registry-administration
Harbor 应用商店就有,安装方便,号称企业级 registry,功能强大:http://vmware.github.io/harbor/rancher
如何选择?还是那句话,看需求。我司有部署 maven 和 npm 的需要,所以用了 nexus oss,顺便管理 docker registry。
Service Mesh——下一代微服务
我司是从 16 年八九月份开始拆分单体服务,彼时国内 Spring Cloud,微服务等相关资料较少,国内流行 dubbo(那会已经断更 1 年多了,虽然现在复更,但是对其前景不太看好)。
从 17 年开始,圈内讨论 Spring Cloud 的渐渐多起来了,同时市面上也有了介绍 Spring Cloud 的书籍,比如周立的《Spring Cloud 与 Docker 微服务架构实战》, 翟永超的《Spring Cloud 微服务实战》等。
但是用了 Spring Cloud 后,感觉 Spring Cloud 太复杂了(如果用了 JHipster 情况会好点),并没有实现微服务的初衷:
跟语言,框架无关:局限于 java
隐藏底层细节,需要学习 zuul 路由,eureka 注册中心,configserver 配置中心,需要熔断,降级,需要实现分布式跟踪…
在这种情况下,16 年,国外 buoyant 公司提出 Service Mesh 概念,基于 scala 创建了 linkerd 项目。Service Mesh 的设想就是,让开发人员专注于业务,不再分心于基础设施。
目前主流框架:
istio:背靠 google,ibm,后台硬,前景广阔
conduit:跟 linkerd 是一个公司的,使用 Rust 语言开发,proxy 消耗不到 10M 内存,p99 控制在毫秒内
linkerd:商用企业较多,国内我知道的有豆瓣
envoy:国内腾讯在用
其中 istio 和 conduit 都不太成熟,而 linkerd 和 envoy 都有商用案例,较为成熟。长远来看,我更看好 istio 和 conduit。
对 Dubbo 的老用户来说也有个好消息,据说 Dubbo3 将兼容 2,并且支持 Service Mesh,支持反应式编程。
结语
建议大家根据公司、团队实际情况理性选择框架,目前 Service Mesh 还处于垦荒阶段,而 Spring Cloud 或者 Dubbo 还没到彻底过时的程度,建议持续关注,不建议立刻上马。
如果已经落地了相关的微服务技术,不要盲目跟风,在可接受学习成本和开发成本情况下,可以考虑研究一下 Service Mesh。
如果使用的是 Spring 框架的话,建议抛开 Spring Cloud,直接 Spring Boot + Service Mesh,更清爽一些。
扩展阅读资料:
【官方文档|ServiceMesh 服务网格 Istio 面板组件 &设计目标】 http://blog.shurenyun.com/untitled-102/
【演讲实录 | Service Mesh 时代的选边与站队(附 PPT 下载)】 http://www.servicemesh.cn/?/article/25
【Service Mesh:下一代微服务】 https://servicemesh.gitbooks.io/awesome-servicemesh/mesh/2017/service-mesh-next-generation-of-microservice/
Q&A
Q:你们是选择使用 consul 还是 JHipster-register?
A:我们用的是 JHipster-registry,核心是 eureka,但是有问题,服务状态广播需要心跳时间,在升级服务的时候,容易丢请求,建议用 consul 或者类似 kong 这种的,或者用 service mesh,比如 istio,定义流量策略。
Q:Spring Boot+k8s 进行微服务改造可行不?先来简单的。
A:当然可行,如果可以,建议 spring boot+service mesh(e.g. istio)+k8s,皇家拍档,类似咖啡跟咖啡伴侣。
Q:请问贵司是如何定制 JHipster 的呢?或者有没有什么好的建议。
A:JHipster 本身是很 open 的,通过我贴的技术栈基本满足普通开发需求了,而且 JHipster 是基于 Spring Boot/Spring Cloud,而 Spring Boot 又基于 Spring 。所以理论上没有集成压力,或者说是定制压力。
Q:ORM 能随意切换 MyBais 吗?
A:可以换,没问题。
Q:Spring Cloud 里面的组件和 k8s 功能有重叠的部分,可不可以相互用下?
A:跟上题一样,只要能跟 Spring 集成,就能跟 JHipster 集成。如果没用 SC 或者 JHipster,我是建议用 Springboot+Service Mesh+k8s。不过只从开发体验来说,用 JHipster 和 Service Mesh,差别不大(JHipster 隐藏了很多 SC 的底层细节)。
Q:除了 java 以外的如何集成呢?
A:如果非 java 语言的话,建议 Service mesh+k8s,可以参考微博的 Motan。
Q:数据库版本管理,有什么好的方式?
A:数据库版本管理,目前比较流行的有 liquibase(JHipster 默认使用,Rancher 也用的 liquibase) 与 flyway。
Q:JHipster 默认使用 JPA ,你安利案例中,你们是使用 JPA 还是使用别的?如 mybatis 等。
A:JHipster 默认使用 JPA 没错,但是在一些简单 CURD 中,已经够用了,稍微复杂点的,可以用 @Query,再复杂点的,可以用【querydsl】 http://www.querydsl.com/ 。逆天难度的,可以国产的 mybatis-plus。还是要看困难等级。50%的情况,用 JPA 就够了,比如 findAll(),不用写任何实现,findByName(String name)。
Q:在安利案例中,有是使用 uaa 做 Oauth2 服务器吗?
A:【uaa】http://www.jhipster.tech/using-uaa/。从 JHipster 官方来看,建议用 OIDC。当然也支持 jwt。OIDC openID Connect: http://www.jhipster.tech/security/
Q:SC 的通讯效率是不是有问题?没有 Dubbo 快
A:其实,SC 用的是 RESTful 基于 http,Dubbo 是 rpc。虽然 rest 慢一些,更占带宽一些,但是,好处是调试方便,方便对接,扪心自问一下,你们的 qps,真到了 rest 成瓶颈的级别了么?
Q:java 与 jhipster 在 CICD 持续集成,结合 K8S 如何做的,具体的例子有没有
A:k8s CD:http://www.jhipster.tech/kubernetes/
Q:是不是 k8s 安装了 linkerd 组件就有 service mesh 了?
A:建议 k8s + istio conduit
linkerd 基于 scala,性能有点差,当然目前也是商用最多的方案。同时 service mesh,也是 linkerd 提出的概念,service mesh 类似微服务,只是一个概念,具体实现,目前主流的有 istio、conduit、linkerd、envoy。
Q:scala 性能不算差吧?跟 java 是同样的。
A:对啊,基于 jvm,而 conduit 使用 Rust 语言(可以理解成 c++)开发,proxy 消耗不到 10M 内存,p99 控制在毫秒内,而 linkerd 一般 300-500M,不是一个量级。
评论