java 拉起服务_技术开发者应该如何构建小团队的微服务方案?

a2d32dbd4994c844eca77b1dec16040a.png

作者 | 徐鹏

责编 | 刘静

出品 | CSDN(ID:CSDNnews)

我们的产品是Linkflow,企业运营人员使用的客户数据平台(CDP)。产品的一个重要部分类似企业版的”捷径”,让运营人员可以像搭乐高积木一样创建企业的自动化流程,无需编程即可让数据流动起来。从这一点上,我们的业务特点就是聚少成多,把一个个服务连接起来就成了数据的海洋。理念上跟微服务一致,一个个独立的小服务最终实现大功能。当然我们一开始也没有使用微服务,当业务还未成型就开始考虑架构,那么就是”过度设计”。另一方面需要考虑的因素就是”人”,有没有经历过微服务项目的人,团队是否有devops文化等等,综合考量是否需要微服务化。

eaeb7a366ed14f6d5baa6e8a9b5a15bf.png

要不要微服务

微服务的好处是什么?

  • 相比于单体应用,每个服务的复杂度会下降,特别是数据层面(数据表关系)更清晰,不会一个应用上百张表,新员工上手快;

  • 对于稳定的核心业务可以单独成为一个服务,降低该服务的发布频率,也减少测试人员压力;

  • 可以将不同密集型的服务搭配着放到物理机上,或者单独对某个服务进行扩容,实现硬件资源的充分利用;

  • 部署灵活,在私有化项目中,如果客户有不需要的业务,那么对应的微服务就不需要部署,节省硬件成本,就像上文提到的乐高积木理念。

微服务有什么挑战?

  • 一旦设计不合理,交叉调用,相互依赖频繁,就会出现牵一发动全身的局面。想象单个应用内service层依赖复杂的场面就明白了;

  • 项目多了,轮子需求也会变多,需要有人专注公共代码的开发;

  • 开发过程的质量需要通过持续集成(CI)严格把控,提高自动化测试的比例,因为往往一个接口改动会涉及多个项目,光靠人工测试很难覆盖所有情况;

  • 发布过程会变得复杂,因为微服务要发挥全部能力需要容器化的加持,容器编排就是最大的挑战;

  • 线上运维,当系统出现问题需要快速定位到某个机器节点或具体服务,监控和链路日志分析都必不可少。

下面详细说说我们是怎么应对这些挑战的:

b23596efcd9f65e84d9ccf9cfcdeb59b.png

开发过程的挑战

持续集成:

  • 通过CI将开发过程规范化,串联自动化测试和人工Review;

  • 我们使用Gerrit作为代码&分支管理工具,在流程管理上遵循Gitlab的工作流模型;

  • 开发人员提交代码至Gerrit的magic分支;

  • 代码Review人员Review代码并给出评分;

  • 对应Repo的Jenkins job监听分支上的变动,触发Build job。经过IT和Sonar的静态代码检查给出评分;

  • Review和Verify皆通过之后,相应Repo的负责人将代码merge到真实分支上若有一项不通过,代码修改后重复过程;

  • Gerrit将代码实时同步备份至的两个远程仓库中。

0f9170f5e67214af30309b0ae06d55ac.png

集成测试

一般来说代码自动执行的都是单元测试(Unit Test),即不依赖任何资源(数据库,消息队列)和其他服务,只测试本系统的代码逻辑。但这种测试需要mock的部分非常多,一是写起来复杂,二是代码重构起来跟着改的测试用例也非常多,显得不够敏捷。而且一旦要求开发团队要达到某个覆盖率,就会出现很多造假的情况。所以我们选择主要针对API进行测试,即针对controller层的测试。另外对于一些公共组件如分布式锁,json序列化模块也会有对应的测试代码覆盖。测试代码在运行时会采用一个随机端口拉起项目,并通过http client对本地API发起请求,测试只会对外部服务做mock,数据库的读写,消息队列的消费等都是真实操作,相当于把Jmeter的事情在Java层面完成一部分。Spring Boot项目可以很容易的启动这样一个测试环境,代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)

测试过程的http client推荐使用io.rest-assured:rest-assured支持JsonPath,十分好用。

测试时需要注意的一个点是测试数据的构造和清理。构造又分为schema的创建和测试数据的创建。

  • schema由flyway处理,在启用测试环境前先删除所有表,再进行表的创建;

  • 测试数据可以通过@Sql读取一个sql文件进行创建,在一个用例结束后再清除这些数据。

