├── 接口请求参数如何定义.md ├── 如何优雅的使用配置中心.md ├── 服务注册组件如何选择.md ├── 如何优雅的进行服务更新发布.md ├── 如何优雅的使用接口文档.md ├── 网关应该承担什么功能和能力.md ├── 如何规划日志文件和格式.md ├── 服务器目录如何规划.md ├── 微服务应该有哪些监控点.md ├── 多个节点定时任务如何设置.md ├── 接口返回数据结构以及状态码如何定义.md ├── readme.md ├── 微服务如何执行部署操作.md └── 所依赖的基础组件的版本如何进行选择.md /接口请求参数如何定义.md: -------------------------------------------------------------------------------- 1 | - 请求方式有很多,但是由于为了统一,所以目前所有的接口的定义都定义成为了POST方式,这样虽然不完全遵守restful的定义,但是也有一些好处。 2 | - 可以对参数进行一定的保护 3 | - 可以避免超出`GET`请求参数长度限制 4 | - 接口定义都是尽量都是由一个单词组成,如果出现多个单词的情况下,通过中划线`-`来进行分割。不使用Java的驼峰命名法。 5 | - 接口业务参数如果是简单类型,并且数量少于3个,则使用`application/x-www-form-urlencoded`方式进行接受。如果是复杂对象类型,那么就使用`application/json`放手进行接受。 6 | - 一些公共参数比如`设备号、版本号、ip等`都放到HTTP的Header里面,不要和业务接口参数混到一起。 7 | 8 | ### 公共请求参数总结 9 | - 设备id 10 | - 用户凭证 11 | - 终端类型id 12 | - 基础信息(平台|系统版本|渠道|版本号|机型|网络类型) 13 | - 请求唯一标志(traceid|spanid) 14 | - 地理信息 (经度|纬度) 15 | - 客户端时间 16 | - 接口所在页面名称 17 | -------------------------------------------------------------------------------- /如何优雅的使用配置中心.md: -------------------------------------------------------------------------------- 1 | 配置中心我们设计的初衷就是尽量简单,所以直接使用了springcloud提供的spring-cloud-config,因为结合git他能满足目前我们所有的需求。 2 | 3 | - 优势 4 | - spring-cloud-config和整个springboot框架完美结合,对于开发人员基本没有感知 5 | - 通过git来管理文件,可以很好的记录历史修改,并且通过git来管理提交记录 6 | - 配置文件有优先级,可以很好的完成默认配置,统一配置,个性化配置的需求 7 | - 配置文件可以区分环境,针对不同的环境使用不同的配置文件,很好的区分不同的项目,便于维护 8 | - 可以对于敏感性信息进行加密,防止原始的用户名和密码的泄漏 9 | - 可以动态刷新变量配置,实现不停机更新变量配置 10 | 11 | - 踩过的坑 12 | - 通过`basedir`配置,改变配置文件存放路径,要不然会存在`/tmp`目录下面,导致读取配置文件丢失 13 | - 获取配置的时候需要快速失败,防止网络不通的情况下继续启动服务 14 | - 通过`force-pull`配置,尽量每次启动的时候从git来重新拉取配置 15 | - 刷新配置,在服务实例不多的情况下尽量不要通过`bus`来批量更新,因为服务不多的情况下手动执行每个实例更加可控。 -------------------------------------------------------------------------------- /服务注册组件如何选择.md: -------------------------------------------------------------------------------- 1 | 微服务中,最重要的就是服务注册中心,在springcloud的体系中,一般常用的注册中心,就是`eureka`和`consul`。因为springcloud默认使用的是`eureka`,所以我们在工作中也是选择的`eureka`作为微服务体系中的服务注册中心。 2 | 3 | - 优势 4 | - eureka和spring整个体系结合的比较紧密,部署方式简单,并且部署之后,自带有简单web页面来查看服务状态和一些简单的健康检查 5 | - eureka是通过java进行开发的,对于java体系栈的团队来说更加友好 6 | - eureka是保证CAP中的A(高可用)、P(分区容忍) 7 | - 可以通过http的方式请求eureka的数据,相对获取数据比较简单 8 | 9 | - 劣势 10 | - eureka只能通过自带的metedata存储一些数据,并且metedata是挂载实例级别的。不提供kv的存储,没办法针对服务级别设置对应的属性 11 | - 对于同一个服务,默认不具备服务分组或者打标签的功能,对于一个注册中心里面的所有服务都是一样的 12 | - eureka目前不支持watch功能,只能通过轮训去更新服务状态,如果服务多的话,那么相对的造成服务器的压力会比较大,相对性能会比较差一点。不过目前我们的服务个数在100个之内,所以性能不是主要问题 -------------------------------------------------------------------------------- /如何优雅的进行服务更新发布.md: -------------------------------------------------------------------------------- 1 | 微服务更新是一个超级频繁的操作。并且有很多细节需要注意,才能保证服务能够无缝的进行更新和升级。在实际的工作中总结了一些必要的步骤,下面来详细说明一下 2 | 3 | - 执行命令`systemctl stop`的时候,会发出143信号,`springboot`会接受这个信号,触发`ContextClosedEvent`事件。 4 | - 在接受到`ContextClosedEvent`事件的时候,主程序应该有一段时间的等待时间(一般15秒)。因为`eureka-client`在接受到这个信号的时候,会告诉`eureka`需要把实例标记成`down`状态。需要等待其他客户端更新状态。可以通过修改相关的`eureka`的配置来缩短更新时间。 5 | - 等待一段时间后,其他客户端都进行了更新,然后获得`tomcat`的线程池,执行`shutdown`方法,并且设置最长等待时间(一般15秒),如果到达最长时间线程池还没有正常结束,则通过`shutdownNow`方法,强制结束 6 | - 用新的jar包替换更新之前的老jar包 7 | - 执行命令`systemctl start`启动服务 8 | - 等待30s后(一般启动时间为30s左右),通过访问`/actuator/health`来获得该服务的健康状态。 9 | - 如果失败则停止后续实例的发布,如果成功则继续发下一个实例。 10 | - 根据不同的状态进行相关的责任人的通知。 -------------------------------------------------------------------------------- /如何优雅的使用接口文档.md: -------------------------------------------------------------------------------- 1 | 现在微服务的开发模式,避免不了前后端进行联调的工作。所以后端定义了接口,是需要输出给前端开发人员的。 2 | 3 | - 目前java体系使用最多的是`springfox`进行集成,网上有很多相关的文章和代码,这里就不着重介绍了。下面讲讲在工作中发现的`springfox`的优势和劣势 4 | 5 | ### 具有的优势 6 | - 和`SpringBoot`集成相对简单,只需要引入对应的jar包,进行一些简单配置就可以使用 7 | - 接口文档页面随着进程一起启动,一起关闭,并且直接可以访问当前服务的接口,方便本地和测试环境的开发和调试 8 | - 和`eureka`方便进行结合,直接从`eureka`可以通过链接地址点到对应的服务swagger页面 9 | 10 | ### 存在的劣势 11 | - 如果是微服务,那么每个实例启动都会带有接口文档页面,造成微服务的jar包相对臃肿、服务启动时间变长 12 | - 文档应该和服务不进行耦合,没有服务应该前端人员也可以查看接口文档 13 | - 只能访问本地进程的服务 14 | - 对于没有外网地址的云主机,无法打开接口文档页面,进行调试 15 | 16 | ### 现有的问题 17 | - 目前我们服务部署在阿里云上面,并且微服务部署的服务器,没有外网地址,所以不能直接使用`springfox`进行集成,办公网络无法进行访问。 18 | - 微服务启动时间变长,想尽量减少依赖的jar包,提升服务启动速度。 19 | - 不想文档页面依赖于启动的服务,需要进行解耦 20 | 21 | -------------------------------------------------------------------------------- /网关应该承担什么功能和能力.md: -------------------------------------------------------------------------------- 1 | 网关是微服务的入口,所以有很多事情可以在网关做,网关也是所有流量的总入口。是最重要的基础服务。目前总结一下,我们的网关已经实现的功能和还没有实现的功能。 2 | 3 | 4 | ### 已经实现的功能 5 | - 网关健康检查逻辑 6 | - 根据版本号限制访问接口逻辑(接口最低支持的app版本号) 7 | - 内部接口访问保护逻辑(接口仅仅只暴露给内部服务) 8 | - 接口权限验证逻辑(接口仅仅只暴露给某些拥有身份的用户) 9 | - 参数完全透传,不做任何解析(针对第三方格式不统一的接口使用) 10 | - 维护功能逻辑(针对接口开启维护页面) 11 | - 解码客户端参数逻辑 12 | - 唯一请求traceid的接收或者生成 13 | - 修改请求参数逻辑 14 | - 用户唯一凭证解析用户id和身份逻辑(通过用户的ticket和确定算法,得到用户的基础信息) 15 | - 重复请求拒绝逻辑 16 | - 对外路径和对内路径转换映射逻辑(外部路径:内部路径 == N:1) 17 | - 记录用户请求真实ip逻辑 18 | - 访问日志记录逻辑 19 | - 内部接口审计记录逻辑 20 | - 前端跨域CORS的设置逻辑 21 | - 灰度流量请求分发逻辑 22 | - 接口性能监控和指标度量采集逻辑 23 | 24 | ### 未实现的功能 25 | - 接口和服务限流逻辑 26 | - 用户和设备禁用逻辑 27 | - 接口数据缓存逻辑 28 | - SSL认证逻辑 29 | 30 | ### 实现大体方法 31 | - 网关通过注册中心获取微服务实例 32 | - 微服务注册到注册中心,并且通过定时push元数据到注册中心 33 | - 网关定时从注册中心轮训的pull元数据,并且记录在内存中 34 | - 针对不同的请求,根据所配置的元数据来进行不同的策略 35 | 36 | -------------------------------------------------------------------------------- /如何规划日志文件和格式.md: -------------------------------------------------------------------------------- 1 | - 日志文件存储地址: 之前规定了业务日志存放的地址为`/data/logs/service`,然后在目录下面,可以再创建一层日期`yyyy-MM-dd`目录,然后再以小时为文件名创建文件`hh.log`。最终文件为`/data/logs/service_name/yyyy-MM-dd/hh.log`。这样可以保证查找文件可以根据时间来快速定位,也可以保证一个文件内容不会太大。 2 | 3 | - 日志文件级别: 一般来说可以把ERROR级别的日志进行独立,有助于每天的日常检查,应该ERROR级别的错误文件不应该存在,如果存在ERROR就应该进行处理,然后可以对于所有日志(包括INFO、WARN、ERROR)都输出到`hh.log`文件里面,因为出现错误ERROR日志,也需要根据INFO里面的上下文进行问题定位和排查 4 | 5 | - 日志文件格式: 现在定义的日志格式为`[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%t] [${applicationName}] [%X{traceId}] [%X{DEVICE-ID}] %-5level %logger{50} - %msg%n`, 6 | - `%d{yyyy-MM-dd HH:mm:ss.SSS}` 日志记录时间 7 | - `%t` 为线程号 8 | - `${applicationName}`为服务名称,可以快速定位具体什么服务。 9 | - `%X{traceId}`为请求id,用于路径跟踪,一次请求一个唯一的id,有助于排查线上问题 10 | - `%X{DEVICE-ID}`为设备id,用于确定发起请求的设备id,有助于排查线上问题 11 | - `%-5level`为日志级别 12 | - `%logger{50}`为所在类名 13 | - `%msg`具体的日志 14 | 15 | -------------------------------------------------------------------------------- /服务器目录如何规划.md: -------------------------------------------------------------------------------- 1 | ## 目录规划 2 | 3 | 类似于linux系统,什么目录里面放什么文件,都是很有讲究的。由于微服务会随着业务而增加,定义统一的目录标准也是有必要的。这种约定的东西使得其他人接手或者新人熟悉,也是很快的。 4 | 5 | ### 系统分析 6 | - 一般linux系统都分为 系统盘(系统自带的硬盘)和 外部挂载盘(额外挂载的硬盘) 7 | - 系统盘: 用于存放系统产生的日志和数据,这种盘空间一般都很小,不适合用于存放业务系统产生的数据 8 | - 数据盘: 用于业务系统产生的数据和日志,通常空间比较大。空间使用情况和具体的业务紧密相关 9 | 10 | ### 目录规划 11 | 12 | - 数据盘挂载点: 假设数据盘的挂载点为 `/data` 13 | - 项目存放: 项目以服务名称放在 `/data` 目录下面。举个例子`/data/service_name/service_name.jar` 14 | - 日志存放: 日志全部统一放在 `/data/logs` 目录下面,并且根据不同的服务存放不同的目录下面。举个例子`/data/logs/service_name` 15 | - 配置存放: 由于使用了SpringBoot,所有的配置应该包含在jar包之中。额外的配置,比如一些证书或者第三方的配置,都放在`/data/config`目录下面。举个例子`/data/config/service_name` 16 | - 数据存放: 由于服务可能会产生一些临时文件,临时文件可以存放到`/data/data`目录下面。举个例子`/data/data/service_name` 17 | 18 | ### 统一如何落地 19 | - 这个只是目录约定,那么如何确保大家都是用统一的目录,如果只靠文档是不够的,所以可以采用统一配置的方式,并且设置默认配置,不让开发人员感知到这些约定的东西。 20 | - 具体落地可以查看[如何优雅的使用配置中心]和[如何规划日志文件和格式](如何规划日志文件和格式.md) 21 | -------------------------------------------------------------------------------- /微服务应该有哪些监控点.md: -------------------------------------------------------------------------------- 1 | 微服务由于服务众多,所以业务的监控是必不可少的,我们在做微服务监控的话,主要做了几个方面的监控 2 | 3 | ### 监控分类 4 | - metrics监控 5 | - trace监控 6 | - 健康性监控 7 | - 日志监控 8 | 9 | ### 监控做法 10 | - 通过springboot配合micrometer进行使用,底层存储使用prometheus来进行存储 11 | - prometheus从eureka上面获取服务节点信息,并且每天晚上更新一次 12 | - 通过prometheus的alter-manager进行报警通知 13 | - alter-manager把通知发送到一个我们的对接钉钉服务,然后通过这个 14 | 服务通过钉钉的机器人进行通知 15 | 16 | ### metrics监控指标 17 | - 服务qps 18 | - 服务分位数 19 | - 服务错误返回数 20 | - 服务接口请求次数的top 21 | - 服务接口95%请求时间top 22 | - cpu使用率 23 | - cpu个数和负载 24 | - jvm堆内存/非堆内存 25 | - jvm线程 26 | - jvm的类数 27 | - gc的暂停时间和次数 28 | - tomcat的活跃线程 29 | - 数据库连接数 30 | - 日志行数 31 | - 业务通过api自己上报的业务数据 32 | 33 | 34 | ### trace监控指标 35 | - 通过zipkin来产生唯一的traceid、spanid 36 | - 产生的数据会通过kafka发送,然后传给下游服务 37 | - zipkin-server收集数据,存储到es 38 | - zipkin-web从es获取数据,进行展示 39 | 40 | ### 健康性检查 41 | - 通过从eureka获取服务节点,并且从服务请求数据和状态 42 | - 如果服务状态不健康, 进行报警通知 43 | - 通过接口查看错误码,错误码达到一定比率,进行报警通知 44 | 45 | ### 日志监控 46 | - 通过sentry来监控error日志,对于error日志,则通过邮件或者钉钉进行发送。实时排查服务端异常 -------------------------------------------------------------------------------- /多个节点定时任务如何设置.md: -------------------------------------------------------------------------------- 1 | 定时任务是一个常见的需求,如果只是单机部署的话, 可以直接使用springboot自带的`schedule`来完成。但是在分布式系统中,如何确保多个节点在同一时间只有一个服务执行定时任务? 2 | 3 | 在实际的过程中,换过几个定时任务框架,针对使用过的框架做一个简单的说明和分析。 4 | 5 | ### 框架对比和选择 6 | 7 | - 最开始使用的是`xxl-job`,这个项目是个人开发者维护的,不过github上star还是比较多的,所以就准备做个尝试。开始使用的时候就发现它是一个集中管理和集中调度的模式。有一个中心节点来进行任务分配,并且分配的方式还是通过自带的rpc调用方式,还需要在springboot服务中部署额外的jetty服务,感觉和现在的模式冲突太大,并且给官方提供了意见,不过被官方给否决了。后面查看了xxl-job的源码,感觉代码质量很一般,所以最终放弃了这个框架。 8 | - 然后引入了`elastic-job`,算是当当开源的框架,代码质量明显比`xxl-job`有了提升,他没有中心节点,是通过zk来实现了分布式的调度,支持的模式种类比较多,不过常用的只有一种模式,就是在多个节点中选择一个节点进行调度执行,算是比较完美的解决了定时调度的问题。但是随着springboot和springcloud的基础框架不停的迭代和升级,发现`elastic-job`已经没有更新,并且社区逐渐不活跃,作者也把主要的精力转移到另外的项目里面,这一块的维护力度明显下降。所以也打算选择新的框架来替换`elastic-job` 9 | - 本着项目轻量和简洁的目的,后面发现了`shedlock`这个项目,仅仅是利用底层存储(mysql、redis等)作为分布式锁。通过自定义的注解,并且结合springboot原生的`schedule`来完成分布式调度的执行的功能。他设计目标非常明确,并且代码十分简单,代码质量也不错,底层的依赖也特别少,并且也在持续更新。所以最后用`shedlock`替换了`elastic-job`,目前使用得也十分稳定。不过`shedlock`由于功能很基础,后面自己通过springboot的`endpoint`来进行了功能的扩展,实现了定时任务的触发、停止、改变调度周期等常规需求,来弥补一些业务上的需求。最终减少了基础组件依赖的同时高效的完成了目标。 -------------------------------------------------------------------------------- /接口返回数据结构以及状态码如何定义.md: -------------------------------------------------------------------------------- 1 | ### 数据返回格式 2 | - 正常返回 3 | - `applicaiton/json`格式进行返回数据 4 | - `data`具体的业务数据 5 | - `http status code`为200 6 | - `traceId`为唯一的请求id 7 | - 业务逻辑异常,为了统一返回的数据结构,统一使用了[zalando/problem](https://github.com/zalando/problem)项目作为返回的数据结构。主要包括: 8 | - 定义统一的业务异常类,然后统一捕获该异常类,然后转换数据结构。 9 | - `applicaiton/json`格式进行返回数据 10 | - `detail`为对应的错误信息简单描述 11 | - `code`为对应的业务错误码 12 | - `type`为异常请求的uri 13 | - `http status code`为200 14 | - `traceId`为唯一的请求id 15 | - 请求异常,统一识别异常类型,然后转换数据结构 16 | - `applicaiton/json`格式进行返回数据 17 | - `detail`为对应的错误信息简单描述 18 | - `code`为对应的业务错误码 19 | - `type`为异常请求的uri 20 | - `http status code`为400、401、403、404、405、406、415 21 | - `traceId`为唯一的请求id 22 | - 非业务异常类,统一处理 23 | - `applicaiton/json`格式进行返回数据 24 | - `detail`为对应的错误信息简单描述 25 | - `code`为对应的错误码 26 | - `type`为异常请求的uri 27 | - `http status code`为500、501 28 | - `traceId`为唯一的请求id 29 | 30 | ### 统一异常捕获 31 | - 通过继承[zalando/problem-spring-web](https://github.com/zalando/problem-spring-web)项目的`ProblemHandling`类 32 | - 通过使用`@RestControllerAdvice`来统一捕获异常 33 | - 额外定义业务异常类的统一处理方法 34 | - 通过使用`ResponseBodyAdvice`接口和`@RestControllerAdvice`来统一添加traceId和请求的uri -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## 说明 2 | 记录和总结在落地微服务的过程中的经验,项目地址: [https://github.com/dragontree101/java-microservice-experience](https://github.com/dragontree101/java-microservice-experience) 3 | 4 | ### 介绍 5 | 这个地方用来记录工作中在实践微服务的过程中的一些经验。如果大家觉得有更加好的,更加简单的解决方案,欢迎讨论。如果你觉得对于你工作所有帮助,希望能够给一个star,谢谢! 6 | 7 | 公司目前主要是基于 `java + spring全家桶` 来构建微服务体系。 8 | 9 | 本项目以问题的形式提出,回答的方式从三方面的进行回答。 10 | 11 | - 技术的选型的考虑 12 | - 遇到的问题以及对问题的思考和解决方案的确定,以及部分细节实现的描述 13 | - 现在遇到的问题 14 | 15 | 16 | ### 关于转载 17 | 如果需要引用到本仓库的一些东西,必须注明转载地址!!!毕竟大多都是手敲的,或者引用的是我的原创文章,希望大家尊重一下作者的劳动😃😃😃! 18 | 19 | ### 如何对该开源文档进行贡献 20 | 笔记内容大多是手敲,所以难免会有笔误,你可以帮我找错别字。 21 | 很多场景我可能没有涉及到,所以你可以对其他一些场景进行补充说明。 22 | 23 | ### 讨论方式 24 | 有兴趣进行讨论交流和学习 25 | 26 | - [issues](https://github.com/dragontree101/java-microservice-experience/issues) 27 | - qq群: 743226681 28 | - 微信群 29 | 30 | 欢迎大家加入讨论 31 | 32 | 33 | ## 问题 34 | - [所依赖的基础组件的版本如何进行选择?](所依赖的基础组件的版本如何进行选择.md) 35 | - [微服务如何执行部署操作?](微服务如何执行部署操作.md) 36 | - [服务器目录如何规划?](服务器目录如何规划.md) 37 | - [如何规划日志文件和格式?](如何规划日志文件和格式.md) 38 | - [接口请求参数如何定义?](接口请求参数如何定义.md) 39 | - [接口返回数据结构以及状态码如何定义?](接口返回数据结构以及状态码如何定义.md) 40 | - [如何优雅的使用接口文档?](如何优雅的使用接口文档.md) 41 | - [服务注册组件如何选择?](服务注册组件如何选择.md) 42 | - [如何优雅的使用配置中心?](如何优雅的使用配置中心.md) 43 | - [多个节点定时任务如何设置?](多个节点定时任务如何设置.md) 44 | - [如何优雅的进行服务更新发布?](如何优雅的进行服务更新发布.md) 45 | - [网关应该承担什么功能和能力?](网关应该承担什么功能和能力.md) 46 | - [微服务应该有哪些监控点?](微服务应该有哪些监控点.md) 47 | 48 | 49 | -------------------------------------------------------------------------------- /微服务如何执行部署操作.md: -------------------------------------------------------------------------------- 1 | 微服务的目标就是为了能够快速响应产品迭代、快速发布运用而生的。所以微服务的部署频次会变得很高,那么如何快速的完成部署呢? 2 | 3 | ## 持续集成选择 4 | - jenkins: 目前最常用的ci非jenkins莫属了,jenkins功能强大,插件众多,社区和用户也十分活跃,代码也是完全开源的,对于大规模微服务部署是一个不错的选择。 5 | - teamcity: 是jetbrain公司出品的ci,部署简单,使用方便,但是是收费的,免费使用只能配置100个微服务,由于我们现在微服务的规模只有80左右,所以选择了配置简单的teamcity 6 | 7 | ## 环境准备 8 | - 在CentOS 7上每个机器都创建统一的service模版文件,然后通过ci传入不同的微服务名称和相关启动参数,来创建微服务所对应的service文件。然后通过systemctl的命令来启动、关闭和重启对应的微服务 9 | 10 | ``` 11 | [Unit] 12 | Description=${service_name} #服务名称 13 | Requires=network.target 14 | After=network.target 15 | 16 | [Service] 17 | User=java #启动服务的用户 18 | Group=java #启动服务的组 19 | Type=simple 20 | WorkingDirectory=/opt/apps/${service_name} 21 | Environment=JAVA_HOME=/usr/java/default 22 | TimeoutStopSec=60 23 | ExecStart=java -Xms1G -Xmx1G -jar ${service_name}.jar --spring.profiles.active=pro 24 | SuccessExitStatus=143 25 | Restart=always 26 | RestartSec=5 27 | StandardOutput=null 28 | 29 | [Install] 30 | WantedBy=multi-user.target 31 | ``` 32 | 33 | ## 服务部署 34 | 35 | - 更新代码 36 | - 根据源码构建项目,生成jar包 37 | - 上传jar包到对应的备份目录 38 | - 执行停止服务命令: `systemctl stop service_name` 39 | - 移动jar包到对应的启动目录 40 | - 执行启动服务命令: `systemctl start service_name` 41 | - 然后通过health check检查服务正确性 42 | - 启动成功之后,把相关代码在git上打一个tag,为了方便之后回滚 43 | 44 | 45 | ## 踩过的坑 46 | - 当一个服务还在运行的时候,如果用新的jar包替换老的jar包,那么正在运行的进程会抛出异常,导致服务不可用,所以我们先`stop`服务,然后再拷贝jar到对应位置,然后在`start`服务,这样可以保证服务正常关闭和启动 47 | - 因为部署微服务是个连续的过程,必须要通过health check来保证当前服务启动正常,才能进行后续的微服务的部署 48 | - 停止服务是通过service文件里面的`SuccessExitStatus=143`配置来停止的。不要直接通过`kill -9`的命令来停止服务,那样会引起微服务正在进行的处理失败,导致接口返回异常 49 | - service文件里面的`Restart=always`配置可以保证微服务进程意外死亡时自动重启,进一步保障的服务的稳定性 -------------------------------------------------------------------------------- /所依赖的基础组件的版本如何进行选择.md: -------------------------------------------------------------------------------- 1 | ## 所依赖的基础组件的版本如何进行选择 2 | 3 | ### 操作系统(CentOS 7) 4 | - CentOS 7版本,CentOS是一个Linux的主流发行版本,并且内置了一些服务管理的能力(Systemctl),用于后续的服务发布和管理 5 | - 优势:目前基本所有的主流云产商都是支持的 6 | - 缺点:目前没有明显的大缺陷会影响服务部署和使用 7 | - 总结:建议大家选择CentOS 7,如果还没有从CentOS6、CentOS5升级的可以进行升级 8 | 9 | ### 开发语言(JDK11) 10 | - jdk11(2018-09-25正式发布)是自jdk8之后的首个长期支持版本(LTS),现在虽然jdk8是主流,但是相信之后大家也会逐步切换到jdk11的 11 | - 优势:jdk11引入了一些新的特性,并且对于对比于jdk8,gc算法使用G1作为了默认的gc算法,并且引入了少量的新特性。目前主流的基础框架SpringBoot和SpringCloud的新版本都已经支持JDK11 12 | - 劣势:由于jdk11删除了一些默认包,导致从jdk8到jdk11的过程中会遇到无法找到一些Class的异常 13 | - 遇到的坑: 14 | 1. 一些老版本的ide不支持jdk11的编译,需要进行ide升级 15 | 2. 一些框架依赖jre里面的包,但是在jdk11里面被删除了,需要通过依赖显示引入 16 | 3. 少量第三方的`Encode`或者`Decode`算法,使用了jdk以前的`sun.misc`包里面的方法,还有一些使用了jdk里面的`tools`包,现在jdk11没有这些包了,导致程序出错。目前有仅仅遇到一些银行提供的包还在使用`sun.misc`包,并且没有提供有效的解决方案。 17 | 4. 一些大数据相关的组件(flink),目前还不支持jdk8 18 | 19 | - 总结:如果是微服务开发,可以选择进行升级,绝大部分框架或组件都支持jdk11,如果是大数据开发,不建议进行升级。由于工作中主要是为服务业务开发,所以已经完全升级到了jdk11 20 | 21 | ### 基础框架(SpringBoot 2.1.3 + SpringCloud G系列) 22 | - SpringBoot + SpringCloud 作为java语言微服务的标配,已经被大部分公司采用了,目前最新版本SpringBoot为2.1.3,SpringCloud为G系列,通过这两个大版本,基本可以覆盖80%依赖组件的版本,这样有利于统一版本管理。目前通过把SpringBoot + SpringCloud和剩余的20%基础依赖进行了一次二次封装,方便在公司内部进行版本管理和持续的升级所依赖的基础框架 [loc-framework](https://github.com/lord-of-code/loc-framework) 23 | - 优势:绝大部分的微服务功能目前Spring全家桶都可以覆盖,大大降低了开发成本,并且社区活跃,对于绝大部分的场景都有现成的解决方案,并且通过SpringBoot可以使得部署非常方便。 24 | - 劣势:整套技术所依赖的组件过多,大部分业务开发人员不需要掌握所有的东西,所以可以通过上面说的二次封装进行进一步的整体打包,屏蔽技术细节和统一版本 25 | 26 | - 总结:如果能够使用好SpringBoot + SpringCloud可以是的整个团队的效率大大提高。所以我个人认为SpringBoot + SpringCloud也是目前java语言微服务落地方案中最优选择。 27 | 28 | 29 | ### 总结 30 | 很多人问如何选择使用开源框架的什么版本?我建议是选择最新的稳定版本。有些人怕最新版本会有问题,不稳定。其实只要是一个活跃稳定的开源项目,如果这个版本有bug,那么一定会有人先遇到,并且提供解决方案。如果你是第一个遇到问题的人,那么恭喜你,你可以把问题上报给作者,或者自己修复提交pr给作者,也算对开源框架的贡献。 31 | 32 | 关于bug的问题,其实新版本和老版本都会有bug,新版本解决老版本的bug,并且也可能会引入新的bug。所以只要是正式稳定版本,我觉得就可以大胆使用,并且正视问题并且积极解决。 33 | 34 | 希望大家在使用框架的同时一定要多多关注版本号。这样对之后排查问题也是很大的帮助。 --------------------------------------------------------------------------------