顺带说一下,基于flyway的schema upgrade功能我们封成了独立的项目,每个微服务都有自己的upgrade项目,好处一是支持command-line模式,可以细粒度的控制升级版本,二是也可以支持分库分表以后的schema操作。upgrade项目也会被制作成docker image提交到docker hub。

测试在每次提交代码后都会执行,Jenkins监听gerrit的提交,通过docker run -rm {upgrade项目的image}先执行一次schema upgrade,然后gradle test执行测试。最终会生成测试报告和覆盖率报告,覆盖率报告采用jacoco的gradle插件生成。如图:

f6339dfef690fa98f496462d336c17fa.png5e45536c7dd232a3e19b88de0407dbc2.png

这里多提一点,除了集成测试,服务之间的接口要保证兼容,实际上还需要一种consumer-driven testing tool,就是说接口消费端先写接口测试用例,然后发布到一个公共区域,接口提供方发布接口时也会执行这个公共区域的用例,一旦测试失败,表示接口出现了不兼容的情况。比较推荐大家使用Pact或是Spring Cloud Contact。我们目前的契约基于”人的信任“,毕竟服务端开发者还不多,所以没有必要使用这样一套工具。

集成测试的同时还会进行静态代码检查,我们用的是sonar,当所有检查通过后jenkins会+1分,再由reviewer进行代码review。

自动化测试

单独拿自动化测试出来说,就是因为它是质量保证的非常重要的一环,上文能在CI中执行的测试都是针对单个微服务的,那么当所有服务(包括前端页面)都在一起工作的时候是否会出现问题,就需要一个更接近线上的环境来进行测试了。

在自动化测试环节,我们结合Docker提高一定的工作效率并提高测试运行时环境的一致性以及可移植性。在准备好基础的Pyhton镜像以及Webdriver(selenium)之后,我们的自动化测试工作主要由以下主要步骤组成:

  • 测试人员在本地调试测试代码并提交至Gerrit;

  • Jenkins进行测试运行时环境的镜像制作,主要将引用的各种组件和库打包进一个Python的基础镜像;

  • 通过Jenkins定时或手动触发,调用环境部署的job将专用的自动化测试环境更新,然后拉取自动化测试代码启动一次性的自动化测试运行时环境的Docker容器,将代码和测试报告的路径镜像至容器内;

  • 自动化测试过程将在容器内进行;

  • 测试完成之后,不必手动清理产生的各种多余内容,直接在Jenkins上查看发布出来的测试结果与趋势。

d330e13830ec9ce213d69557273d7b67.png53b9b60ffaf38a8cf969708cd36ac590.png

关于部分性能测试的执行,我们同样也将其集成到Jenkins中,在可以直观的通过一些结果数值来观察版本性能变化情况的回归测试和基础场景,将会很大程度的提高效率、便捷的观察趋势。

  • 测试人员在本地调试测试代码并提交至Gerrit;

  • 通过Jenkins定时或手动触发,调用环境部署的job将专用的性能测试环境更新以及可能的Mock Server更新;

  • 拉取最新的性能测试代码,通过Jenkins的性能测试插件来调用测试脚本;

  • 测试完成之后,直接在Jenkins上查看通过插件发布出来的测试结果与趋势。

1005481868806f8641457330dbb76157.png06432cb2f64dd6117ed2deeebc2ccc04.png83dcfff6e9756b4a2147405a184b2b34.png

布过程的挑战

上面提到微服务一定需要结合容器化才能发挥全部优势,容器化就意味线上有一套容器编排平台。我们目前采用是Redhat的Openshift。所以发布过程较原来只是启动jar包相比要复杂的多,需要结合容器编排平台的特点找到合适的方法。

镜像准备

公司开发基于gitlab的工作流程,git分支为master,pre-production和prodution三个分支,同时生产版本发布都打上对应的tag。每个项目代码里面都包含dockerfile与jenkinsfile,通过jenkins的多分支pipeline来打包docker镜像并推送到harbor私库上。

0994dba7b8bff96044ec047c81e7d491.png

docker镜像的命令方式为 项目名/分支名:git_commit_id,如 funnel/production:4ee0b052fd8bd3c4f253b5c2777657424fccfbc9,tag版本的docker镜像命名为 项目名/release:tag名,如 funnel/release:18.10.R1

bf7ad055bac75dc652b231ee95f61cfd.png052106459ec11a44338d630650e2483a.png

在jenkins中执行build docker image job时会在每次pull代码之后调用harbor的api来判断此版本的docker image是否已经存在,如果存在就不执行后续编译打包的stage。在jenkins的发布任务中会调用打包job,避免了重复打包镜像,这样就大大的加快了发布速度。

数据库Schema升级

数据库的升级用的是flyway,打包成docker镜像后,在openshift中创建job去执行数据库升级。job可以用最简单的命令行的方式去创建:

oc run upgrade-foo --image=upgrade/production --replicas=1 --restart=OnFailure --command -- java -jar -Dprofile=production /app/upgrade-foo.jar

脚本升级任务也集成在jenkins中。

容器发布

openshift有个特别概念叫DeploymentConfig,原生k8s Deployment与之相似,但openshift的DeploymentConfig功能更多些。

Deploymentconfig关联了一个叫做ImageStreamTag的东西,而这个ImagesStreamTag和实际的镜像地址做关联,当ImageStreamTag关联的镜像地址发生了变更,就会触发相应的DeploymentConfig重新部署。我们发布是使用了jenkins+openshift插件,只需要将项目对应的ImageStreamTag指向到新生成的镜像上,就触发了部署。

f68ac4023ad1f5d12625163fcf2df3da.png

如果是服务升级,已经有容器在运行怎么实现平滑替换而不影响业务呢?

配置Pod的健康检查,Health Check只配置了ReadinessProbe,没有用LivenessProbe。因为LivenessProbe在健康检查失败之后,会将故障的pod直接干掉,故障现场没有保留,不利于问题的排查定位。而ReadinessProbe只会将故障的pod从service中踢除,不接受流量。使用了ReadinessProbe后,可以实现滚动升级不中断业务,只有当pod健康检查成功之后,关联的service才会转发流量请求给新升级的pod,并销毁旧的pod。

readinessProbe:
failureThreshold: 4
httpGet:
path: /actuator/metrics
port: 8090
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 15
successThreshold: 2
timeoutSeconds: 2
0994a45ecf4987cc1eff0437c4abdcdc.png

线上运维的挑战

服务间调用

Spring Cloud使用eruka接受服务注册请求,并在内存中维护服务列表。当一个服务作为客户端发起跨服务调用时,会先获取服务提供者列表,再通过某种负载均衡算法取得具体的服务提供者地址(ip + port),即所谓的客户端服务发现。在本地开发环境中我们使用这种方式。

由于Openshift天然就提供服务端服务发现,即service模块,客户端无需关注服务发现具体细节,只需知道服务的域名就可以发起调用。由于我们有nodejs应用,在实现eureka的注册和去注册的过程中都遇到过一些问题,不能达到生产级别。所以决定直接使用service方式替换掉eureka,也为以后采用service mesh做好铺垫。具体的做法是,配置环境变量EUREKA_CLIENT_ENABLED=false,RIBBON_EUREKA_ENABLED=false,并将服务列表如 FOO_RIBBON_LISTOFSERVERS: '[http://foo:8080](http://foo:8080/)' 写进configmap中,以envFrom: configMapRef方式获取环境变量列表。

如果一个服务需要暴露到外部怎么办,比如暴露前端的html文件或者服务端的gateway。

Openshift内置的haproxy router,相当于k8s的ingress,直接在Openshift的web界面里面就可以很方便的配置。我们将前端的资源也作为一个Pod并有对应的Service,当请求进入haproxy符合规则就会转发到ui所在的Service。router支持A/B test等功能,唯一的遗憾是还不支持url rewrite。

af0e046b0a06f8688b903fb61a9ed923.png66922a7b9922c4e727fa01453666be87.png

对于需要url rewrite的场景怎么办?那么就直接将nginx也作为一个服务,再做一层转发。流程变成 router → nginx pod → 具体提供服务的pod。

链路跟踪

开源的全链路跟踪很多,比如spring cloud sleuth + zipkin,国内有美团的CAT等等。其目的就是当一个请求经过多个服务时,可以通过一个固定值获取整条请求链路的行为日志,基于此可以再进行耗时分析等,衍生出一些性能诊断的功能。不过对于我们而言,首要目的就是trouble shooting,出了问题需要快速定位异常出现在什么服务,整个请求的链路是怎样的。

为了让解决方案轻量,我们在日志中打印RequestId以及TraceId来标记链路。RequestId在gateway生成表示唯一一次请求,TraceId相当于二级路径,一开始与RequestId一样,但进入线程池或者消息队列后,TraceId会增加标记来标识唯一条路径。举个例子,当一次请求会向MQ发送一个消息,那么这个消息可能会被多个消费者消费,此时每个消费线程都会自己生成一个TraceId来标记消费链路。加入TraceId的目的就是为了避免只用RequestId过滤出太多日志。

实现上,通过ThreadLocal存放APIRequestContext串联单服务内的所有调用,当跨服务调用时,将APIRequestContext信息转化为Http Header,被调用方获取到Http Header后再次构建APIRequestContext放入ThreadLocal,重复循环保证RequestId和TraceId不丢失即可。如果进入MQ,那么APIRequestContext信息转化为Message Header即可(基于Rabbitmq实现)。

当日志汇总到日志系统后,如果出现问题,只需要捕获发生异常的RequestId或是TraceId即可进行问题定位。

1cc600f4b62ea244b5285aa4fcdcf975.png

经过一年来的使用,基本可以满足绝大多数trouble shooting的场景,一般半小时内即可定位到具体业务。

容器监控

容器化前监控用的是telegraf探针,容器化后用的是prometheus,直接安装了openshift自带的cluster-monitoring-operator。自带的监控项目已经比较全面,包括node,pod资源的监控,在新增node后也会自动添加进来。

Java项目也添加了prometheus的监控端点,只是可惜cluster-monitoring-operator提供的配置是只读的,后期将研究怎么将java的jvm监控这些整合进来。

9167202f99edd0f5ab03d7edba2ee934.png0f98a4b868ced5cb1c30b5750dcc78c1.pngba249fa25479653a910f33443eb89c7f.png

MORE

开源软件是对中小团队的一种福音,无论是Spring Cloud还是k8s都大大降低了团队在基础设施建设上的时间成本。当然其中有更多的话题,比如服务升降级,限流熔断,分布式任务调度,灰度发布,功能开关等等都需要更多时间来探讨。对于小团队,要根据自身情况选择微服务的技术方案,不可一味追新,适合自己的才是最好的。

作者简介:徐鹏, Linkflow运维开发负责人

声明:本文为作者投稿,版权归作者个人所有。

【END】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/359130.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html排序按钮_插件分享 | 可进行排序扫描任务的Task Queue

前言:在以往hvv场景中使用Goby的过程总是存在一个痛点:时间短,目标多,只能盯着扫描进度结束后才能手动返回到初始界面开启下一个扫描任务(内心极度狂躁)。本次Goby更新后又开放了新的插件入口点以及API,使添加扫描任务…

RabbitMQ如何做到不丢不重

目录 MQTT协议 如何保证消息100%不丢失 生产端可靠性投递 ​编辑 RabbitMQ的Broker端投 (1)消息持久化 (2)设置集群镜像模式 (3)消息补偿机制 消费端 ACK机制改为手动 总结 MQTT协议 先来说下MQTT…

【LESS系列】简介和使用

LESS —— 一个CSS预编译框架,它在CSS的语法基础之上,引入了变量、Mixin(混入)、运算以及函数等功能,大大简化了CSS的编写,并且降低了CSS的维护成本,就像它的名称所说的那样,LESS可以…

掌握 React 与 React Native

今天面试被人问到React 与 React Native ,废话不多说,直接上干货。 React Native官网:https://reactnative.cn/ React Native App 页面布局直接通过 HTML 和 CSS 的前端基础技术进行布局与开发,大大降低了学习成本。 你如果早就在心里有开发一个自己 App 的想法,而刚…

cpu序列号唯一吗_怎么看电脑硬件是不是新的 有什么软件能检测吗?

怎么看电脑硬件是不是全新的很多人比较关心的问题,毕竟现在很多奸商为了最求利润什么招式都用的出来,其中依旧重新,依次充好是最常见的伎俩了。 怎么看电脑硬件是不是新的 有什么软件能检测吗?这个时候大家可能就会想了&#xff0…

扬州大学计算机考研难考吗,扬州大学(专业学位)计算机技术考研难吗

考研真题资料优惠价原价选择很多考生在准备扬州大学(专业学位)计算机技术考研难吗?是考研报考的时候都会产生这样的疑问:这个专业的研究生好吗?适合我吗?对我以后的人生和职业会有帮助吗?考生在准备扬州大学(专业学位)…

21世纪的设计模式:适配器模式

这是我的演讲“ 21世纪的设计模式”的第三部分。 适配器模式桥接世界。 在一个世界中,我们有一个概念的界面。 在另一个世界,我们有不同的界面。 这两个接口有不同的用途,但有时我们需要进行转移。 在一个编写良好的世界中,我们可…

在百度搜索页添加公司总部的客服电话

先看一下收录标准 1.登录百度数据开放平台:http://open.baidu.com/data/ms/nav/pc/ 注意事项: 2.进到信息提交的页面,先填写相应的资质,后提交信息即可,按照给出来的示例,去填写相对应的信息就可以了

理解Linux系统中的load average(图文版)

本文转自:http://heipark.iteye.com/blog/1340384 一、什么是load average? linux系统中的Load对当前CPU工作量的度量 (WikiPedia: the system load is a measure of the amount of work that a computer system is doing)。也有简单的说是进程队列的长度…

click点击后鼠标移去就失效怎么实现_鼠标右键失灵怎么办,你知道原因吗?

在上网时,有时会遇到按右键没有反应的情况。一开始还以为是中了病毒,但是重启之后,又恢复正常了,这到底是怎么回事呢?如果是在我电脑上操作电脑软件导致的鼠标右键失灵可能以下原因造成的。一:系统繁忙&…

计算机考研379分,考研379分报考南开大学被刷,是调剂还是二战?师姐建议非常肯定...

原标题:考研379分报考南开大学被刷,是调剂还是二战?师姐建议非常肯定随着考研国家线公布,34所自主划线的985大学也加快了复试的脚步,目前很多大学已经开始了复试工作,比如清华大学,南开大学等。…

微信小程序源码下载链接

参考链接备用:https://www.cnblogs.com/ytkah/p/9003620.html 微信小程序的火热程度大家都有所了解,也有很多牛人写了不错的小程序,今天ytkah就整理一些github上的小程序开源项目,源码可以直接下载来用,感兴趣的朋友赶…

开源源码合集

微信小程序的火热程度大家都有所了解,也有很多牛人写了不错的小程序,今天Benson就整理一些github上的小程序开源项目,源码可以直接下载来用,感兴趣的朋友赶紧去看看吧!仿豆瓣电影微信小程序 https://github.com/zc…

2019广西对口计算机分数线,2019广西本科第一批投档分数线出炉,网友:我差一点考上清华大学...

2019广西本科第一批投档分数线出炉,网友:我差一点考上清华大学……就在昨天,7月13号,广西招生考试院公布了“2019年普通高校招生本科第一批最低投档分数线”。不知道,参加第一批志愿填报的考生们,你们过线了…

Android 4.4及以上系统下应用的状态栏颜色渐变效果的实现

上一篇转载的博文里讲到了怎么开启状态栏透明的效果,不过如果在有ActionBar的情况下,会出现状态栏透明而ActionBar横亘在状态栏和内容之间的丑陋情况,如下图: 通过百度之后,发现了GitHub上有个项目可以实现从ActionBar…

学习Spring-Cloud –基础结构和配置

我有机会与Spring-Cloud一起创建了一组云就绪微服务的样本集,Spring-Cloud如何使不同的基础架构组件和服务很好地协同工作给我留下了深刻的印象。 我习惯于基于基于Netflix OSS的堆栈创建微服务,通常在Netflix堆栈中, Eureka被认为是微服务进…

【APICloud系列|6】使用APICloud接入客服系统美洽获取Appkey配置

1.使用超级管理员(没有注册的提前注册登录一下)登录美洽:https://app.meiqia.com/ 2.找到设置——SDK 3.点击添加APP配置 4.上传

架构(三层架构)、框架(MVC)、设计模式三者异同点

前言: 本博客主要针对架构、框架和设计模式三者的差别、还有三层和MVC的差别进行讨论、对于这三者一点都不了解的、请点在维基和百度百科上补补课、这里就不发链接了 软件架构(software architecture) 软件的架构是系统的一个草图、阐述了各个…

轩逸车联网功能怎么用_北斗已建设完成,那“北斗导航”怎么用?“短报文功能”怎么用?...

6月23号长征三号乙运载火箭将北斗导航系统(BDS)最后一颗卫星,也就是第55颗卫星成功发射升空,这是我国全球导航系统的收官之作,整个导航系统建设耗时20年。中国北斗(BDS)是继美国(GPS)、俄罗斯(GLONASS)第三大成熟的全球定位导航系统&#xff…

nba2k19登陆显示你与服务器,NBA2K19无法登陆了?NBA2K19连不上服务器怎么办?[图]...

NBA2K19是一款很不错的篮球类游戏,喜欢篮球的朋友一定不要错过了!大家都知道这款游戏可以联网也可以单机,但是有朋友反映NBA2K19连不上服务器,这是什么原因呢?NBA2K19连不上服务器:1、卸载其他NBA2K学习版内…