关于spring-cloud:开源微服务如何选型Spring-CloudDubbogRPCIstio-详细对比

不管您是一名开发者、架构师、CTO, 如果您曾深度参加在微服务开发中,那么置信您肯定有过开源微服务框架或体系选型的疑难:Apache Dubbo、Spring Cloud、gRPC 以及 Service Mesh 体系产品如 Istio,到底应该选型哪一个?这篇文章对这几个框架进行了具体的阐明,并在选型方面给了肯定的领导意见,置信能给微服务开发者带来肯定的帮忙。 须要留神的是,这篇文章的作者有深度 Apache Dubbo 社区参加教训,因而整篇文章是以 Dubbo 为根底开展的,通过将 Dubbo 与其余组件之间的分割与差别主观、通明的展示进去,来向读者出现几款开源产品的劣势和实用场景。整篇文章中有局部内容突出了 Apache Dubbo 我的项目的劣势,请大家在浏览过程中放弃对这点的意识,但它总体上并不影响咱们从总体上理解每个产品并取得具备价值的选型领导。 Dubbo 与 Spring Cloud 从上图咱们能够看出,Dubbo 和 Spring Cloud 有很多相似之处,它们都在整个架构图的雷同地位并提供一些类似的性能。 Dubbo 和 Spring Cloud 都偏重在对分布式系统中常见问题模式的形象(如服务发现、负载平衡、动静配置等),同时对每一个问题都提供了配套组件实现,造成了一套微服务整体解决方案,让应用 Dubbo 及 Spring Cloud 的用户在开发微服务利用时能够专一在业务逻辑开发上。Dubbo 和 Spring Cloud 都齐全兼容 Spring 体系的利用开发模式,Dubbo 对 Spring 利用开发框架、Spring Boot 微服务框架都做了很好的适配,因为 Spring Cloud 出自 Spring 体系,在这一点上天然更不用多说。尽管两者有很多相似之处,但因为它们在诞生背景与架构设计上的微小差别,两者在性能、实用的微服务集群规模、生产稳定性保障、服务治理等方面都有很大差别。 Spring Cloud 的劣势在于: 同样都反对 Spring 开发体系的状况下,Spring Cloud 失去更多的原生反对。对一些罕用的微服务模式做了形象如服务发现、动静配置、异步音讯等,同时包含一些批处理工作、定时工作、长久化数据拜访等畛域也有涉猎。基于 HTTP+JSON 的通信模式,对于开发、测试、上下游体系接入等更敌对,老本更低。Spring Cloud 官网具备绝对欠缺的入门文档和演示 demo 和 starters,包含书籍材料等,让开发者上更易于上手。Spring Cloud 的问题有: ...

August 28, 2023 · 2 min · jiezi

关于spring-cloud:Spring-Cloud-如何引入云原生网关创新微服务架构

在传统的微服务体系中,Spring Cloud Alibaba 和 Zuul 常被用作配合 Spring Cloud 应用的微服务网关。然而,这些传统的 Java 网关在面对大规模流量的场景下仍存在种种问题。例如 Zuul 因为采纳了非异步 IO 的架构,导致了其在面对高流量的状况下容易呈现阻塞的景象,Spring Cloud Gateway 也会在流量很大的状况下产生 Full GC 的状况,导致申请 RT 变长,影响用户体验和业务稳定性。因而咱们须要寻找一个新的选项,来代替这些传统的微服务网关。 Higress: Spring Cloud生态下微服务网关的新抉择Higress 是阿里巴巴开源的一款下一代云原生微服务网关。Higress 能够对接多种注册核心,包含Nacos/Zookeeper/Eureka 等,可能无缝集成 Spring Cloud 利用,对 Dubbo/Sentinel/OpenSergo 等微服务生态也有着深度的集成。与此同时,Higress 采纳 C++内核,相比于传统的 Java 网关来说性能更高,更稳固,比照Spring Cloud Gateway 和 Zuul 来说,性能能够晋升至2-4倍。另外,Higress 还人造兼容 K8s 的Ingress/Gateway API 规范,是一款更合乎云原生时代规范的微服务网关。 更多性能压测试验,请参考:https://mp.weixin.qq.com/s/45ZAc5CGfND46Ao3lbHefQHigress无缝对接Spring Cloud利用公布实战在古代软件架构逐步走向微服务化、云原生化的过程中,利用的更新和迭代的频率变得越来越快,如何在尽可能保障用户体验不受影响的状况下实现利用的迭代公布就显得至关重要。目前业界广泛采纳的几种典型的利用公布策略包含蓝绿公布、金丝雀公布、A/B Testing公布等。接下来本文将介绍如何应用Higress来实现Spring Cloud Alibaba利用公布的最佳实际。 前提条件装置Higress,并装置Istio CRD,参考Higress装置部署文档。装置Naocs,参考Nacos装置部署文档。Higress反对将Nacos,Spring Cloud利用部署于K8s集群内,或者独立于K8s进行部署。为了演示不便,本文将Higress,Nacos,Spring Cloud利用都部署在本地K8s集群。 1.通过Higress实现Spring Cloud利用的服务发现和路由1.1. 部署SpringCloudAlibaba利用apiVersion: apps/v1kind: Deploymentmetadata: name: spring-cloud-demo-v1spec: replicas: 1 selector: matchLabels: app: spring-cloud-demo template: metadata: labels: app: spring-cloud-demo spec: containers: - name: server image: higress-registry.cn-hangzhou.cr.aliyuncs.com/samples/spring-cloud-demo:v1 imagePullPolicy: IfNotPresent env: # 注册到的nacos的地址 - name: NACOS_REGISTRY_ADDRESS value: nacos-server.default.svc.cluster.local # 注册时携带的version元信息 - name: SPRING_CLOUD_NACOS_DEMO_VERSION value: v1咱们在k8s集群中部署如上Deployment,其中通过NACOS_REGISTRY_ADDRESS和SPRING_CLOUD_NACOS_DEMO_VERSION两个环境变量指定了Nacos的地址以及注册时携带的version元信息。SpringCloud利用的application.properties配置会读取这两个环境变量,如下所示: ...

July 4, 2023 · 2 min · jiezi

关于spring-cloud:openfeign集成spring-cloud-loadbalancer实现负载均衡流程

当咱们在我的项目中调用本人实现的Feignclient负载平衡中如何起作用?请看下图: 图一 在图一中咱们能够发现,在ConsumerController中调用自定义的DemoFeignClient办法时,通过spring容器中对DemoFeignclient的代理类的调用最终通过feign.SynchronousMethodHandler.invoke()->openfeign.loadbalancer.execute()->org.springframework.cloud.loadbalancer.blocking.client.FeignBlockingLoadBalancerClient.choose()->org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer.choose()这样的调用链,最终执行spring cloud loadbalaner中的轮询负载均横策略! 然而,上图中的这些要害类是如何组合起来发挥作用呢?请咱们一起持续剖析!spring cloud我的项目启动后,spring容器解析并加载LoadBalancerClientConfiguration.java配置文件(如下图所示)图二 而后将"reactorServiceInstanceLoadBalancer"注册到beanDefinitionMap中。而后会扫描咱们申明的controller,因为conroller中注入了DemoFeignClient,因而spring容器会递归创立DemoFeignClient,创立DemoFiegnClient过程中会通过AbstractAutowireCapableBeanFactory.obtainFromSupplier()注入instanceSupplier实例,也就是FeignClientFactoryBean实例! 上面是org.springframework.cloud.openfeign.FeignClientsRegistrar.registerFeignClient()办法次要逻辑: private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { //疏忽非核心代码片段 BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> { //设置url factoryBean.setUrl(getUrl(beanFactory, attributes)); //设置门路 factoryBean.setPath(getPath(beanFactory, attributes)); //decode404 布尔值 factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404")))); Object fallback = attributes.get("fallback"); //设置fallback if (fallback != null) { factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback : ClassUtils.resolveClassName(fallback.toString(), null)); } //设置fallback工厂类 Object fallbackFactory = attributes.get("fallbackFactory"); if (fallbackFactory != null) { factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory : ClassUtils.resolveClassName(fallbackFactory.toString(), null)); } //实例化咱们申明的DemoClient return factoryBean.getObject(); });}这还没有完,org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject()中最终执行loadBalance();在loadBalance()中实例化FeignInvocationHandler; ...

July 4, 2023 · 1 min · jiezi

关于spring-cloud:Spring依赖可视化分析与微服务模块划分

前言19年的时候,次要负责微服务治理平台BOMS交付工作,期间客户提到在微服务模块拆分方面须要征询。 过后我还只是技术负责人,没有深刻理解这方面的需要,只是网上找了点材料发给客户,再联合资料简略讲一下“正交合成”等准则。 起初据说客户找到埃森哲做培训,每天的培训费用大略是好几千,前面领导打算让我当架构师,惋惜我回绝了,当初想想十分惋惜,但我并不是想做培训老师, 而是想能不能制作一款可视化的剖析工具,给微服务模块拆分提供可量化的拆分根据,以及评估拆分前后的性能指标变动。 Spring依赖剖析我首先想到基于代码扫描的动态剖析,得益于 Spring 的架构劣势,做起来并不难,只须要把 Spring IoC 容器保留的 Bean 信息导出来即可,而正好 Spring Boot Actuator 模块刚好提供 /beans 接口用于导出Bean信息,Bean信息结构大略如下: {    "contexts": {        "school-service": {            "beans": {                "spring.jpa-org.springframework.boot.autoconfigure.orm.jpa.JpaProperties": {                    "aliases": [],                    "scope": "singleton",                    "type": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties",                    "resource": null,                    "dependencies": []                } } } }}对于没有应用 Spring Boot 的老旧我的项目,以下就是参考 Actuator 源码实现的代替实现: ...

June 8, 2023 · 4 min · jiezi

关于spring-cloud:2022升级版Spring-Cloud-进阶-Alibaba-微服务体系自媒体实战

download:2022升级版Spring Cloud 进阶 Alibaba 微服务体系自媒体实战Spring Cloud 进阶 Alibaba:微服务架构下的可靠性、性能与平安作为以后风行的微服务框架之一,Spring Cloud 在构建分布式系统方面施展着重要作用。随着企业数字化转型以及云计算技术的一直遍及,越来越多的企业开始关注微服务架构在实现业务翻新、进步 IT 效率、保障数据安全等方面带来的劣势。 而在泛滥的微服务解决方案中,基于阿里巴巴开源技术的 Spring Cloud Alibaba 也越来越受到企业的关注和青眼。本文将介绍 Spring Cloud Alibaba 的特点和劣势,并从可靠性、性能和平安三个方面论述如何进一步晋升 Spring Cloud 在微服务架构下的价值。 一、Spring Cloud Alibaba 简介Spring Cloud Alibaba 是由 Spring Cloud 和阿里巴巴联合推出的微服务整体解决方案。它利用 Spring Cloud 生态圈中最罕用的组件和利用程序库,联合阿里巴巴的优良开源产品,帮忙企业疾速搭建分布式应用程序。 Spring Cloud Alibaba 包含了 Spring Cloud Alibaba 微服务框架和 Spring Cloud Alibaba 生态系列产品两局部。其中微服务框架包含 Spring Cloud Alibaba 的外围组件,例如 Nacos 注册核心、Sentinel 服务降级与熔断、Seata 分布式事务等;而生态系列产品则包含 Alibaba Cloud SDK、Logistics 算法库等。 相较于其余微服务框架,Spring Cloud Alibaba 具备以下劣势: 兼容 Spring 生态圈: Spring Cloud Alibaba 基于 Spring Cloud 实现,兼容 Spring Boot 和 Spring Cloud 的所有性能和个性。集成开箱即用: Spring Cloud Alibaba 整合了多个阿里巴巴自主研发的优良产品,如 Nacos、Sentinel、RocketMQ 等,提供了高效便捷的解决方案。轻量级高性能: Spring Cloud Alibaba 各个组件都是基于轻量化的应用程序构建,同时具备杰出的性能和可靠性。二、可靠性晋升在大型分布式系统中,各个服务之间会存在许多不可避免的故障和问题。因而,在微服务架构下实现高可靠性是十分必要的。Spring Cloud Alibaba 提供了多种工具和机制,帮忙企业实现微服务架构下的可靠性。 ...

June 2, 2023 · 1 min · jiezi

关于spring-cloud:SpringCloudalibabaVue开发仿社交小程序谪居卧病浔阳城

download:SpringCloudalibaba+Vue开发仿社交小程序莫辞更坐弹一曲音乐,古琴,传统文化莫辞更是中国现代文人雅士中的代表人物之一,他是一位喜好古琴的文艺青年。据史料记录,莫辞更经常在宴会上弹奏古琴,给人们带来美好的音乐享受。其中最有名的就要数他“更坐弹一曲”的故事了。 相传有一次,莫辞更加入了一个宴会,过后的氛围非常热烈,人们喝着酒、谈着天。突然间,有人向莫辞更提出了一个挑战:“你能一边弹古琴,一边吟诗吗?”莫辞更并不慌乱,他微笑着承受了这个挑战,而后开始演奏起古琴来。他的指尖轻捷地拨动着琴弦,音乐随之流淌而出,像一朵绽开的花,漂亮而动人。同时,他还口吟着本人创作的诗歌,将音乐与诗意完满联合在一起。 这一幕场景,让在场的众人为之倾倒。他们惊叹于莫辞更的琴艺、诗才和气派,也由衷地感触到了中国传统文化的博大精深。 莫辞更“更坐弹一曲”的故事,至今仍被前人传颂不衰。这个故事通知咱们,艺术能够逾越时空的界线,它是人类智慧和理性的结晶。古琴作为中国传统音乐的代表,有着博大精深的历史渊源和独特的韵味,而莫辞更则将其演奏得酣畅淋漓,彰显出了中国文化的魅力与底蕴。 在当今社会,咱们应该更加关注和弘扬传统文化,让这些古老而神秘的艺术模式在古代焕发新的光辉。同时,咱们也要向莫辞更这样的前辈学习,用本人的才华和致力去发明属于本人的经典,为传统文化的倒退奉献本人的力量。

May 14, 2023 · 1 min · jiezi

关于spring-cloud:2022升级版Spring-Cloud-进阶-Alibaba-微服务体系自媒体实战风月即勋名

download:2022升级版Spring Cloud 进阶 Alibaba 微服务体系自媒体实战WEB前端技术:从HTML、CSS到JavaScript的全面介绍随着互联网的遍及和倒退,WEB前端技术也变得越来越重要。本文将全面介绍WEB前端技术,包含HTML、CSS和JavaScript三方面的内容。 HTMLHTML(Hypertext Markup Language)是一种用于创立网页的标记语言。它通过各种标签和属性来形容网页上的内容和构造。HTML标签通常由尖括号突围,例如<html>、<head>、<body>等。HTML还反对链接、图片、表格、表单等性能,这些都是通过不同的标签和属性实现的。 CSSCSS(Cascading Style Sheets)是一种用于管制网页外观的样式表语言。它能够扭转文本的色彩、字体、大小,设置页面布局和款式等。CSS通过层叠规定来确定利用哪个款式,同时也反对选择器来抉择元素并为其利用款式。CSS还反对动画和转换等高级成果,能够让网页更加丰富多彩。 JavaScriptJavaScript是一种广泛应用于WEB前端开发的编程语言,它能够在网页中增加动态效果、交互行为、数据验证和操作等。JavaScript能够通过DOM(Document Object Model)和BOM(Browser Object Model)来拜访和管制网页元素。它还能够通过AJAX(Asynchronous JavaScript and XML)技术实现异步数据交互,使网页更加晦涩和疾速。 总之,WEB前端技术是创立网页和应用程序的关键所在。HTML、CSS和JavaScript三者相辅相成,独特构建了一个残缺的网页。通过学习WEB前端技术,开发者能够创立出高质量、高性能的网站和应用程序。

May 11, 2023 · 1 min · jiezi

关于spring-cloud:Spring-Cloud-Alibaba-应用如何平滑迁移至-IPv6

背景IPv4 协定(后文简称 IPv4)为互联网的倒退与遍及做出了重要奉献,但近年来,随着应用程序、数据和 IT 服务的爆炸式增长。当初协定设计过程中用来形容 IP 地址所采纳的 32 位二进制数格局的 IPv4 地址曾经于 2011 年[1]被申请耗尽,从那时起,全世界都曾经处于无新地址可用的场面。 IPv6 协定(后文简称 IPv6)作为 IPv4 之后被采纳的下一代互联网协议,相比 IPv4 协定中采纳 32 位来示意 IP 地址,其地址示意位数裁减到了 128 位,地址数量是 IPv4 所能提供的 2 的 96 次方倍。简略看数字可能显得不太直观,换成一句形容 IPv6 地址之多更直观和经典的话:“采纳 128 位示意地址的 IPv6 能够为地球上的每一粒沙子都调配一个 IP 地址”!此外,IPv6 协定其不仅能够解决 IPv4 协定中的地址短缺问题,同时也能为互联网提供更高效、更平安的网络通信。IPv6 协定在网络通信中提供了许多新的性能和劣势。例如,在数据传输和路由方面,其通过新的设计进步了效率和可靠性,缩小了网络拥挤和数据包失落的状况。此外,在平安畛域,其内置对 IPSec 的反对,能够更好地爱护网络中的数据传输平安,避免黑客攻击和窃取数据。 作为下一代互联网协议,向 IPv6 迁徙是将来的大势所趋。在我国,从 2014 年开始相干机构曾经逐渐进行向新用户和利用调配 IPv4 地址,开始全面商用 IPv6 协定[2]。在政府疏导测,近年来,陆续也出台了一系列相干领导文件例如:2017 年国务院公布的《推动互联网协议第六版(IPv6)规模部署行动计划》[3]、2021 年工业与信息化部公布的《IPv6 流量晋升三年专项行动计划(2021-2023 年)》[4]、2021 年网信办公布的《对于推动 IPv6 规模部署的领导意见》[5]等一直地在疏导企业从 IPv4 协定向 IPv6 协定迁徙。 但因为以后互联网中 IPv4 协定的利用规模十分大,对于用户来说,没方法通过规定一个工夫日期,从那一刻开始,所有互联网上的设施全副应用 IPv6,这是不事实的。一次性迁徙不仅在基础设施层面不可行,对企业用户来说,就算基础设施都能筹备结束,让其将少则上百,多则成千上万的利用实例在一段时间内一次性停机进行协定栈迁徙,无论是在危险上,还是老本上,对企业用户来说都是难以承受的!既然无奈一步到位,渐进式的 IP 地址迁徙成为以后的支流抉择。接下来本文将介绍一些支流渐进式的 IP 地址迁徙办法。 ...

March 27, 2023 · 2 min · jiezi

关于spring-cloud:Spring-Cloud-Alibaba-在-Proxyless-Mesh-上的探索

站在 2023 年的明天,Service Mesh 早已不是一个新兴的概念, 回顾过去 6 年多的倒退历程,Service Mesh 从一经推出就受到来自全世界的支流技术公司关注和追捧。 2016 年作为 Service Mesh 的元年,Buoyant 公司 CEO William Morgan 率先公布 Linkerd[1] ,成为业界首个 Service Mesh 我的项目,同年 Lyft 公布Envoy[2] ,成为第二个 Service Mesh 我的项目。2017年,Google、IBM、Lyft 联手公布了 Istio[3],它与 Linkerd / Envoy 等我的项目相比,它首次给大家减少了管制立体的概念,提供了弱小的流量控制能力。通过多年的倒退 Istio,曾经逐渐成为服务网格畛域管制立体的事实标准。2018年7月,Istio 1.0版本公布[4],标记着其进入了能够生产可用的时代,逐步也有越来越多的企业开始思考和尝试将服务网格利用于生产中。Istio 作为以后最风行的开源服务网格技术,它由管制立体和数据立体两局部形成。 在 Istio Mesh 架构中,其管制立体是一个名为 Istiod 的过程,网络代理是 Envoy 。Istiod 作为管制面的对立组件,负责对接服务注册发现、路由规定治理、证书治理等能力,Envoy 则是作为数据面通过 Sidecar 形式代理业务流量,Istio 和 Envoy 之间通过 xDS 协定接口实现服务发现、路由规定等数据的传递。Istiod 通过监听 K8s 资源例如 Service、Endpoint 等,获取服务信息,并将这些资源对立通过 xDS 协定下发给位于数据立体的网络代理。Envoy 则是独立于利用之外的一个过程,以 Sidecar 的形式(个别是以 Container 形式)随同业务利用 Pod 运行,它与利用过程共用同一个主机网络,通过批改路由表的形式劫持业务利用的网络流量从而达到为利用无侵入地提供如服务鉴权、标签路由等能力。 Proxyless MeshProxyless Mesh 全称是 Proxyless Service Mesh,其是近几年在 Service Mesh 根底上倒退而来的一种新型软件架构。Service Mesh 现实很饱满,但事实很骨感!通过一层代理尽管做到了对利用无侵入,但减少的网络代理开销对很多性能要求很高的互联网业务落地造成不少挑战。因而 Proxyless Mesh 作为一种在传统侵入式微服务框架与 Service Mesh 之间的折中计划,通过取众家之所长,为大量的非 Service Mesh 利用在云原生时代,拥抱云原生基础设施,解决流量治理等痛点提供了一种无效的解决方案。Service Mesh 和 Proxyless Mesh 架构区别如下图所示: ...

February 7, 2023 · 5 min · jiezi

关于spring-cloud:关于SpringCloudSpringBoot

一、对于SpringCloud、SpringBoot什么是Spring Boot用我的话来了解,Spring Boot就是整合了框架的框架,它让所有依赖都变得有序简略,你不必操心A.jar是什么版本,又依赖哪些版本的jar,它默认配置了很多框架的应用形式,就像 maven整合了所有的jar包,Spring Boot整合了所有的框架,第三方库的性能你拿着就能用。 Spring Boot的核心思想就是约定大于配置,所有由内定的束缚来主动实现。采纳 Spring Boot能够大大的简化你的开发模式,节俭大部分照搬照抄的老本,通过大量的代码就能创立一个独立的,它都有对应的组件反对。 它是由 Pivotal团队提供的全新框架,其设计目标是用来简化新 Spring利用的初始搭建以及开发过程。该框架应用了特定的形式来进行配置,从而使开发人员不再须要定义样板化的配置。 Spring Boot提供了很多”开箱即用“的依赖模块,都是以spring-boot-starter-xx作为命名的。上面列举一些罕用的模块。 spring-boot-starter-logging :应用 Spring Boot 默认的日志框架 Logback。spring-boot-starter-log4j :增加 Log4j 的反对。spring-boot-starter-web :反对 Web 利用开发,蕴含 Tomcat 和 spring-mvc。spring-boot-starter-tomcat :应用 Spring Boot 默认的 Tomcat 作为应用服务器。spring-boot-starter-jetty :应用 Jetty 而不是默认的 Tomcat 作为应用服务器。spring-boot-starter-test :蕴含罕用的测试所需的依赖,如 JUnit、Hamcrest、Mockito 和 spring-test 等。spring-boot-starter-aop :蕴含 spring-aop 和 AspectJ 来反对面向切面编程(AOP)。spring-boot-starter-security :蕴含 spring-security。spring-boot-starter-jdbc :反对应用 JDBC 拜访数据库。spring-boot-starter-redis :反对应用 Redis。spring-boot-starter-data-mongodb :蕴含 spring-data-mongodb 来反对 MongoDB。spring-boot-starter-data-jpa :蕴含 spring-data-jpa、spring-orm 和 Hibernate 来反对 JPA。spring-boot-starter-amqp :通过 spring-rabbit 反对 AMQP。spring-boot-starter-actuator : 增加实用于生产环境的性能,如性能指标和监测等性能。什么是Spring CloudSpring Cloud是一套分布式服务治理的框架,既然它是一套服务治理的框架,那么它自身不会提供具体功能性的操作,更专一于服务之间的通信、熔断、监控等。因而就须要很多的组件来反对一套性能。 ...

November 27, 2022 · 1 min · jiezi

关于spring-cloud:如何阅读-Spring-Cloud-OpenFein-源码

背景始终以来,应用 Spring Cloud OpenFeign 都是浏览官网文档,尽管也大略晓得其实现原理,但究竟是没有"证据"的。对于 Spring 的源码浏览,自认为是一件非常令人头疼的事件。最近,在学习 Feign 的原生 API,乘此机会,也就浏览一下 Spring Cloud OpenFeign 的源码,并将分享进去,心愿能帮到有须要的人吧。 概述对于 Spring Cloud OpenFeign 源码的博客有很多,然而,不晓得为什么,照着博客,一边读博客,一边读源码,还一边 debug,总是认为还有很多不分明的中央。究其原因,我认为,博客都是依照源码的流程解说,尽管附上了大段代码,可能还是无奈清晰的了解。不晓得你们是不是,反正我是这样的。 指标首先,咱们明确一下明天探索的问题: 咱们晓得,当咱们应用 @FeignClient,是应用了JDK动静代理,那么是如何实现的,那一步创立的代理类。当咱们晓得第一个问题后,咱们就根本分明整个流程了,那么,咱们就能够手写一个繁难的入门测试了。源码启动流程org.springframework.cloud.openfeign.EnableFeignClientsorg.springframework.cloud.openfeign.FeignAutoConfigurationorg.springframework.cloud.openfeign.FeignClientsRegistrarorg.springframework.cloud.openfeign.FeignClientsRegistrar#registerBeanDefinitionsorg.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClientorg.springframework.cloud.openfeign.FeignClientFactoryBean#getObjectorg.springframework.cloud.openfeign.Targeterfeign.Feign.Builder#buildfeign.SynchronousMethodHandler.Factoryfeign.ReflectiveFeign.ParseHandlersByNamefeign.ReflectiveFeign#ReflectiveFeignfeign.Feign#newInstancefeign.ReflectiveFeign#newInstancefeign.InvocationHandlerFactory#createfeign.InvocationHandlerFactory.Default#createfeign.ReflectiveFeign.FeignInvocationHandler#FeignInvocationHandler贴上图吧,看看完整版的 注册流程: 主动配置: 调用流程feign.ReflectiveFeign.FeignInvocationHandler#invokefeign.InvocationHandlerFactory.MethodHandler#invokefeign.SynchronousMethodHandler#invoke MyRpc通过下面的流程,咱们手写一个 RPC。 上面给出次要代码。 @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import({MyRpcRegister.class, MyRpcAutoConfig.class})public @interface EnableMyRpc {}getObject() @Datapublic class MyRpcFactoryBean implements FactoryBean<Object> { private String url; private String contextPath; private String name; private Class<?> type; private BeanFactory beanFactory; private MyClient myClient; @Override public Object getObject() { Map<Method, RpcBean> map = new HashMap<>(); Method[] methods = type.getMethods(); myClient = beanFactory.getBean(MyClient.class); for (Method method : methods) { Annotation[] annotations = method.getAnnotations(); String httpMethod = ""; String path = ""; for (Annotation annotation : annotations) { if (annotation.annotationType() == PostMapping.class) { httpMethod = "POST"; path = ((PostMapping) annotation).value()[0]; break; } else if (annotation.annotationType() == GetMapping.class) { httpMethod = "GET"; path = ((GetMapping) annotation).value()[0]; break; } else if (annotation.annotationType() == RequestMapping.class) { RequestMapping requestMapping = ((RequestMapping) annotation); httpMethod = requestMapping.method()[0].name(); path = requestMapping.value()[0]; break; } } RpcBean rpcBean = new RpcBean() .setUrl(url + contextPath) .setPath(path) .setHttpMethod(httpMethod) .setMyClient(myClient) ; map.put(method, rpcBean); } ClassLoader loader = type.getClassLoader(); return Proxy.newProxyInstance(loader, new Class<?>[] {type}, new MyRpcInvocationHandler(map)); } @Override public Class<?> getObjectType() { return type; }}handler ...

October 22, 2022 · 2 min · jiezi

关于spring-cloud:sofa模块化隔离

传统我的项目传统我的项目中有时会Klass service层间接调用Student service层的Bean去实现某些逻辑,当我的项目变得越来越大时,这种层与层之间的依赖关系变得十分复杂,不利于开发。多个团队同时开发时,本团队只心愿关怀本人负责的模块。这种状况下,就须要将模块于模块之间互相独立,也就是对模块做隔离,export能够提供的Bean,import须要的bean,这样也能让开发者分明每个模块依赖的货色。当我的项目收缩到须要去做服务化的时候,这样,拆分起来就非常简单了。 sofaSOFABoot 是蚂蚁金服开源的基于 Spring Boot 的研发框架。提供了很多性能,如扩大 Spring Boot 健康检查的能力,提供模块化开发的能力,减少模块并行加载和 Spring Bean 异步初始化能力,减少日志空间隔离的能力,减少类隔离的能力,减少中间件集成治理的能力,其中就有模块化隔离性能。 模块化隔离原理原理:基于 Spring 上下文隔离的模块化,用 Spring 上下文来做不同功能模块的隔离,在开发期和编译期,代码和配置也会分在不同 Java 工程中,但在运行期,不同模块间的 Spring Bean 互相不可见,然而所有的 Java 类还是在同一个 ClassLoader 下。 https://www.sofastack.tech/pr... sofa模块首先咱们须要创立一个基于sofa的模块,一个sofa模块与一般我的项目类似,多一个配置文件,使之可能被辨认成一个sofa模块。同时多个sofa模块又都在同一个Spring Boot 我的项目文件夹下。 .├── README.md├── build.gradle├── gradle│   └── wrapper├── gradle.properties├── gradlew├── gradlew.bat├── logs│   ├── health-check│   ├── infra│   ├── sofa-runtime│   └── spring.log├── pom.xml├── service-consumer│   ├── build│   ├── build.gradle│   ├── pom.xml│   └── src├── service-facade│   ├── build│   ├── build.gradle│   ├── pom.xml│   └── src├── service-provider│   ├── build│   ├── build.gradle│   ├── pom.xml│   └── src├── settings.gradle└── sofa-boot-run ├── build ├── build.gradle ├── pom.xml └── src对于每一个sofa模块,多一个sofa-module.properties 文件(src/main/resources 目录下) ...

October 5, 2022 · 1 min · jiezi

关于spring-cloud:2022升级版Spring-Cloud-进阶-Alibaba-微服务体系自媒体实战完结无密王盘分xiang

网潘货区:2022升级版Spring Cloud 进阶 Alibaba 微服务体系自媒体实战完结无密王盘分xiang网站SEO关键词优化的5个技巧对于企业来说,网站很重要。通过网站能够展现企业的产品和服务,与客户进行交换。然而,一个企业只有网站是不够的。还要做好SEO优化,让网站有一个好的排名。那么企业如何做好网站SEO优化呢?上面分享一下SEO网站优化办法和网站SEO关键词优化的五个小技巧。网站SEO优化的办法 1.设置网站的TDK(题目、形容和关键字)。 网站的题目和形容是关键词布局的重要组成部分,设置网站的题目和形容是十分重要的一步。个别题目蕴含3~5个关键词。倡议应用“_”、“|”等作为连接符,重要的关键词要放在后面的地位。个别通顺的句子蕴含3~5个关键词,句子不要超过80个汉字,160个英文字符。 2.公布与主题相干的优质内容。 网站要有明确的主题,每个版块的内容都要解释和撑持这个主题,版块之间要有清晰的逻辑关系和层次感。每一节的内容不要混同,不要与主题无关。更加重视为用户提供主题相干、品质更高的原创内容。 3.向网站图片增加文本形容。 网站展现的图片要加上图片的形容,能够帮忙搜索引擎索引网站的图片,从而进步网站相干主题的排名。 4.关上HTTPS性能 有很大的反对百度HTTPS网站。Https能够减少网站的信任度,爱护数据,防止龚攻打,同时进步网站的SEO排名。该性能在在线建站后盾的“设置-域名”中一键开启,无需放心细节问题。 5.建设友情链接并推广。 一部分搜寻后果来自内部链接和流量,这意味着越多高质量的网站链接到咱们的网站,咱们的网站排名就会越高。所以你能够去各大博客、论坛或者社交网站分享咱们的网站,减少曝光率。 6.留神网站收录。通过SEO综合查问工具,每天查看网站的收录和关键词排名。咱们能够通过md5.com.cn枫叶SEO网查问网站。关上网站后,在首页的输入框中输出要查问的网站,点击查问。稍等一下,能够看到网站的收录和关键词排名。 网站SEO关键词优化的5个技巧 1.网站关键词权重的聚合 应该和题目形容中设置的关键词统一。每一页都应该有不同的题目和形容。切记不要和其余页面一样。题目中关键词的数量应不少于三次。 2.调配关键字等级。 把关键词分成好的等级,外围关键词要放在首页,而后下一级词放在栏目页,长尾词放在内容页。这样清晰的层次结构会给搜索引擎留下很好的印象,整个网站的构造也会更清晰,对搜索引擎优化更敌对。 3.网站的标签和关键词密度 网站的三个标签要依照前后的程序写,否则引擎会依据网站关键词呈现的次数来确定网站关键词。另外,alt标签也很重要,它能够减少关键词的密度,也有利于引擎抓取。同时须要留神的是,引擎无奈抓取网站的图片。为了不影响网站的关上速度,增加时通常须要对图片进行压缩。 4.网站关键词超链接 网站的关键词要有超链接。文章中出现的关键词能够进行网站内容的互相链接,咱们能够链接到一个与网站内容相干的网页。这也是在关键词优化技巧中突出关键词的体现。事实上,内容中某些段落的题目和文章中加粗的段落能够通过比照暂停,以显示关键词。5.定期更新文章。 放弃网站每天定期更新文章。更新的内容尽量是原创或者高质量的伪原创。其次要图文并茂,字数在800字左右。最初,如果优化后的网站竞争不强烈,也没必要天天更新。然而,别忘了引流。没有流量,天然就没有转化。 因为当初各行各业都很风行搞网站SEO,所以网站关键词排名的竞争也越来越强烈。进步网站关键词排名,要晓得网站SEO优化的办法和技巧。以上分享网站SEO优化办法和关键词优化技巧,心愿能帮忙到有须要的敌人。

September 30, 2022 · 1 min · jiezi

关于spring-cloud:sentineldashboardapollo-185-发布支持-apollo-持久化的定制版

sentinel-dashboard-apollo 是从 sentinel-dashboard 官网 fork 进去的一个定制版,反对所有规定长久化到 apollo,不批改一行官网源码,不便滚动降级,继续更新。 版本定制阐明:不改一行源码,实现 sentinel-dashboard 所有配置反对 apollo 长久化 应用文档:sentinel-dashboard-apollo 应用 github:sentinel-dashboard-apollo v1.8.5 版本公布https://github.com/fengjx/Sen... #2 sentinel-dashboard-apollo 降级到 1.8.5 版本#3 docker 镜像构建

September 28, 2022 · 1 min · jiezi

关于spring-cloud:Spring-Cloud-Alibaba-微服务架构实战完结无密

download:Spring Cloud / Alibaba 微服务架构实战|完结无密OAuth2学习中的一些高频问题的QA对于OAuth2相信很多初学者都有一些疑难,胖哥将这些疑难一一收集了起来做成了QA,或者能帮助学习者。OAuth2相干的QA Q:OAuth2 的一些罕用场景? A: OAuth2次要用于API授权,是跨API服务之间授权的解决打算。它实用于单点登录(SSO)、微服务之间的授权鉴权、API开放平台等场景。 Q: 什么是OAuth2客户端? A: 在OAuth2授权服务器上注册为客户端,并获得专属client_id标识的才是OAuth2客户端。安卓利用、IOS利用、Web前端等客户端利用也要遵循这个原则,它们本身注册到OAuth2授权服务器才能成为OAuth2客户端,否则就不是OAuth2客户端,必须是它们本身,而不是撑持它们的后端服务。 Q:OAuth2 客户端为什么分为public和confidential两种类型,别离是什么场景? A:rfc6749#section-2.1 根据OAuth2客户端自身是否有能力保护客户端凭据(client credentials)的私密性,是否能平安地通过授权服务器对客户端的资质进行认证将OAuth2客户端分为机密客户端和公共客户端。大部分的后端数据服务都应该被注册为机密客户端;无奈保障自身凭据安全的都应该被注册为公共客户端,公共客户端是没有client_sercet的,间接注册到OAuth2授权服务器的执行客户端,不通过后端利用进行拜访令牌中继的都是公共客户端,例如在一些特定场景下需要直连授权服务器的Web利用、移动利用。 Q:OAuth2 的access_token和refresh_token应该间接返回给前端吗? A:能不能返回给前端取决于这个前端是不是间接在授权服务器的OAuth2客户端,如果不是,就不能持有access_token和refresh_token,access_token和refresh_token的签发目标只能是OAuth2客户端。如果暴露面放开,则很容易被盗用。 Q: 非OAuth2客户端的客户端利用既然不能间接持有access_token和refresh_token的话,应该如何获取授权状态? A:当授权胜利后,令牌和用户客户端侧可能借助于session或者cookie进行一个映射,当然也可能考虑计算出一个不通明令牌( Opaque Token )映射,具体根据业务考量。 Q:OAuth2中的scope是什么? A:OAuth2是一个授权框架,授权天然要划定一个范畴(scope),以保障OAuth2客户端在既定的范畴内行事而不越界。它起到的作用和RBAC中的role其实类似,都是用来限度资源的拜访权限的。 role针对的是资源具备者(Resource Owner),而scope针对的是OAuth2客户端。 当然openid是一个例外,这个是OIDC 1.0的标识,算一个关键字。 Q:OAuth2 中的登录页面和授权确认页面能不能用前后端分离的形式? A:很多开发者不心愿点击授权的时候被302重定向到授权服务器提供的登录页面,然而你得明确一个情理, OAuth2客户端和授权服务器之间并不是一个残缺信赖的关系。外卖小哥给你送外卖,你必定心愿发放给他的是一个临时门禁通行码,而不是一个罕用通行码。另外ajax无奈平安地处理OAuth2授权流程中的302重定向问题,这也是一个技术问题。 Q:OAuth2 客户端是否做用户认证? A:OAuth2本身并没有定义用户如何向OAuth2客户端认证身份,这里要和授权服务器上的用户认证区别开来。OAuth2客户端在实现授权时可能拿到授权凭据,然而并不能间接拿到用户信息,如果授权服务器提供了获取用户信息的资源接口,OAuth2客户端可能通过该接口尝试获取用户信息用来表明用户的身份,这取决于用户是否授权了OAuth2客户端这样做。OIDC 1.0补充定义了OAuth2客户端对用户进行认证的细节流程。 Q:OAuth2客户端认证是什么? A:confidential类型的OAuth2客户端诚然在OAuth2授权服务器注册,它们要根据一些策略(Client Authentication Method)来向授权服务器证实自己是非法的客户端。这样它们才能调用一些OAuth2规定的端点,比如/oauth2/token令牌端点、/oauth2/revoke令牌撤销端点等等。对于OAuth2客户端认证的细节可能参考胖哥专栏中的OAuth2客户端认证过滤器详解一文。 Q:OAuth2明码模式为什么被废除了? A:准确地说目前明码模式在OAuth2.1中被移除了,包含OAuth0、okta等出名三方授权服务机构都对明码模式进行了移除处理。明码模式诞生的时候,像React、Vue这种单页利用还没有衰亡,以至连框架都还没有呢。它更像一种为理解决遗留问题而采纳的过渡打算。在传统利用中,用户习惯了把明码间接交给客户端换取资源拜访权限,而不是跳来跳去去拉授权、确认授权。OAuth2诞生之时为了让用户从传统思维中慢慢转变过去就设计了这种模式。 它冲破了托付授权的模式,升高了OAuth2的安全性。更多的细节请参考我往期的相干文章。 Q:OAuth2中的资源服务器怎么讲? A:只需蕴含了需要OAuth2客户端携带access_token拜访的资源接口的服务器都可能认为是资源服务器,包含OAuth2客户端、OAuth2授权服务器都可能根据业务和架构承担资源服务器的功能。从用户(资源所有者)角度来说,存放用户可能授权的资源接口的服务器都可能是资源服务器。资源服务器可能对拜访令牌access_token进行解码、校验,并必定本次请求是否合规。 Q:微服务是否可能不使用OAuth2? 当然可能,OAuth2只不过是目前微服务访问控制的解决打算之一,并不是唯一选项。总结这就是最近胖哥被问的比较多的一些问题,相信能够帮助各位。OAuth2的货色并不简略,通过近三年内断断续续的学习,胖哥才完残缺全理解这个货色,所以各位学习者不要心急,学的枯燥的时候先晾一时间,学这个最重要的是理解它的概念和流程,这远比各种框架重要,OAuth2本身和语言是无关的。

June 10, 2022 · 1 min · jiezi

关于spring-cloud:Spring-Cloud使用了注册中心nacos的服务优雅下线方案

应用了注册核心的服务集群,各个业务节点通过RestTemplate、openFeign进行外部调用时,或者gateway做服务转发时,个别会应用从注册核心获取的服务节点列表进行负载路由,而当一个服务节点被暴力敞开时,从注册核心检测到节点处在不衰弱状态,到注册核心将该节点从保护列表中移除,再到其余业务节点将失效节点从本身保护的节点列表缓存数据中移除(定时拉取或播送告诉形式),两头个别会经验数秒时长,这时如果有转向失效节点的新申请,就会不得不等满一个timeout周期,而后再反馈回调用端去做下一步是重试还是标记熔断的解决。总之,有异样产生,不优雅。 (伪装有流程图) 现成的有不少优雅敞开服务的计划,比方应用actuator的shutdown端点、提供入口调用SpringApplication的exit()静态方法等,不过重要的是在做这些之前要能先被动的将节点从注册核心中下线,而后期待一个适合的时间段之后再敞开服务,这样能多给正在解决中的申请执行实现的机会。 上面是应用了nacos的服务下线示例代码: /** 应用了nacos注册核心的服务敞开端点配置 */@ConditionalOnClass(NacosAutoServiceRegistration.class)@RestController@RequestMapping("actuator")@RequiredArgsConstructor@Slf4jpublic class NacosStopEndpoint { private final NacosAutoServiceRegistration nacosAutoServiceRegistration; private final ApplicationContext context; /** 登记服务后敞开利用前期待的工夫(毫秒) */ @Value("${stopService.waitTime:10000}") private int waitTime; /** * 敞开服务 <br> * 只接管localhost发动的申请 * * @param request * @return */ @PostMapping("stopService") public ResponseEntity<Boolean> stopNacosService( HttpServletRequest request) { if (!request.getServerName().equalsIgnoreCase("localhost")) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(false); new Thread( () -> { log.info("Ready to stop service"); nacosAutoServiceRegistration.stop(); log.info("Nacos instance has been de-registered"); log.info("Waiting {} milliseconds...", waitTime); try { Thread.sleep(waitTime); } catch (InterruptedException e) { log.info("interrupted!", e); } log.info("Closing application..."); SpringApplication.exit(context); ((ConfigurableApplicationContext) context).close(); }) .start(); return ResponseEntity.ok(true); }}这段代码提供了一个 /actuator/stopService 的POST端点,调用它即可优雅将服务下线,先把本身从nacos注册核心中移除,期待10秒后敞开spring利用。 ...

May 27, 2022 · 1 min · jiezi

关于spring-cloud:Spring-Cloud-Alibaba-微服务架构实战

Spring Cloud / Alibaba 微服务架构实战超清原画 残缺无密 包含所有视频课件以及源码 MP4格局 获取材料:网盘链接hashCode() 和 equals()的区别equals()equals() 方法用于比较两个对象是否相等,它与 == 相等比较符有着本质的不同。 在万物皆对象的 Java 体系中,零碎把判断对象是否相等的权力交给程序员。具体的措施是把 equals() 方法写到 Object 类中,并让所有类继承 Object 类。 这样程序员就能在自定义的类中重写 equals() 方法, 从而实现自己的比较逻辑。 hashCode()hashCode() 的意义是哈希值, 哈希值是经哈希函数运算后失去的后果,哈希函数能够保障雷同的输出能够失去雷同的输入(哈希值),然而不能够保障不同的输出总是能得出不同的输入。 当输出的样本量足够大时,是会产生哈希冲突的,也就是说不同的输出产生了雷同的输入。 暂且不谈冲突,就雷同的输出能够产生雷同的输入这点而言,是及其宝贵的。它使得零碎只需要通过简略的运算,在工夫复杂度O(1)的情况下就能得出数据的映射关系,根据这种个性,散列表应运而生。 一种支流的散列表实现是:用数组作为哈希函数的输入域,输出值通过哈希函数计算后失去哈希值。而后根据哈希值,在数组种找到对应的存储单元。当发生冲突时,对应的存储单元以链表的形式保存冲突的数据。 两者关系在大多数编程实践中,归根结底会落实到数据的存取问题上。 在汇编语言期间,你需要老诚恳实地对每个数据操作编写存取语句。 而随着期间发展到明天,咱们都用更便利灵活的高级语言编写代码,比如 Java。 Java 以面向对象为中心思想,封装了一系列操作数据的 api,升高了数据操作的复杂度。 但在咱们对数据进行操作之前,首先要把数据按照肯定的数据结构保存到存储单元中,否则操作数据将无从谈起。 然而不同的数据结构有各自的个性,咱们在存储数据的时候需要抉择合适的数据结构进行存储。 Java 根据不同的数据结构提供了丰富的容器类,便利程序员抉择适合业务的容器类进行开发。 通过继承关系图咱们看到 Java 的容器类被分为 Collection 和 Map 两大类,Collection 又可能进一步分为 List 和 Set。 其中 Map 和 Set 都是不容许元素重复的,严格来说Map存储的是键值对,它不容许重复的键值。 值得注意的是:Map 和 Set 的绝大多数实现类的底层都会用到散列表结构。 讲到这里咱们提取两个关键字不容许重复和散列表结构, 回顾 hashCode() 和 equals() 的个性,你是否想到了些什么货色呢?equals()力不从心下面提到 Set 和 Map 不存放重复的元素(key),这些容器在存储元素的时必须对元素做出判断:在以后的容器中有没有和新元素雷同的元素? ...

May 1, 2022 · 1 min · jiezi

关于spring-cloud:Spring-cloud-集成-SkyWalking-实现性能监控链路追踪日志收集

Why SkyWalking?Skywalking 是一个优良的APM(application performance monitor)利用性能监控零碎,针对微服务场景设计,能够不便的实现Spring cloud等微服务场景下的性能监控、链路追踪等。而v8.x版本也反对了日志收集性能,能够取代ELK作为分布式下日志收集的计划。一个零碎实现监控+追踪+日志的多个能力,无效升高微服务下运维的复杂度。 上面咱们以Spring cloud为例,一起玩转Skywalking1. 环境筹备与装置要实现监控+追踪+日志,咱们须要装置根底的 APM 和 Java agent。 进入下载页面: SkyWalking 下载下载 SkyWalking APM 以及 Java agent 如下两个压缩包: 下载实现后解压,尝试运行 /apache-skywalking-apm-bin/bin/startup.bat (或startup.sh)拜访 http://localhost:8080/,即可看到SkyWalking监控UI 以上装置为间接装置,如需docker等装置形式可参考SkyWalking官网文档2. 配置SkyWalking日志收集(logback为例)pom 中依赖 SkyWalking 的 logback 插件包: <!-- SkyWalking log collection --><dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-logback-1.x</artifactId> <version>8.9.0</version></dependency>增加/批改 logback.xml,启用 SkyWalking 提供的 appender,示例配置如下: <?xml version="1.0" encoding="UTF-8"?><configuration scan="true" scanPeriod="10 seconds"> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern> </layout> </encoder> </appender> <appender name="grpc" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern> </layout> </encoder> </appender> <root level="INFO"> <appender-ref ref="stdout"/> <appender-ref ref="grpc"/> </root></configuration>3. 配置Java agentIDEA开发环境下配置Java agent: ...

April 6, 2022 · 1 min · jiezi

关于spring-cloud:Spring-Security-OAuth20-自定义授权模式

大家好,我是不才陈某~ 这是《Spring Cloud 进阶》第24篇文章,往期文章如下: 五十五张图通知你微服务的灵魂摆渡者Nacos到底有多强?openFeign夺命连环9问,这谁受得了?阿里面试这样问:Nacos、Apollo、Config配置核心如何选型?这10个维度通知你!阿里面试败北:5种微服务注册核心如何选型?这几个维度通知你!阿里限流神器Sentinel夺命连环 17 问?比照7种分布式事务计划,还是偏爱阿里开源的Seata,真香!(原理+实战)Spring Cloud Gateway夺命连环10问?Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!分布式链路追踪之Spring Cloud Sleuth夺命连环9问?链路追踪自从用了SkyWalking,睡的真香!3本书了,7万+字,10篇文章,《Spring Cloud 进阶》根底版 PDF妹子始终没搞懂OAuth2.0,明天整合Spring Cloud Security 一次说明确!OAuth2.0实战!应用JWT令牌认证!OAuth2.0实战!玩转认证、资源服务异样自定义这些骚操作!实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式对立认证受权!字节面试这样问:跨库多表存在大量数据依赖问题有哪些解决方案?实战!退出登录时如何借助外力使JWT令牌生效?实战!Spring Cloud Gateway集成 RBAC 权限模型实现动静权限管制!实战!阿里神器 Seata 实现 TCC模式 解决分布式事务,真香!实战!openFeign如何实现全链路JWT令牌信息不失落?微服务下蓝绿公布、滚动公布、灰度公布等计划,必须懂!微服务如何聚合 API 文档?这波秀~Spring Cloud 2021.0.1 正式公布,卷不动了~本篇文章介绍一下Spring Security如何扩大新的受权类型,也是理论开发中十分重要的知识点。 目录如下: 为什么须要自定义受权类型?后面介绍OAuth2.0的根底知识点时介绍过反对的4种受权类型,别离如下: 受权码模式简化模式客户端模式明码模式对于上述4种受权类型不分明的,能够看之前的文章:妹子始终没搞懂OAuth2.0,明天整合Spring Cloud Security 一次说明确! 理论生产中上述四种受权类型基本不够用,比方常见的受权类型如下: 微信认证QQ认证手机号+验证码认证图形验证码认证邮箱认证因而咱们必须懂得OAuth2.0如何自定义受权类型,这也是本篇文章的重点。 实现思路Spring Security 定制受权类型其实很简略,次要是把握其中的思路,上面是明码模式的受权流程,如下图: 根据上述流程图能够跟着源码进去看看,不难发现有几个如下重要点: 每种受权类型都对应一个实现类TokenGranter,其中定义着受权类型所有 TokenGranter 实现类都通过 CompositeTokenGranter 中的 tokenGranters 汇合存起来。而后通过判断 grantType 参数来定位具体应用那个 TokenGranter 实现类来解决受权。每种受权形式都对应一个AuthenticationProviderTokenGranter 类会 new 一个 AuthenticationToken实现类,如 UsernamePasswordAuthenticationToken 传给 ProviderManager 类。因而想要自定义一个受权类型,必须构建本人的TokenGranter、AuthenticationProvider、AuthenticationToken。 ...

March 11, 2022 · 1 min · jiezi

关于spring-cloud:阿里神器Seata集成TCC模式解决分布式事务

大家好,我是不才陈某~ 这是《Spring Cloud 进阶》第19篇文章,往期文章如下: 五十五张图通知你微服务的灵魂摆渡者Nacos到底有多强?openFeign夺命连环9问,这谁受得了?阿里面试这样问:Nacos、Apollo、Config配置核心如何选型?这10个维度通知你!阿里面试败北:5种微服务注册核心如何选型?这几个维度通知你!阿里限流神器Sentinel夺命连环 17 问?比照7种分布式事务计划,还是偏爱阿里开源的Seata,真香!(原理+实战)Spring Cloud Gateway夺命连环10问?Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!分布式链路追踪之Spring Cloud Sleuth夺命连环9问?链路追踪自从用了SkyWalking,睡的真香!3本书了,7万+字,10篇文章,《Spring Cloud 进阶》根底版 PDF妹子始终没搞懂OAuth2.0,明天整合Spring Cloud Security 一次说明确!OAuth2.0实战!应用JWT令牌认证!OAuth2.0实战!玩转认证、资源服务异样自定义这些骚操作!实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式对立认证受权!字节面试这样问:跨库多表存在大量数据依赖问题有哪些解决方案?实战!退出登录时如何借助外力使JWT令牌生效?实战!Spring Cloud Gateway集成 RBAC 权限模型实现动静权限管制!明天这篇文章介绍一下Seata如何实现TCC事务模式,文章目录如下: 什么是TCC模式?TCC(Try Confirm Cancel)计划是一种利用层面侵入业务的两阶段提交。是目前最火的一种柔性事务计划,其核心思想是:针对每个操作,都要注册一个与其对应的确认和弥补(撤销)操作。 TCC分为两个阶段,别离如下: 第一阶段:Try(尝试),次要是对业务零碎做检测及资源预留 (加锁,锁住资源)第二阶段:本阶段依据第一阶段的后果,决定是执行confirm还是cancel Confirm(确认):执行真正的业务(执行业务,开释锁)Cancle(勾销):是预留资源的勾销(出问题,开释锁) 为了不便了解,上面以电商下单为例进行计划解析,这里把整个过程简略分为扣减库存,订单创立 2 个步骤,库存服务和订单服务别离在不同的服务器节点上。 假如商品库存为 100,购买数量为 2,这里检查和更新库存的同时,解冻用户购买数量的库存,同时创立订单,订单状态为待确认。 ①Try 阶段TCC 机制中的 Try 仅是一个初步操作,它和后续的确认一起能力真正形成一个残缺的业务逻辑,这个阶段次要实现: 实现所有业务查看( 一致性 ) 。预留必须业务资源( 准隔离性 ) 。Try 尝试执行业务。 ②Confirm / Cancel 阶段依据 Try 阶段服务是否全副失常执行,继续执行确认操作(Confirm)或勾销操作(Cancel)。 Confirm 和 Cancel 操作满足幂等性,如果 Confirm 或 Cancel 操作执行失败,将会一直重试直到执行实现。 ...

January 18, 2022 · 2 min · jiezi

关于spring-cloud:实现微服务预热调用之后再开始服务下

持续剖析其余接入点。 其余须要初始化的接入点剖析咱们有时候还须要做一些自定义的初始化操作,然而如何在注册到注册核心状态为 UP 也就是开始解决申请之前做这些操作呢? 为了更加与云环境兼容,Spring Boot 从 2.3.0 版本之后引入了一些云上部署相干的概念: LivenessState(存活状态):就应用程序而言,存活状态是指应用程序的状态是否失常。如果存活状态不失常,则意味着应用程序自身已损坏,无奈复原。在 k8s 中,如果存活检测失败,则 kubelet 将杀死 Container,并且依据其重新启动策略进行重启: 在 spring boot 中对应的接口是 /actuator/health/liveness对应的枚举类是 org.springframework.boot.availability.LivenessState,包含上面两个状态: CORRECT:存活状态失常BROKEN:存活状态不失常Readiness(就绪状态):指的是应用程序是否已筹备好承受并解决客户端申请。出于任何起因,如果应用程序尚未筹备好解决服务申请,则应将其申明为忙碌,直到可能失常响应申请为止。如果 Readiness 状态尚未就绪,则不应将流量路由到该实例。在 k8s 中,如果就绪检测失败,则 Endpoints 控制器将从 Endpoints 中删除这个 Pod 的 IP 地址,如果你没有应用 k8s 的服务发现的话,就不必太关怀这个: 在 spring boot 中对应的接口是 /actuator/health/readiness对应的枚举类是 org.springframework.boot.availability.ReadinessState,包含上面两个状态: ACCEPTING_TRAFFIC:筹备好承受申请REFUSING_TRAFFIC:目前不能承受申请了默认状况下,Spring Boot 在初始化过程中会批改这些状态,对应源码(咱们只关怀 listeners 相干,这些标记着 Spring Boot 生命周期变动): SpringApplication.java public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); //通知所有 Listener 启动中 listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //通知所有 Listener 启动实现 listeners.started(context); //调用各种 SpringRunners + CommandRunners callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { //告诉所有 Listener 运行中 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context;}其中,listeners.started 和 listeners.running 外面做的事件是: ...

January 2, 2022 · 2 min · jiezi

关于spring-cloud:实现微服务预热调用之后再开始服务上

最近线上发现一个景象,利用实例刚刚启动的时候,开始接管申请之后产生了一小段时间的申请阻塞,从 HTTP Servlet 申请队列监控上能够看出(基于 spring-web 的一般阻塞的 HTTP 服务器是有 HTTP 线程池的,当线程是满了之后,申请在阻塞队列中期待解决。基于 spring-webflux 的没有这个景象,然而思考的背压问题其实和这个场景相似): 而后阻塞数量很快就上来了,通过 JFR 发现和 Spring 各种懒加载的 Bean,各种资源或者连接池初始化等无关。这些资源能够了解为是懒加载的,是在申请真正用到的时候才会初始化。这些资源初始化之前,微服务就曾经注册到注册核心并开始承受申请了。这样在平时业务低峰公布的时候,是没有问题的,因为这些资源的初始化耗时也就在几十到几百毫秒之间。然而在业务顶峰须要动静扩容的时候,就会受一些影响,因为申请压力会立即大量打到这些新启动的实例上,这种状况下,初始化耗时的影响就比拟大了。 所以,咱们心愿在微服务开始真正提供服务之前,将这些比拟耗时的须要初始化的资源提前初始化实现之后,再通知注册核心咱们能够开始承受解决申请了。 Spring Boot 中的 MVC Servlet 与 Web Service Servlet 的提前初始化在微服务实例启动后,咱们发送第一个申请的时候,会看到相似于上面的日志: INFO: Initializing Servlet 'dispatcherServlet'INFO: Initializing Spring DispatcherServlet 'dispatcherServlet'这是在初始化 Servlet。 MVC Servlet 指的就是 Spring-MVC 的 Servlet,其实就是提供 HTTP 服务的一些外围 Servlet,例如最外围的 org.springframework.web.servlet.DispatcherServlet。这些默认是懒加载的,须要通过上面的配置关上: spring.mvc.servlet.load-on-startup: 1除了 MVC Servlet,另一些 Servlet 可能是提供除了 HTTP 以外的其余利用协定的 Servlet,这些 Servlet 默认也是懒加载的,须要通过上面的配置关上: spring.webservices.servlet.load-on-startup: 1例如 WebSocket 的 org.springframework.ws.transport.http.MessageDispatcherServlet 就是通过这个配置进行初始化的。 spring-data-redis 连接池的初始化咱们我的项目中应用的是 spring-data-redis + lettuce。如果没有应用 Pipeline 等须要独占连贯的 redis 操作,其实不必应用连接池。然而咱们在应用中为了效率,尽量都是用 Pipeline,所以咱们都启用了连接池配置。其连接池实现基于 common-pools2 库。相干配置如下所示: ...

January 1, 2022 · 2 min · jiezi

关于spring-cloud:实战干货Spring-Cloud-Gateway-整合-OAuth20-实现分布式统一认证授权

大家好,我是不才陈某~ 这是《Spring Cloud 进阶》第15篇文章,往期文章如下: 五十五张图通知你微服务的灵魂摆渡者Nacos到底有多强?openFeign夺命连环9问,这谁受得了?阿里面试这样问:Nacos、Apollo、Config配置核心如何选型?这10个维度通知你!阿里面试败北:5种微服务注册核心如何选型?这几个维度通知你!阿里限流神器Sentinel夺命连环 17 问?比照7种分布式事务计划,还是偏爱阿里开源的Seata,真香!(原理+实战)Spring Cloud Gateway夺命连环10问?Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!分布式链路追踪之Spring Cloud Sleuth夺命连环9问?链路追踪自从用了SkyWalking,睡的真香!3本书了,7万+字,10篇文章,《Spring Cloud 进阶》根底版 PDF妹子始终没搞懂OAuth2.0,明天整合Spring Cloud Security 一次说明确!OAuth2.0实战!应用JWT令牌认证!OAuth2.0实战!玩转认证、资源服务异样自定义这些骚操作!明天这篇文章介绍一下Spring Cloud Gateway整合OAuth2.0实现认证受权,波及到的知识点有点多,有不分明的能够看下陈某的往期文章。 文章目录如下: 微服务认证计划微服务认证计划目前有很多种,每个企业也是大不相同,然而总体分为两类,如下: 网关只负责转发申请,认证鉴权交给每个微服务管制对立在网关层面认证鉴权,微服务只负责业务你们公司目前用的哪种计划? 先来说说第一种计划,有着很大的弊病,如下: 代码耦合重大,每个微服务都要保护一套认证鉴权无奈做到对立认证鉴权,开发难度太大第二种计划显著是比较简单的一种,长处如下: 实现了对立的认证鉴权,微服务只须要各司其职,专一于本身的业务代码耦合性低,不便后续的扩大上面陈某就以第二种计划为例,整合Spring Cloud Gateway+Spring Cloud Security 整合出一套对立认证鉴权案例。 案例架构开始撸代码之前,先来说说大抵的认证鉴权流程,架构如下图: 大抵分为四个角色,如下: 客户端:须要拜访微服务资源网关:负责转发、认证、鉴权OAuth2.0受权服务:负责认证受权颁发令牌微服务汇合:提供资源的一系列服务。大抵流程如下: 1、客户端发出请求给网关获取令牌 2、网关收到申请,间接转发给受权服务 3、受权服务验证用户名、明码等一系列身份,通过则颁发令牌给客户端 4、客户端携带令牌申请资源,申请间接到了网关层 5、网关对令牌进行校验(验签、过期工夫校验....)、鉴权(对以后令牌携带的权限)和拜访资源所需的权限进行比对,如果权限有交加则通过校验,间接转发给微服务 6、微服务进行逻辑解决 针对上述架构须要新建三个服务,别离如下: 名称性能oauth2-cloud-auth-serverOAuth2.0认证受权服oauth2-cloud-gateway网关服务oauth2-cloud-order-service订单资源服务案例源码目录如下: 认证受权服务搭建很多企业是将认证受权服务间接集成到网关中,这么做耦合性太高了,这里陈某间接将认证受权服务抽离进去。 认证服务的搭建这里就不再细说了,上一篇文章中曾经介绍的很分明了:OAuth2.0实战!应用JWT令牌认证! 新建一个oauth2-cloud-auth-server模块,目录如下: 和上篇文章不同的是创立了JwtTokenUserDetailsService这个类,用于从数据库中加载用户,如下: 为了演示只是模仿了从数据库中查问,其中存了两个用户,如下: user:具备ROLE_user权限admin:具备ROLE_admin、ROLE_user权限要想这个失效,还要在security的配置文件SecurityConfig中指定,如下图: 另外还整合了注册核心Nacos,具体配置就不贴了,能够看源码。有不分明Nacos,能够看之前文章:五十五张图通知你微服务的灵魂摆渡者Nacos到底有多强? 案例源码曾经上传GitHub,关注公众号:码猿技术专栏,回复关键词:9529 获取!网关服务搭建网关应用的是Spring Cloud Gateway,网关如何搭建这里就不再细说了,有不分明的能够看之前文章:Spring Cloud Gateway夺命连环10问? 新建一个oauth2-cloud-gateway模块,目录如下图: 1、增加依赖须要增加几个OAuth2.0相干的依赖,如下: 2、JWT令牌服务配置应用JWT令牌,配置要和认证服务的令牌配置雷同,代码如下: ...

December 23, 2021 · 1 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版45-实现公共日志记录

本系列代码地址:https://github.com/JoJoTec/sp...咱们这一节在后面实现的带有链路信息的 Publisher 的工厂的根底上,实现公共日志记录的 GlobalFilter。回顾下咱们的需要: 咱们须要在网关记录每个申请的: HTTP 相干元素: URL 相干信息申请信息,例如 HTTP HEADER,申请工夫等等某些类型的申请体响应信息,例如响应码某些类型响应的响应体链路信息记录申请与响应的 Body 须要留神的中央后面的章节咱们提到过,对于申请与响应的 body 解决,如果用其后果放入主链路的话,会造成 Spring Cloud Sleuth 的链路信息失落。还有两个要留神的中央是: TCP 粘包拆包导致一个申请体宰割成好几份或者一个包蕴含几个申请读取后要开释本来的申请 body 读取进去的 DataBuffer为何要开释本来的申请 body 读取进去的 DataBuffer?因为读取进去后占用的 DataBuffer 如果手动不开释那么底层的计数始终不归零会造成内存透露。能够参考框架代码看出,这里的 DataBuffer 是须要手动开释的,参考源码: ByteBufferDecoder.java @Overridepublic ByteBuffer decode(DataBuffer dataBuffer, ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) { int byteCount = dataBuffer.readableByteCount(); ByteBuffer copy = ByteBuffer.allocate(byteCount); copy.put(dataBuffer.asByteBuffer()); copy.flip(); DataBufferUtils.release(dataBuffer); if (logger.isDebugEnabled()) { logger.debug(Hints.getLogPrefix(hints) + "Read " + byteCount + " bytes"); } return copy;}咱们是想把能够输入到日志的 body 转换成字符串进行输入,为了代码简洁避免出错,咱们应用一个工具类来实现将 DataBuffer 读取成字符串并开释的操作: ...

December 1, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版44避免链路信息丢失做的设计2

本系列代码地址:https://github.com/JoJoTec/sp...咱们在这一节咱们将持续解说防止链路信息失落做的设计,次要针对获取到现有 Span 之后,如何保障每个 GlobalFilter 都能放弃链路信息。首先,咱们自定义 Reactor 的外围 Publisher 即 Mono 和 Flux 的工厂,将链路信息封装进去,保障由这个工厂生成的 Mono 和 Flux,都是只有是这个工厂生成的 Mono 和 Flux 之间无论怎么拼接都会放弃链路信息的: 自定义 Mono 和 Flux 的工厂公共 Subscriber 封装,将 reactor Subscriber 的所有要害接口,都查看以后上下文是否有链路信息,即 Span,如果没有就包裹上,如果有则间接执行即可。 public class TracedCoreSubscriber<T> implements Subscriber<T>{ private final Subscriber<T> delegate; private final Tracer tracer; private final CurrentTraceContext currentTraceContext; private final Span span; TracedCoreSubscriber(Subscriber<T> delegate, Tracer tracer, CurrentTraceContext currentTraceContext, Span span) { this.delegate = delegate; this.tracer = tracer; this.currentTraceContext = currentTraceContext; this.span = span; } @Override public void onSubscribe(Subscription s) { executeWithinScope(() -> { delegate.onSubscribe(s); }); } @Override public void onError(Throwable t) { executeWithinScope(() -> { delegate.onError(t); }); } @Override public void onComplete() { executeWithinScope(() -> { delegate.onComplete(); }); } @Override public void onNext(T o) { executeWithinScope(() -> { delegate.onNext(o); }); } private void executeWithinScope(Runnable runnable) { //如果以后没有链路信息,强制包裹 if (tracer.currentSpan() == null) { try (CurrentTraceContext.Scope scope = this.currentTraceContext.maybeScope(this.span.context())) { runnable.run(); } } else { //如果以后已有链路信息,则间接执行 runnable.run(); } }}之后别离定义所有 Flux 的代理 TracedFlux,和所有 Mono 的代理 TracedMono,其实就是在 subscribe 的时候,用 TracedCoreSubscriber 包装传入的 CoreSubscriber: ...

November 30, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版44避免链路信息丢失做的设计1

本系列代码地址:https://github.com/JoJoTec/sp...咱们在这一节首先剖析下 Spring Cloud Gateway 一些其余可能失落链路信息的点,之后来做一些能够防止链路信息失落的设计,之后基于这个设计去实现咱们须要的一些定制化的 GlobalFilter Spring Cloud Gateway 其余的可能失落链路信息的点通过后面的剖析,咱们能够看出,不止这里,还有其余中央会导致 Spring Cloud Sleuth 的链路追踪信息隐没,这里举几个大家常见的例子: 1.在 GatewayFilter 中指定了异步执行某些工作,因为线程切换了,并且这时候可能 Span 曾经完结了,所以没有链路信息,例如: @Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange).publishOn(Schedulers.parallel()).doOnSuccess(o -> { //这里就没有链路信息了 log.info("success"); });}2.将 GatewayFilter 中持续链路的 chain.filter(exchange) 放到了异步工作中执行,下面的 AdaptCachedBodyGlobalFilter 就属于这种状况,这样会导致之后的 GatewayFilter 都没有链路信息,例如: @Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return Mono.delay(Duration.ofSeconds(1)).then(chain.filter(exchange));}Java 并发编程模型与 Project Reactor 编程模型的抵触思考Java 中的很多框架,都用到了 ThreadLocal,或者通过 Thread 来标识唯一性。例如: 日志框架中的 MDC,个别都是 ThreadLocal 实现。所有的锁、基于 AQS 的数据结构,都是通过 Thread 的属性来惟一标识谁获取到了锁的。分布式锁等数据结构,也是通过 Thread 的属性来惟一标识谁获取到了锁的,例如 Redisson 中分布式 Redis 锁的实现。然而放到 Project Reactor 编程模型,这就显得心心相印了,因为 Project Reactor 异步响应式编程就是不固定线程,没法保障提交工作和回调能在同一个线程,所以 ThreadLocal 的语义在这里很难成立。Project Reactor 尽管提供了对标 ThreadLocal 的 Context,然而支流框架还没有兼容这个 Context,所以给 Spring Cloud Sleuth 粘合这些链路追踪带来了很大艰难,因为 MDC 是一个 ThreadLocal 的 Map 实现,而不是基于 Context 的 Map。这就须要 Spring Cloud Sleuth 在订阅一开始,就须要将链路信息放入 MDC,同时还须要保障运行时不切换线程。 ...

November 29, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版43为何-SpringCloudGateway-中会有链路信息丢失

本系列代码地址:https://github.com/JoJoTec/sp...在开始编写咱们本人的日志 Filter 之前,还有一个问题我想在这里和大家分享,即在 Spring Cloud Gateway 中可能产生链路信息失落的问题。 次要抵触 - Project Reactor 与 Java Logger MDC 之间的设计抵触Poject Reactor 是基于异步响应式设计的编程模式的实现,它的次要实现思路是先编写执行链路,最初 sub 执行整个链路。然而链路的每一部分,到底是哪个线程执行的,是不确定的。 Java 的日志框架设计,其上下文 MDC(Mapped Diagnostic Context)信息,是基于线程设计的,其实能够简略了解为一个 ThreadLocal 的 Map。日志的链路信息,是保留在这个 MDC 中的。 这样其实能够看出 Project Reactor 与日志框架的 MDC 默认是不兼容的,只有产生异步线程切换,这个 MDC 就变了。Spring Cloud Sleuth 为此加了很多粘合代码,然而智者千虑必有一失,Project Reactor 利用场景和库也在一直倒退和壮大,Spring Cloud Sleuth 也可能会漏掉一些场景导致链路信息失落。 一种 Spring Cloud Gateway 常见的链路信息失落的场景咱们编写一个简略的测试项目(我的项目地址): 引入依赖: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.6</version></parent><dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <!--log4j2异步日志须要的依赖,所有我的项目都必须用log4j2和异步日志配置--> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>${disruptor.version}</version> </dependency></dependencies><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2020.0.3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>对所有门路开启 AdaptCachedBodyGlobalFilter: ...

November 28, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版42SpringCloudGateway-现有的可供分析的请求日志以及缺陷

本系列代码地址:https://github.com/JoJoTec/sp...网关因为是所有内部用户申请的入口,记录这些申请中咱们须要的元素,对于线上监控以及业务问题定位,是十分重要的。并且,在这些元素中,链路信息也是十分重要的。通过链路信息,咱们能够找到申请调用全链路相干的日志。并且,网关也是大部分申请链路起始的中央,记录申请中的元素的同时,也要带上链路信息。 咱们须要在网关记录每个申请的: HTTP 相干元素:URL 相干信息申请信息,例如 HTTP HEADER,申请工夫等等某些类型的申请体响应信息,例如响应码某些类型响应的响应体链路信息现有的可供剖析的日志以及缺点 首先咱们来看 Spring Cloud Gateway 中自身咱们能够利用的日志。Spring Cloud Gateway 基于 Spring-WebFlux,Spring-WebFlux 基于 Project Reactor,咱们没有在网关退出额定的 Web 容器依赖,所以 Web 容器用的是默认的基于 Project Reactor 的 reactor-netty 实现的 Web 容器。 netty 抓包日志 应用了 netty 咱们能够联想到 netty 的抓包日志,Spring Cloud Gateway 封装了这个性能,并裸露了配置。Spring Cloud Gateway 是一个网关,他会作为 HTTP 服务器承受 HTTP 申请的同时,还在作为 HTTP 客户端将申请转发到上游的微服务。所以,这里有两种抓包日志,一种是作为 HTTP 服务器接管到的申请和响应,另一种是做为 HTTP 客户端收回的申请和响应。别离对应两个配置: spring.cloud.gateway: httpserver: wiretap: truehttpclient: wiretap: true常常有读者私信我问如何看 spring cloud 有哪些配置,官网文档感觉不够分明全面。我个别是看源码,然而鉴于很多人没有精力去钻研源码,一种偷懒的形式是去看 jar 包外面的 spring-configuration-metadata.json。外面蕴含了比拟全的配置,以及配置类(如果存在的话),这是很不便的。例如咱们这里的两个配置,在这个 json 中对应: { "name": "spring.cloud.gateway.httpclient.wiretap", "type": "java.lang.Boolean", "description": "Enables wiretap debugging for Netty HttpClient.", "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", "defaultValue": false},{ "name": "spring.cloud.gateway.httpserver.wiretap", "type": "java.lang.Boolean", "description": "Enables wiretap debugging for Netty HttpServer.", "defaultValue": "false"},能够看出,spring.cloud.gateway.httpclient.wiretap 对应配置类 org.springframework.cloud.gateway.config.HttpClientProperties(这个配置类外面的配置咱们前面还会用到,到时候会详细分析其中的配置项),默认为 false。spring.cloud.gateway.httpserver.wiretap 没有配置类,他是被间接应用的,对应源码: ...

November 27, 2021 · 22 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版41-SpringCloudGateway-基本流程讲解3

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续剖析上一节提到的 WebHandler。退出 Spring Cloud Sleuth 以及 Prometheus 相干依赖之后, Spring Cloud Gateway 的解决流程如下所示: Spring Cloud Gateway 入口 -> WebFlux 的 DefaultWebFilterChainSpring Cloud Gateway 是基于 Spring WebFlux 开发的异步响应式网关,异步响应式代码比拟难以了解和浏览,我这里给大家分享一种办法去了解,通过这个流程来了解 Spring Cloud Gateway 的工作流程以及底层原理。其实能够了解为,上图这个流程,就是拼出来一个残缺的 Mono(或者 Flux)流,最初 subscribe 执行。 当收到一个申请的时候,会通过 org.springframework.web.server.handler.DefaultWebFilterChain,这是 WebFilter 的调用链,这个链路包含三个 WebFilter: org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter:增加 Prometheus 相干依赖之后,会有这个 MetricsWebFilter,用于记录申请解决耗时,采集相干指标。org.springframework.cloud.sleuth.instrument.web.TraceWebFilter:增加 Spring Cloud Sleuth 相干依赖之后,会有这个 TraceWebFilter。org.springframework.cloud.gateway.handler.predicate.WeightCalculatorWebFilter:Spring Cloud Gateway 路由权重相干配置性能相干实现类,这个咱们这里不关怀。在这个 DefaultWebFilterChain 会造成这样一个 Mono,咱们顺次将他们标记进去,首先是入口代码 org.springframework.web.server.handler.DefaultWebFilterChain#filter: public Mono<Void> filter(ServerWebExchange exchange) { return Mono.defer(() -> // this.currentFilter != null 代表 WebFilter 链还没有完结 // this.chain != null 代表 WebFilter 链不为空 this.currentFilter != null && this.chain != null ? //在 WebFilter 链没有完结的状况下,调用 WebFilter invokeFilter(this.currentFilter, this.chain, exchange) : //在 WebFilter 完结的状况下,调用 handler this.handler.handle(exchange));}对于咱们这里的 WebFilter 链的第一个 MetricsWebFilter,假如启用了对应的采集统计的话,这时候生成的 Mono 就是: ...

November 26, 2021 · 5 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版41-SpringCloudGateway-基本流程讲解2

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续剖析上一节提到的 WebHandler,通过将申请封装成 ServerWebExchange 的 HttpWebHandlerAdapter 之后,申请会通过 ExceptionHandlingWebHandler 全局 Web 解决异样处理器的接入点 - ExceptionHandlingWebHandler之前有网友私信问过笔者,如何给 Spring Cloud Gateway 加全局异样处理器,其实和给基于 Spring-Flux 的异步 Web 服务加是一样的,都是通过实现并注册一个 WebExceptionHandler Bean: WebExceptionHandler.java public interface WebExceptionHandler { Mono<Void> handle(ServerWebExchange exchange, Throwable ex);}这些 Bean,就是在 ExceptionHandlingWebHandler 被退出到整个申请解决链路中的: ExceptionHandlingWebHandler.java @Overridepublic Mono<Void> handle(ServerWebExchange exchange) { Mono<Void> completion; try { //这里其实就是组装前面的链路,即调用前面的 FilteringWebHandler 的 handle completion = super.handle(exchange); } catch (Throwable ex) { completion = Mono.error(ex); } for (WebExceptionHandler handler : this.exceptionHandlers) { completion = completion.onErrorResume(ex -> handler.handle(exchange, ex)); } return completion;}从源码能够看出,这里将每个 WebExceptionHandler 作为 Mono 的异样解决 onErrorResume 退出了链路。onErrorResume 的意思是如果链路后面产生异样,则在这里捕捉住异样同时调用 handler.handle(exchange, ex) 进行解决,如果应用阻塞代码了解,就相当于: ...

November 25, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版41-SpringCloudGateway-基本流程讲解1

本系列代码地址:https://github.com/JoJoTec/sp...接下来,将进入咱们降级之路的又一大模块,即网关模块。网关模块咱们废除了曾经进入保护状态的 zuul,选用了 Spring Cloud Gateway 作为外部网关。为何抉择 Spring Cloud Gateway 而不是 nginx 还有 Kong 的起因是: 项目组对于 Java 更加相熟,并且对于 Project Reactor 异步编程也比拟相熟,这个比拟重要须要在网关中应用咱们之前实现的基于申请的有状态重试的压力敏感的负载均衡器须要在网关中实现重试须要在网关中实现实例门路断路须要在网关中进行业务对立加解密须要在网关中实现 BFF(Backends For Frontends)接口,即依据客户端申请,将某几个不同接口的申请一次性组合返回须要在网关中应用 Redis 记录一些与 Token 相干的值因而,咱们应用了 Spring Cloud Gateway 作为外部网关,接下来,咱们就来顺次实现下面说的这些性能。同时在本次降级应用过程中, Spring Cloud Gateway 也有一些坑,例如: 联合应用 spring-cloud-sleuth 会有链路信息追踪,然而某些状况链路信息会失落。对于三方 Reactor 封装的异步 API (例如后面提到的操作 Redis 应用的 spring-data-redis)了解不到位导致要害线程被占用。然而首先,咱们须要简略了解下 Spring Cloud Gateway 到底包含哪些组件以及整个调用流程是什么样子的。因为 Spring Cloud Gateway 基于 Spring-Boot 和 Spring-Webflux 实现,所以咱们会从外层 WebFilter 开始阐明,而后剖析如何走到 Spring Cloud Gateway 的封装逻辑,以及 Spring Cloud Gateway 蕴含的组件,申请是如何转发进来,回来后又通过了哪些解决,这些咱们都会逐个剖析。 创立一个简略的 API 网关为了详细分析流程,咱们先来创立一个简略的网关,用于疾速上手并剖析。 ...

November 24, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版40-spock-单元测试封装的-WebClient下

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续上一节,持续应用 spock 测试咱们本人封装的 WebClient 测试针对 readTimeout 重试针对响应超时,咱们须要验证重试仅针对能够重试的办法(包含 GET 办法以及配置的可重试办法),针对不可重试的办法没有重试。咱们能够通过 spock 单元测试中,查看对于负载均衡器获取实例办法的调用次数看进去是否有重试 咱们通过 httpbin.org 的 '/delay/秒' 实现 readTimeout,别离验证: 测试 GET 提早 2 秒返回,超过读取超时,这时候会重试测试 POST 提早 3 秒返回,超过读取超时,同时门路在重试门路中,这样也是会重试的测试 POST 提早 2 秒返回,超过读取超时,同时门路在重试门路中,这样不会重试代码如下: @SpringBootTest( properties = [ "webclient.configs.testServiceWithCannotConnect.baseUrl=http://testServiceWithCannotConnect", "webclient.configs.testServiceWithCannotConnect.serviceName=testServiceWithCannotConnect", "webclient.configs.testService.baseUrl=http://testService", "webclient.configs.testService.serviceName=testService", "webclient.configs.testService.responseTimeout=1s", "webclient.configs.testService.retryablePaths[0]=/delay/3", "webclient.configs.testService.retryablePaths[1]=/status/4*", "spring.cloud.loadbalancer.zone=zone1", "resilience4j.retry.configs.default.maxAttempts=3", "resilience4j.circuitbreaker.configs.default.failureRateThreshold=50", "resilience4j.circuitbreaker.configs.default.slidingWindowType=TIME_BASED", "resilience4j.circuitbreaker.configs.default.slidingWindowSize=5", //因为重试是 3 次,为了避免断路器关上影响测试,设置为正好比重试多一次的次数,避免触发 //同时咱们在测试的时候也须要手动清空断路器统计 "resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls=4", "resilience4j.circuitbreaker.configs.default.recordExceptions=java.lang.Exception" ], classes = MockConfig)class WebClientUnitTest extends Specification { @SpringBootApplication static class MockConfig { } @SpringBean private LoadBalancerClientFactory loadBalancerClientFactory = Mock() @Autowired private CircuitBreakerRegistry circuitBreakerRegistry @Autowired private Tracer tracer @Autowired private ServiceInstanceMetrics serviceInstanceMetrics @Autowired private WebClientNamedContextFactory webClientNamedContextFactory //不同的测试方法的类对象不是同一个对象,会从新生成,保障相互没有影响 def zone1Instance1 = new DefaultServiceInstance(instanceId: "instance1", host: "www.httpbin.org", port: 80, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) def zone1Instance2 = new DefaultServiceInstance(instanceId: "instance2", host: "www.httpbin.org", port: 8081, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) def zone1Instance3 = new DefaultServiceInstance(instanceId: "instance3", host: "httpbin.org", port: 80, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) RoundRobinWithRequestSeparatedPositionLoadBalancer loadBalancerClientFactoryInstance = Spy(); ServiceInstanceListSupplier serviceInstanceListSupplier = Spy(); //所有测试的办法执行前会调用的办法 def setup() { //初始化 loadBalancerClientFactoryInstance 负载均衡器 loadBalancerClientFactoryInstance.setTracer(tracer) loadBalancerClientFactoryInstance.setServiceInstanceMetrics(serviceInstanceMetrics) loadBalancerClientFactoryInstance.setServiceInstanceListSupplier(serviceInstanceListSupplier) } def "测试针对 readTimeout 重试"() { given: "设置 testService 的实例都是失常实例" loadBalancerClientFactory.getInstance("testService") >> loadBalancerClientFactoryInstance serviceInstanceListSupplier.get() >> Flux.just(Lists.newArrayList(zone1Instance1, zone1Instance3)) when: "测试 GET 提早 2 秒返回,超过读取超时" //革除断路器影响 circuitBreakerRegistry.getAllCircuitBreakers().forEach({ c -> c.reset() }) try { webClientNamedContextFactory.getWebClient("testService") .get().uri("/delay/2").retrieve() .bodyToMono(String.class).block(); } catch (WebClientRequestException e) { if (e.getCause() in ReadTimeoutException) { //读取超时疏忽 } else { throw e; } } then: "每次都会超时所以会重试,依据配置一共有 3 次" 3 * loadBalancerClientFactoryInstance.getInstanceResponseByRoundRobin(*_) when: "测试 POST 提早 3 秒返回,超过读取超时,同时门路在重试门路中" //革除断路器影响 circuitBreakerRegistry.getAllCircuitBreakers().forEach({ c -> c.reset() }) try { webClientNamedContextFactory.getWebClient("testService") .post().uri("/delay/3").retrieve() .bodyToMono(String.class).block(); } catch (WebClientRequestException e) { if (e.getCause() in ReadTimeoutException) { //读取超时疏忽 } else { throw e; } } then: "每次都会超时所以会重试,依据配置一共有 3 次" 3 * loadBalancerClientFactoryInstance.getInstanceResponseByRoundRobin(*_) when: "测试 POST 提早 2 秒返回,超过读取超时,这个不能重试" //革除断路器影响 circuitBreakerRegistry.getAllCircuitBreakers().forEach({ c -> c.reset() }) try { webClientNamedContextFactory.getWebClient("testService") .post().uri("/delay/2").retrieve() .bodyToMono(String.class).block(); } catch (WebClientRequestException e) { if (e.getCause() in ReadTimeoutException) { //读取超时疏忽 } else { throw e; } } then: "没有重试,只有一次调用" 1 * loadBalancerClientFactoryInstance.getInstanceResponseByRoundRobin(*_) }}测试非 2xx 响应码返回的重试对于非 2xx 的响应码,代表申请失败,咱们须要测试: ...

November 23, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版40-spock-单元测试封装的-WebClient上

本系列代码地址:https://github.com/JoJoTec/sp...咱们来测试下后面封装好的 WebClient,这里开始,咱们应用 spock 编写 groovy 单元测试,这种编写进去的单元测试,代码更加简洁,同时更加灵便,咱们在接下来的单元测试代码中就能看进去。 编写基于 spock 的 spring-boot context 测试咱们退出后面设计的配置,编写测试类: @SpringBootTest( properties = [ "webclient.configs.testServiceWithCannotConnect.baseUrl=http://testServiceWithCannotConnect", "webclient.configs.testServiceWithCannotConnect.serviceName=testServiceWithCannotConnect", "webclient.configs.testService.baseUrl=http://testService", "webclient.configs.testService.serviceName=testService", "webclient.configs.testService.responseTimeout=1s", "webclient.configs.testService.retryablePaths[0]=/delay/3", "webclient.configs.testService.retryablePaths[1]=/status/4*", "spring.cloud.loadbalancer.zone=zone1", "resilience4j.retry.configs.default.maxAttempts=3", "resilience4j.circuitbreaker.configs.default.failureRateThreshold=50", "resilience4j.circuitbreaker.configs.default.slidingWindowType=TIME_BASED", "resilience4j.circuitbreaker.configs.default.slidingWindowSize=5", //因为重试是 3 次,为了避免断路器关上影响测试,设置为正好比重试多一次的次数,避免触发 //同时咱们在测试的时候也须要手动清空断路器统计 "resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls=4", "resilience4j.circuitbreaker.configs.default.recordExceptions=java.lang.Exception" ], classes = MockConfig)class WebClientUnitTest extends Specification { @SpringBootApplication static class MockConfig { }}咱们退出三个服务实例供单元测试调用: class WebClientUnitTest extends Specification { def zone1Instance1 = new DefaultServiceInstance(instanceId: "instance1", host: "www.httpbin.org", port: 80, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) def zone1Instance2 = new DefaultServiceInstance(instanceId: "instance2", host: "www.httpbin.org", port: 8081, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) def zone1Instance3 = new DefaultServiceInstance(instanceId: "instance3", host: "httpbin.org", port: 80, metadata: Map.ofEntries(Map.entry("zone", "zone1")))}咱们要动静的指定负载平衡获取服务实例列表的响应,即去 Mock 负载均衡器的 ServiceInstanceListSupplier 并笼罩: ...

November 22, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版39-改造-resilience4j-粘合-WebClient

本系列代码地址:https://github.com/JoJoTec/sp...要想实现咱们上一节中提到的: 须要在重试以及断路中加一些日志,便于日后的优化须要定义重试的 Exception,并且与断路器相结合,将非 2xx 的响应码也封装成特定的异样须要在断路器相干的 Operator 中减少相似于 FeignClient 中的负载平衡的数据更新,使得负载平衡更加智能咱们须要将 resilience4j 自身提供的粘合库做一些革新,其实次要就是对 resilience4j 实现的 project reactor 的 Operator 进行革新。 对于断路器的革新首先,WebClient 的返回对象只可能是 ClientResponse 类型,所以咱们这里革新进去的 Operator 不用带上形参,只须要针对 ClientResponse 即可,即: public class ClientResponseCircuitBreakerOperator implements UnaryOperator<Publisher<ClientResponse>> { ...}在原有的断路器逻辑中,咱们须要退出针对 GET 办法以及之前定义的能够重试的门路匹配配置能够重试的逻辑,这须要咱们拿到原有申请的 URL 信息。然而 ClientResponse 中并没有裸露这些信息的接口,其默认实现 DefaultClientResponse(咱们只有没有本人给 WebClient 退出非凡的革新逻辑,实现都是 DefaultClientResponse) 中的 request() 办法能够获取申请 HttpRequest,其中蕴含 url 信息。然而这个类还有办法都是 package-private 的,咱们须要反射进去: ClientResponseCircuitBreakerSubscriber private static final Class<?> aClass;private static final Method request;static { try { aClass = Class.forName("org.springframework.web.reactive.function.client.DefaultClientResponse"); request = ReflectionUtils.findMethod(aClass, "request"); request.setAccessible(true); } catch (Exception e) { throw new RuntimeException(e); }}之后,在获取到 ClientResponse 之后记录断路器的逻辑中,须要退出下面提到的对于重试的革新,以及负载均衡器的记录: ...

November 21, 2021 · 4 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版38-实现自定义-WebClientNamedContextFactory

本系列代码地址:https://github.com/JoJoTec/sp...实现 WeClient 的 NamedContextFactory咱们要实现的是不同微服务主动配置装载不同的 WebClient Bean,这样就能够通过 NamedContextFactory 实现。咱们先来编写下实现这个 NamedContextFactory 整个的加载流程的代码,其结构图如下所示: spring.factories # AutoConfigurationorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.github.jojotech.spring.cloud.webflux.auto.WebClientAutoConfiguration在 spring.factories 定义了主动装载的主动配置类 WebClientAutoConfiguration WebClientAutoConfiguration @Import(WebClientConfiguration.class)@Configuration(proxyBeanMethods = false)public class WebClientAutoConfiguration {}WebClientAutoConfiguration 这个主动配置类 Import 了 WebClientConfiguration WebClientConfiguration @Configuration(proxyBeanMethods = false)@EnableConfigurationProperties(WebClientConfigurationProperties.class)public class WebClientConfiguration { @Bean public WebClientNamedContextFactory getWebClientNamedContextFactory() { return new WebClientNamedContextFactory(); }}WebClientConfiguration 中创立了 WebClientNamedContextFactory 这个 NamedContextFactory 的 Bean。在这个 NamedContextFactory 中,定义了默认配置 WebClientDefaultConfiguration。在这个默认配置中,次要是给每个微服务都定义了一个 WebClient 定义 WebClient 的配置类咱们编写下上一节定义的配置,包含: 微服务名称微服务地址,服务地址,不填写则为 http://微服务名称连贯超时,应用 Duration,这样咱们能够用更直观的配置了,例如 5ms,6s,7m 等等响应超时,应用 Duration,这样咱们能够用更直观的配置了,例如 5ms,6s,7m 等等能够重试的门路,默认只对 GET 办法重试,通过这个配置减少针对某些非 GET 办法的门路的重试;同时,这些门路能够应用 * 等门路匹配符,即 Spring 中的 AntPathMatcher 进行门路匹配多个门路。例如 /query/order/**WebClientConfigurationProperties ...

November 20, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版37-实现异步的客户端封装配置管理的意义与设计

本系列代码地址:https://github.com/JoJoTec/sp...为何须要封装异步 HTTP 客户端 WebClient对于同步的申请,咱们应用 spring-cloud-openfeign 封装的 FeignClient,并做了额定的定制。对于异步的申请,应用的是异步 Http 客户端即 WebClient。WebClient 应用也比较简单,举一个简略的例子即: //应用 WebClient 的 Builder 创立 WebClientWebClient client = WebClient.builder() //指定基址 .baseUrl("http://httpbin.org") //能够指定一些默认的参数,例如默认 Cookie,默认 HttpHeader 等等 .defaultCookie("cookieKey", "cookieValue") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .build();创立好 WebClient 后即能够应用这个 WebClient 进行调用: // GET 申请 /anything 并将 body 转化为 StringMono<String> stringMono = client.get().uri("/anything").retrieve().bodyToMono(String.class);//这里为了测试,采纳阻塞获取String block = stringMono.block();返回的后果如下所示(申请 http://httporg.bin/anything 会将申请中的所有内容一成不变返回,从这里咱们能够看出下面测试的 Header 还有 cokkie 都被返回了): { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip", "Cookie": "TestCookie=TestCookieValue,getAnythingCookie=getAnythingCookieValue", "Getanythingheader": "getAnythingHeaderValue", "Host": "httpbin.org", "Testheader": "TestHeaderValue", "User-Agent": "ReactorNetty/1.0.7" }, "json": null, "method": "GET", "origin": "12.12.12.12", "url": "http://httpbin.org/anything"}咱们也能够退出负载平衡的性能,让 WebClient 利用咱们外部的 LoadBalancer,负载平衡调用其余微服务,首先注入负载平衡 Filter: ...

November 19, 2021 · 1 min · jiezi

关于spring-cloud:System-Performance-读书笔记-操作系统1

本系列是针对 Systems Performance: Enterprise and the Cloud, 2nd Edition (2020) 书籍的读书笔记,退出了一些集体了解以及拓展,并且针对一些难以了解的中央提供了一些额定的参考内核(Kernel)经典模型中,内核在操作系统构造中的地位如图所示: 从里到外别离是: 硬件(Hardware):操作系统运行在的硬件设施。内核(Kernel):操作系统的外围软件,内核治理着 CPU 调度、内存、文件系统、网络协议以及各种零碎设施(磁盘 IO、网络 IO 等等)。通过零碎调用提供服务。零碎调用(System Calls):提供拜访硬件设施或者内核服务的程序接口。例如 open, close, read, write, ioctl等,需蕴含头文件unistd.h。零碎库(System Libraries):间接用零碎调用可能不太不便,咱们能够应用封装好的库函数进行编程应用。从图上能够看出,这里其实有个缺口,因为利用也能够不应用零碎库而是间接应用零碎调用。例如像是 Go 语言运行环境,他就应用了本人封装的零碎调用层而不是规范库 libc。目前很多操作系统都在这个模型的根底上做了变种,之后咱们会详细分析。 内核执行通过一直地迭代,内核目前曾经十分宏大,有上百万的代码。内核的执行是按需的,例如当用户级别的应用程序发动了零碎调用,或者设施发送了一个中断(interrupt)的时候。另外,某些内核线程回异步执行一些维护性的工作,可能蕴含内核时钟程序以及内存治理工作,然而这些工作都会尽量放弃轻量级并只占用很少的 CPU 资源。 像 Web 服务器这种 I/O 密集型的利用(一直的承受申请返回响应),会常常在内核上下文中执行。计算密集型的利用则会尽量不打搅内核,能够不中断地在 CPU 上执行。内核调度器会决定那个线程会运行,哪个会期待,以及调度到哪个 CPU 上。内核会抉择硬件缓存更热或者对于这个过程本地性更好的 CPU,来进步性能。 内核态以及用户态内核态(kernel mode):运行内核程序的时候,CPU 处于的模式即内核态,在这一状态下,设施的所有拜访以及各种特权命令执行都是被容许的。内核管制对于设施的拜访来实现多过程解决。除非明确指定,否则过程之间或者用户之间的数据是无奈相互拜访的 用户态(user mode):运行用户程序的时候,CPU 处于的模式。通过零碎调用,会从用户态切换到内核态用更高的权限级别执行: 用户态切换到内核态是一种模式切换(mode switch),所有的零碎调用都会模式切换,某些零碎调用还会上下文切换:遇到硬盘 IO 或者网络 IO 的线程会上下文切换到能够运行的线程。这种切换都是有性能损耗的,个别通过如下几种优化来防止: 用户模式零碎调用(User-mode syscalls):能够在用户模式库实现一些零碎调用。Linux 通过裸露 virtual dynamic shared object (vDSO)来实现,能够参考:https://man7.org/linux/man-pa...内存映射(Memory mappings):用于按需装载内存页(缺页中断),前面还会提到。这样能防止间接拜访 IO 造成零碎调用。内核绕开(Kernel bypass):能够让用户态程序间接拜访设施,例如 DPDK(Data Plane Development Kit),这里举荐一篇对于 DPDK 的文章内核态利用:例如运行在内核的 TUX 服务器,以及 BPF(Berkeley Packet Filter). 对于 BPF,有一个驰名的基于 BPF 实现的工具汇合是:https://github.com/iovisor/bcc ...

November 17, 2021 · 1 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版35-验证线程隔离正确性

本系列代码地址:https://github.com/JoJoTec/sp...上一节咱们通过单元测试验证了重试的正确性,这一节咱们来验证咱们线程隔离的正确性,次要包含: 验证配置正确加载:即咱们在 Spring 配置(例如 application.yml)中的退出的 Resilience4j 的配置被正确加载利用了。雷同微服务调用不同实例的时候,应用的是不同的线程(池)。验证配置正确加载与之前验证重试相似,咱们能够定义不同的 FeignClient,之后查看 resilience4j 加载的线程隔离配置来验证线程隔离配置的正确加载。 并且,与重试配置不同的是,通过系列后面的源码剖析,咱们晓得 spring-cloud-openfeign 的 FeignClient 其实是懒加载的。所以咱们实现的线程隔离也是懒加载的,须要先调用,之后才会初始化线程池。所以这里咱们须要先进行调用之后,再验证线程池配置。 首先定义两个 FeignClient,微服务别离是 testService1 和 testService2,contextId 别离是 testService1Client 和 testService2Client @FeignClient(name = "testService1", contextId = "testService1Client")public interface TestService1Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}@FeignClient(name = "testService2", contextId = "testService2Client") public interface TestService2Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}而后,咱们减少 Spring 配置,并且给两个微服务都增加一个实例,应用 SpringExtension 编写单元测试类: //SpringExtension也蕴含了 Mockito 相干的 Extension,所以 @Mock 等注解也失效了@ExtendWith(SpringExtension.class)@SpringBootTest(properties = { //默认申请重试次数为 3 "resilience4j.retry.configs.default.maxAttempts=3", // testService2Client 外面的所有办法申请重试次数为 2 "resilience4j.retry.configs.testService2Client.maxAttempts=2", //默认线程池配置 "resilience4j.thread-pool-bulkhead.configs.default.coreThreadPoolSize=10", "resilience4j.thread-pool-bulkhead.configs.default.maxThreadPoolSize=10", "resilience4j.thread-pool-bulkhead.configs.default.queueCapacity=1" , //testService2Client 的线程池配置 "resilience4j.thread-pool-bulkhead.configs.testService2Client.coreThreadPoolSize=5", "resilience4j.thread-pool-bulkhead.configs.testService2Client.maxThreadPoolSize=5", "resilience4j.thread-pool-bulkhead.configs.testService2Client.queueCapacity=1",})@Log4j2public class OpenFeignClientTest { @SpringBootApplication @Configuration public static class App { @Bean public DiscoveryClient discoveryClient() { //模仿两个服务实例 ServiceInstance service1Instance1 = Mockito.spy(ServiceInstance.class); ServiceInstance service2Instance2 = Mockito.spy(ServiceInstance.class); Map<String, String> zone1 = Map.ofEntries( Map.entry("zone", "zone1") ); when(service1Instance1.getMetadata()).thenReturn(zone1); when(service1Instance1.getInstanceId()).thenReturn("service1Instance1"); when(service1Instance1.getHost()).thenReturn("www.httpbin.org"); when(service1Instance1.getPort()).thenReturn(80); when(service2Instance2.getInstanceId()).thenReturn("service1Instance2"); when(service2Instance2.getHost()).thenReturn("httpbin.org"); when(service2Instance2.getPort()).thenReturn(80); DiscoveryClient spy = Mockito.spy(DiscoveryClient.class); Mockito.when(spy.getInstances("testService1")) .thenReturn(List.of(service1Instance1)); Mockito.when(spy.getInstances("testService2")) .thenReturn(List.of(service2Instance2)); return spy; } }}编写测试代码,验证配置正确: ...

November 16, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版34验证重试配置正确性3

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续上一节针对咱们的重试进行测试 验证针对可重试的办法响应超时异样重试正确咱们能够通过 httpbin.org 的 /delay/响应工夫秒 来实现申请响应超时。例如 /delay/3 就会提早三秒后返回。这个接口也是能够承受任何类型的 HTTP 申请办法。 咱们先来指定对于 Feign 超时的配置 Options: //SpringExtension也蕴含了 Mockito 相干的 Extension,所以 @Mock 等注解也失效了@ExtendWith(SpringExtension.class)@SpringBootTest(properties = { //敞开 eureka client "eureka.client.enabled=false", //默认申请重试次数为 3 "resilience4j.retry.configs.default.maxAttempts=3", //指定默认响应超时为 2s "feign.client.config.default.readTimeout=2000",})@Log4j2public class OpenFeignClientTest { @SpringBootApplication @Configuration public static class App { @Bean public DiscoveryClient discoveryClient() { //模仿两个服务实例 ServiceInstance service1Instance1 = Mockito.spy(ServiceInstance.class); ServiceInstance service1Instance3 = Mockito.spy(ServiceInstance.class); Map<String, String> zone1 = Map.ofEntries( Map.entry("zone", "zone1") ); when(service1Instance1.getMetadata()).thenReturn(zone1); when(service1Instance1.getInstanceId()).thenReturn("service1Instance1"); when(service1Instance1.getHost()).thenReturn("httpbin.org"); when(service1Instance1.getPort()).thenReturn(80); DiscoveryClient spy = Mockito.spy(DiscoveryClient.class); //微服务 testService1 有一个实例即 service1Instance1 Mockito.when(spy.getInstances("testService1")) .thenReturn(List.of(service1Instance1)); return spy; } }}咱们别离定义会超时和不会超时的接口: ...

November 15, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版34验证重试配置正确性2

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续上一节针对咱们的重试进行测试 验证针对限流器异样的重试正确通过系列后面的源码剖析,咱们晓得 spring-cloud-openfeign 的 FeignClient 其实是懒加载的。所以咱们实现的断路器也是懒加载的,须要先调用,之后才会初始化线程隔离。所以这里如果咱们要模仿线程隔离满的异样,须要先手动读取载入线程隔离,之后能力获取对应实例的线程隔离,将线程池填充斥。 咱们先定义一个 FeignClient: @FeignClient(name = "testService1", contextId = "testService1Client")public interface TestService1Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}应用后面同样的形式,给这个微服务增加实例: //SpringExtension也蕴含了 Mockito 相干的 Extension,所以 @Mock 等注解也失效了@ExtendWith(SpringExtension.class)@SpringBootTest(properties = { //敞开 eureka client "eureka.client.enabled=false", //默认申请重试次数为 3 "resilience4j.retry.configs.default.maxAttempts=3", //减少断路器配置 "resilience4j.circuitbreaker.configs.default.failureRateThreshold=50", "resilience4j.circuitbreaker.configs.default.slidingWindowType=COUNT_BASED", "resilience4j.circuitbreaker.configs.default.slidingWindowSize=5", "resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls=2",})@Log4j2public class OpenFeignClientTest { @SpringBootApplication @Configuration public static class App { @Bean public DiscoveryClient discoveryClient() { //模仿两个服务实例 ServiceInstance service1Instance1 = Mockito.spy(ServiceInstance.class); ServiceInstance service1Instance3 = Mockito.spy(ServiceInstance.class); Map<String, String> zone1 = Map.ofEntries( Map.entry("zone", "zone1") ); when(service1Instance1.getMetadata()).thenReturn(zone1); when(service1Instance1.getInstanceId()).thenReturn("service1Instance1"); when(service1Instance1.getHost()).thenReturn("httpbin.org"); when(service1Instance1.getPort()).thenReturn(80); when(service1Instance3.getMetadata()).thenReturn(zone1); when(service1Instance3.getInstanceId()).thenReturn("service1Instance3"); //这其实就是 httpbin.org ,为了和第一个实例进行辨别加上 www when(service1Instance3.getHost()).thenReturn("www.httpbin.org"); DiscoveryClient spy = Mockito.spy(DiscoveryClient.class); //微服务 testService3 有两个实例即 service1Instance1 和 service1Instance4 Mockito.when(spy.getInstances("testService1")) .thenReturn(List.of(service1Instance1, service1Instance3)); return spy; } }}而后,编写测试代码: ...

November 14, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版34验证重试配置正确性1

本系列代码地址:https://github.com/JoJoTec/sp...在后面一节,咱们利用 resilience4j 粘合了 OpenFeign 实现了断路器、重试以及线程隔离,并应用了新的负载平衡算法优化了业务激增时的负载平衡算法体现。这一节,咱们开始编写单元测试验证这些性能的正确性,以便于日后降级依赖,批改的时候能保障正确性。同时,通过单元测试,咱们更能深刻了解 Spring Cloud。 验证重试配置对于咱们实现的重试,咱们须要验证: 验证配置正确加载:即咱们在 Spring 配置(例如 application.yml)中的退出的 Resilience4j 的配置被正确加载利用了。验证针对 ConnectTimeout 重试正确:FeignClient 能够配置 ConnectTimeout 连贯超时工夫,如果连贯超时会有连贯超时异样抛出,对于这种异样无论什么申请都应该重试,因为申请并没有收回。验证针对断路器异样的重试正确:断路器是微服务实例办法级别的,如果抛出断路器关上异样,应该间接重试下一个实例。验证针对限流器异样的重试正确:当某个实例线程隔离满了的时候,抛出线程限流异样应该间接重试下一个实例。验证针对非 2xx 响应码可重试的办法重试正确验证针对非 2xx 响应码不可重试的办法没有重试验证针对可重试的办法响应超时异样重试正确:FeignClient 能够配置 ReadTimeout 即响应超时,如果办法能够重试,则须要重试。验证针对不可重试的办法响应超时异样不能重试:FeignClient 能够配置 ReadTimeout 即响应超时,如果办法不能够重试,则不能重试。验证配置正确加载咱们能够定义不同的 FeignClient,之后查看 resilience4j 加载的重试配置来验证重试配置的正确加载。 首先定义两个 FeignClient,微服务别离是 testService1 和 testService2,contextId 别离是 testService1Client 和 testService2Client @FeignClient(name = "testService1", contextId = "testService1Client")public interface TestService1Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}@FeignClient(name = "testService2", contextId = "testService2Client") public interface TestService2Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}而后,咱们减少 Spring 配置,应用 SpringExtension 编写单元测试类: ...

November 13, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版33-实现重试断路器以及线程隔离源码

本系列代码地址:https://github.com/JoJoTec/sp...在后面两节,咱们梳理了实现 Feign 断路器以及线程隔离的思路,并阐明了如何优化目前的负载平衡算法。然而如何更新负载平衡的数据缓存,以及实现重试、断路器以及线程隔离的源码还没提,这一节咱们会详细分析。 首先,从 spring.factories 引入,减少咱们自定义 OpenFeign 配置的加载: spring.factories # AutoConfigurationorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.github.jojotech.spring.cloud.webmvc.auto.OpenFeignAutoConfiguration主动配置类是 OpenFeignAutoConfiguration,其内容是: OpenFeignAutoConfiguration.java //设置 `@Configuration(proxyBeanMethods=false)`,因为没有 @Bean 的办法相互调用须要每次返回同一个 Bean,没必要代理,敞开减少启动速度@Configuration(proxyBeanMethods = false)//加载配置,CommonOpenFeignConfiguration@Import(CommonOpenFeignConfiguration.class)//启用 OpenFeign 注解扫描和配置,默认配置为 DefaultOpenFeignConfiguration,其实就是 Feign 的 NamedContextFactory(即 FeignContext)的默认配置类是 DefaultOpenFeignConfiguration@EnableFeignClients(value = "com.github.jojotech", defaultConfiguration = DefaultOpenFeignConfiguration.class)public class OpenFeignAutoConfiguration {}为何要加这一层而不是间接应用 Import 的 CommonOpenFeignConfiguration?应用 @AutoConfigurationBefore 和 @AutoConfigurationAfter 配置和其余 AutoConfiguration 加载的前后程序。 @AutoConfigurationBefore 和 @AutoConfigurationAfter 是 spring-boot 的注解,只对于 spring.factories 加载的 AutoConfiguration 失效。所以在设计上要加上这一层,避免咱们将来可能会用到这些注解。 CommonOpenFeignConfiguration 中蕴含所有 OpenFeign 的共用的一些 Bean,这些 Bean 是单例被所有 FeignClient 专用的,包含: FeignClient 要用的 Client 的底层 HTTP Client,咱们这里应用 Apache HttpClient将 Apache HttpClient 封装成 FeignClient 要用的 Client 的 ApacheHttpClientspring-cloud-openfeign 的 FeignClient 用的 Client 的负载平衡实现外围类是 FeignBlockingLoadBalancerClient,咱们须要将其封装代理从而实现断路器和线程隔离以及负载平衡数据采集,封装类是咱们本人实现的 FeignBlockingLoadBalancerClientDelegate。外围实现断路器和线程隔离逻辑的类是 Resilience4jFeignClient。CommonOpenFeignConfiguration.java ...

November 12, 2021 · 5 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版32-改进负载均衡算法

本系列代码地址:https://github.com/JoJoTec/sp...在后面一节,咱们梳理了实现 Feign 断路器以及线程隔离的思路,这一节,咱们先不看如何源码实现(因为源码中会蕴含负载平衡算法的改良局部),先来探讨下如何优化目前的负载平衡算法。 之前的负载平衡算法获取服务实例列表,将实例列表依照 ip 端口排序,如果不排序即便 position 是下一个可能也代表的是之前曾经调用过的实例依据申请中的 traceId,从本地缓存中以 traceId 为 key 获取一个初始值为随机数的原子变量 position,这样避免所有申请都从第一个实例开始调用,之后第二个、第三个这样。position 原子加一,之后对实例个数取余,返回对应下标的实例进行调用其中申请蕴含 traceId 是来自于咱们应用了 spring-cloud-sleuth 链路追踪,基于这种机制咱们能保障申请不会重试到之前曾经调用过的实例。源码是: //肯定必须是实现ReactorServiceInstanceLoadBalancer//而不是ReactorLoadBalancer<ServiceInstance>//因为注册的时候是ReactorServiceInstanceLoadBalancer@Log4j2public class RoundRobinWithRequestSeparatedPositionLoadBalancer implements ReactorServiceInstanceLoadBalancer { private final ServiceInstanceListSupplier serviceInstanceListSupplier; //每次申请算上重试不会超过1分钟 //对于超过1分钟的,这种申请必定比拟重,不应该重试 private final LoadingCache<Long, AtomicInteger> positionCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES) //随机初始值,避免每次都是从第一个开始调用 .build(k -> new AtomicInteger(ThreadLocalRandom.current().nextInt(0, 1000))); private final String serviceId; private final Tracer tracer; public RoundRobinWithRequestSeparatedPositionLoadBalancer(ServiceInstanceListSupplier serviceInstanceListSupplier, String serviceId, Tracer tracer) { this.serviceInstanceListSupplier = serviceInstanceListSupplier; this.serviceId = serviceId; this.tracer = tracer; } //每次重试,其实都会调用这个 choose 办法从新获取一个实例 @Override public Mono<Response<ServiceInstance>> choose(Request request) { return serviceInstanceListSupplier.get().next().map(serviceInstances -> getInstanceResponse(serviceInstances)); } private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> serviceInstances) { if (serviceInstances.isEmpty()) { log.warn("No servers available for service: " + this.serviceId); return new EmptyResponse(); } return getInstanceResponseByRoundRobin(serviceInstances); } private Response<ServiceInstance> getInstanceResponseByRoundRobin(List<ServiceInstance> serviceInstances) { if (serviceInstances.isEmpty()) { log.warn("No servers available for service: " + this.serviceId); return new EmptyResponse(); } //为了解决原始算法不同调用并发可能导致一个申请重试雷同的实例 //从 sleuth 的 Tracer 中获取以后申请的上下文 Span currentSpan = tracer.currentSpan(); //如果上下文不存在,则可能不是前端用户申请,而是其余某些机制触发,咱们就创立一个新的上下文 if (currentSpan == null) { currentSpan = tracer.newTrace(); } //从申请上下文中获取申请的 traceId,用来惟一标识一个申请 long l = currentSpan.context().traceId(); AtomicInteger seed = positionCache.get(l); int s = seed.getAndIncrement(); int pos = s % serviceInstances.size(); log.info("position {}, seed: {}, instances count: {}", pos, s, serviceInstances.size()); return new DefaultResponse(serviceInstances.stream() //实例返回列表程序可能不同,为了保持一致,先排序再取 .sorted(Comparator.comparing(ServiceInstance::getInstanceId)) .collect(Collectors.toList()).get(pos)); }}然而在这次申请突增很多的时候,这种负载平衡算法还是给咱们带来了问题。 ...

November 11, 2021 · 4 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版31-FeignClient-实现断路器以及线程隔离限流的思路

本系列代码地址:https://github.com/JoJoTec/sp...在后面一节,咱们实现了 FeignClient 粘合 resilience4j 的 Retry 实现重试。仔细的读者可能会问,为何在这里的实现,不把断路器和线程限流一起加上呢: @Beanpublic FeignDecorators.Builder defaultBuilder( Environment environment, RetryRegistry retryRegistry) { //获取微服务名称 String name = environment.getProperty("feign.client.name"); Retry retry = null; try { retry = retryRegistry.retry(name, name); } catch (ConfigurationNotFoundException e) { retry = retryRegistry.retry(name); } //笼罩其中的异样判断,只针对 feign.RetryableException 进行重试,所有须要重试的异样咱们都在 DefaultErrorDecoder 以及 Resilience4jFeignClient 中封装成了 RetryableException retry = Retry.of(name, RetryConfig.from(retry.getRetryConfig()).retryOnException(throwable -> { return throwable instanceof feign.RetryableException; }).build()); return FeignDecorators.builder().withRetry( retry );}次要起因是,这里减少断路器以及线程隔离,其粒度是微服务级别的,这样的害处是: 微服务中只有有一个实例始终异样,整个微服务就会被断路微服务只有有一个办法始终异样,整个微服务就会被断路微服务的某个实例比较慢,其余实例失常,然而轮询的负载平衡模式导致线程池被这个实例的申请堵满。因为这一个慢实例,倒是整个微服务的申请都被拖慢回顾咱们想要实现的微服务重试、断路、线程隔离申请重试来看几个场景: 1.在线公布服务的时候,或者某个服务呈现问题下线的时候,旧服务实例曾经在注册核心下线并且实例曾经敞开,然而其余微服务本地有服务实例缓存或者正在应用这个服务实例进行调用,这时候个别会因为无奈建设 TCP 连贯而抛出一个 java.io.IOException,不同框架应用的是这个异样的不同子异样,然而提示信息个别有 connect time out 或者 no route to host。这时候如果重试,并且重试的实例不是这个实例而是失常的实例,就能调用胜利。如下图所示: ...

November 10, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版30-FeignClient-实现重试

本系列代码地址:https://github.com/JoJoTec/sp...须要重试的场景微服务零碎中,会遇到在线公布,个别的公布更新策略是:启动一个新的,启动胜利之后,敞开一个旧的,直到所有的旧的都被敞开。Spring Boot 具备优雅敞开的性能,能够保障申请解决完再敞开,同时会回绝新的申请。对于这些回绝的申请,为了保障用户体验不受影响,是须要重试的。 云上部署的微服务,对于同一个服务,同一个申请,很可能不会所有实例都同时异样,例如: Kubernetes 集群部署的实例,可能同一个虚拟机 Node 在闲时部署了多个不同微服务实例,当压力变大时,就须要迁徙和扩容。这时候因为不同的微服务压力不同,过后处于哪一个 Node 也说不定,有的可能处于压力大的,有的可能处于压力小的。对于同一个微服务,可能并不会所有实例位于的 Node 压力都大。云上部署个别会跨可用区部署,如果有一个可用区异样,另一个可用区还能够持续提供服务。某个业务触发了 Bug,导致实例始终在 GC,然而这种申请个别很不常见,不会发到所有实例上。这时候,就须要咱们对申请进行无感知的重试。 重试须要思考的问题重试须要重试与之前不同的实例,甚至是不处于同一个虚拟机 Node 的实例,这个次要通过 LoadBalancer 实现,能够参考之前的 LoadBalancer 局部。前面的文章,咱们还会改良 LoadBalancer重试须要思考到底什么申请能重试,以及什么异样能重试: 假如咱们有查问接口,和没有做幂等性的扣款接口,那么很直观的就能感觉出查问接口是能够重试的,没有做幂等性的扣款接口是不能重试的。业务上不能重试的接口,对于非凡的异样(其实是示意申请并没有收回去的异样),咱们是能够重试的。尽管是没有做幂等性的扣款接口,然而如果抛出的是起因是 Connect Timeout 的 IOException,这样的异样代表申请还没有收回去,是能够重试的。重试策略:重试几次,重试距离。类比多处理器编程模式中的 Busy Spin 策略会造成很大的总线通量从而升高性能这个景象,如果失败立即重试,那么在某一个实例异样导致超时的时候,会在同一时间有很多申请重试到其余实例。最好加上肯定提早。应用 resilience4j 实现 FeignClient 重试FeignClient 自身带重试,然而重试策略绝对比较简单,同时咱们还想应用断路器以及限流器还有线程隔离,resilience4j 就蕴含这些组件。 原理简介Resilience4J 提供了 Retryer 重试器,官网文档地址:https://resilience4j.readme.i... 从配置上就能了解其中的原理,然而官网文档配置并不全面,如果想看所有的配置,最好还是通过源码: RetryConfigurationProperties.java //重试距离,默认 500ms@Nullableprivate Duration waitDuration;//重试间隔时间函数,和 waitDuration 只能设置一个,默认就是 waitDuration@Nullableprivate Class<? extends IntervalBiFunction<Object>> intervalBiFunction;//最大重试次数,包含自身那次调用@Nullableprivate Integer maxAttempts;//通过抛出的异样判断是否重试,默认是只有有异样就会重试@Nullableprivate Class<? extends Predicate<Throwable>> retryExceptionPredicate;//通过后果判断是否重试,默认是只有获取到后果就不重试@Nullableprivate Class<? extends Predicate<Object>> resultPredicate;//配置抛出这些异样以及子类则会重试@SuppressWarnings("unchecked")@Nullableprivate Class<? extends Throwable>[] retryExceptions;//配置抛出这些异样以及子类则不会重试@SuppressWarnings("unchecked")@Nullableprivate Class<? extends Throwable>[] ignoreExceptions;//启用 ExponentialBackoff 提早算法,首次重试延迟时间为 waitDuration,之后每次重试延迟时间都乘以 exponentialBackoffMultiplier,直到 exponentialMaxWaitDuration@Nullableprivate Boolean enableExponentialBackoff;private Double exponentialBackoffMultiplier;private Duration exponentialMaxWaitDuration;//启用随机提早算法,范畴是 waitDuration - randomizedWaitFactor*waitDuration ~ waitDuration + randomizedWaitFactor*waitDuration@Nullableprivate Boolean enableRandomizedWait;private Double randomizedWaitFactor;@Nullableprivate Boolean failAfterMaxAttempts;引入 resilience4j-spring-boot2 的依赖,就能够通过 Properties 配置的形式去配置 Retryer 等所有 resilience4j 组件,例如: ...

November 9, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版29Spring-Cloud-OpenFeign-的解析2

本系列代码地址:https://github.com/JoJoTec/sp...在应用云原生的很多微服务中,比拟小规模的可能间接依附云服务中的负载均衡器进行外部域名与服务映射,通过健康检查接口判断实例衰弱状态,而后间接应用 OpenFeign 生成对应域名的 Feign Client。Spring Cloud 生态中,对 OpenFeign 进行了封装,其中的 Feign Client 的各个组件,也是做了肯定的定制化,能够实现在 OpenFeign Client 中集成服务发现与负载平衡。在此基础上,咱们还联合了 Resilience4J 组件,实现了微服务实例级别的线程隔离,微服务办法级别的断路器以及重试。 咱们先来剖析下 Spring Cloud OpenFeign Spring Cloud OpenFeign 解析HTTP 编码解码器,与 spring-boot 中的编码解码器相结合Spring Cloud 中的任何组件,都是基于 Spring Boot 而实现的。因为 Spring Boot 中曾经有了 HTTP 编码解码器,就能够不必独自给 OpenFeign 独自再实现 HTTP 编码解码器了,而是思考将 OpenFeign 的编码解码器接口用 Spring Boot 的 HTTP 编码解码器实现。 在 FeignClientsConfiguration 中,提供了默认的实现: //因为初始化程序以及 NamedContextFactory 的 Configuration 初始化的起因,这里须要注入 ObjectFactory 而不是间接注入 HttpMessageConverters 避免找不到 Bean@Autowiredprivate ObjectFactory<HttpMessageConverters> messageConverters;@Bean@ConditionalOnMissingBeanpublic Decoder feignDecoder() { return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));}@Bean@ConditionalOnMissingBean//咱们这里疏忽 Pageable 类存在的状况//针对 Spring Data 的分页包装 Pageable 的兼容实现也比较简单,这里疏忽@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) { return springEncoder(formWriterProvider, encoderProperties);}private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider, FeignEncoderProperties encoderProperties) { AbstractFormWriter formWriter = formWriterProvider.getIfAvailable(); if (formWriter != null) { return new SpringEncoder(new SpringPojoFormEncoder(formWriter), this.messageConverters, encoderProperties); } else { return new SpringEncoder(new SpringFormEncoder(), this.messageConverters, encoderProperties); }}基于 SpringDecoder 的解码器通过源码能够看出,默认的 Decoder 是通过几层包装的 Decoder,别离包含: ...

November 8, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版29Spring-Cloud-OpenFeign-的解析1

本系列代码地址:https://github.com/JoJoTec/sp...在应用云原生的很多微服务中,比拟小规模的可能间接依附云服务中的负载均衡器进行外部域名与服务映射,通过健康检查接口判断实例衰弱状态,而后间接应用 OpenFeign 生成对应域名的 Feign Client。Spring Cloud 生态中,对 OpenFeign 进行了封装,其中的 Feign Client 的各个组件,也是做了肯定的定制化,能够实现在 OpenFeign Client 中集成服务发现与负载平衡。在此基础上,咱们还联合了 Resilience4J 组件,实现了微服务实例级别的线程隔离,微服务办法级别的断路器以及重试。 咱们先来剖析下 Spring Cloud OpenFeign Spring Cloud OpenFeign 解析从 NamedContextFactory 动手Spring Cloud OpenFeign 的 github 地址:https://github.com/spring-clo... 首先,依据咱们之前剖析 spring-cloud-loadbalancer 的流程,咱们先从继承 NamedContextFactory 的类动手,这里是 FeignContext,通过其构造函数,失去其中的默认配置类: FeignContext.java public FeignContext() { super(FeignClientsConfiguration.class, "feign", "feign.client.name");}从构造方法能够看出,默认的配置类是:FeignClientsConfiguration。咱们接下来详细分析这个配置类中的元素,并与咱们之前剖析的 OpenFeign 的组件联合起来。 负责解析类元数据的 Contract,与 spring-web 的 HTTP 注解相结合为了开发人员更好上手应用和了解,最好能实现应用 spring-web 的 HTTP 注解(例如 @RequestMapping,@GetMapping 等等)去定义 FeignClient 接口。在 FeignClientsConfiguration 中就是这么做的: FeignClientsConfiguration.java @Autowired(required = false)private FeignClientProperties feignClientProperties;@Autowired(required = false)private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();@Autowired(required = false)private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();@Bean@ConditionalOnMissingBeanpublic Contract feignContract(ConversionService feignConversionService) { boolean decodeSlash = feignClientProperties == null || feignClientProperties.isDecodeSlash(); return new SpringMvcContract(this.parameterProcessors, feignConversionService, decodeSlash);}@Beanpublic FormattingConversionService feignConversionService() { FormattingConversionService conversionService = new DefaultFormattingConversionService(); for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) { feignFormatterRegistrar.registerFormatters(conversionService); } return conversionService;}其外围提供的 Feign 的 Contract 就是 SpringMvcContract,SpringMvcContract 次要蕴含两局部外围逻辑: ...

November 7, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版28OpenFeign的生命周期进行调用

本系列代码地址:https://github.com/JoJoTec/sp...接下来,咱们开始剖析 OpenFeign 同步环境下的生命周期的第二局部,应用 SynchronousMethodHandler 进行理论调用,其流程能够总结为: 调用代理类的办法理论调用的是后面一章中生成的 InvocationHandler 的 invoke 办法。默认实现是查问 Map<Method, MethodHandler> methodToHandler 找到对应的 MethodHandler 进行调用,对于同步 Feign,其实就是 SynchronousMethodHandler对于 SynchronousMethodHandler: 应用后面一章剖析创立的创立的申请模板工厂 RequestTemplate.Factory,创立申请模板 RequestTemplate。读取 Options 配置应用配置的 Retryer 创立新的 Retryer执行申请并将响应反序列化 - executeAndDecode:如果配置了 RequestInterceptor,则执行每一个 RequestInterceptor将申请模板 RequestTemplate 转化为理论申请 Request通过 Client 执行 Request如果响应码是 2XX,应用 Decoder 解析 Response如果响应码是 404,并且在后面一章介绍的配置中配置了 decode404 为 true, 应用 Decoder 解析 Response对于其余响应码,应用 errorDecoder 解析,能够本人实现 errorDecoder 抛出 RetryableException 来走入重试逻辑如果以上步骤抛出 IOException,间接封装成 RetryableException 抛出 如果第 4 步抛出 RetryableException,则应用第三步创立的 Retryer 判断是否重试,如果须要重试,则从新走第 4 步,否则,抛出异样。给出这个流程后,咱们来详细分析 OpenFeign的生命周期-进行调用源码剖析后面一章的最初,咱们曾经从源码中看到了这一章结尾提到的流程的前两步,咱们间接从第三步开始剖析。 SynchronousMethodHandler ...

October 17, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版27OpenFeign的生命周期创建代理

本系列代码地址:https://github.com/JoJoTec/sp...接下来,咱们开始剖析 OpenFeign 的生命周期,联合 OpenFeign 自身的源代码。首先是从接口定义创立 OpenFeign 代理开始。咱们这里只关怀同步客户端,因为异步客户端目前还在实现中,并且在咱们的我的项目中,异步响应式的客户端不必 OpenFeign,而是用的官网的 WebClient 创立 OpenFeign 代理创立 OpenFeign 代理,次要分为以下几步: 应用 Contract 解析接口的每一个办法,生成每一个办法的元数据列表:List<MethodMetadata> metadata依据每一个 MethodMetadata,生成对应的申请模板工厂 RequestTemplate.Factory,用于生成前面的申请。同时,应用这个模板工厂以及其余配置生成对应的办法处理器 MethodHandler,对于同步的 OpenFeign,MethodHandler 实现为 SynchronousMethodHandler。将接口办法与 MethodHandler 一一对应建设映射,后果为 Map<Method, MethodHandler> methodToHandler。对于 Java 8 引入的 interface default 办法,须要用不同 MethodHandler,即 DefaultMethodHandler ,因为这种办法不必代理,不必生成对应的 http 调用,其实现为间接调用对应的 default 办法代码。应用 InvocationHandlerFactory 这个工厂,创立 InvocationHandler 用于代理调用。调用 JDK 动静代理生成类办法应用 InvocationHandler 创立代理类。创立 OpenFeign 代理,次要基于 JDK 的动静代理实现。咱们先举一个简略的例子,创立一个 JDK 动静代理,用来类比。 JDK 动静代理应用 JDK 动静代理,须要如下几个步骤: 1. 编写接口以及对应的代理类。咱们这里编写一个简略的接口和对应的实现类: public interface TestService { void test();}public class TestServiceImpl implements TestService { @Override public void test() { System.out.println("TestServiceImpl#test is called"); }}2.创立代理类实现java.lang.reflect.InvocationHandler,并且,在外围办法中,调用理论的对象,这里即咱们下面 TestService 的实现类 TestServiceImpl 的对象。 ...

October 16, 2021 · 5 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版26OpenFeign的组件

本系列代码地址:https://github.com/JoJoTec/sp...首先,咱们给出官网文档中的组件结构图: 官网文档中的组件,是以实现性能为维度的,咱们这里是以源码实现为维度的(因为之后咱们应用的时候,须要依据须要定制这些组件,所以须要从源码角度去拆分剖析),可能会有一些小差别。 负责解析类元数据的 ContractOpenFeign 是通过代理类元数据来主动生成 HTTP API 的,那么到底解析哪些类元数据,哪些类元数据是无效的,是通过指定 Contract 来实现的,咱们能够通过实现这个 Contract 来自定义一些类元数据的解析,例如,咱们自定义一个注解: //仅可用于办法上@java.lang.annotation.Target(METHOD)//指定注解放弃到运行时@Retention(RUNTIME)@interface Get { //申请 uri String uri();}这个注解很简略,标注了这个注解的办法会被主动封装成 GET 申请,申请 uri 为 uri() 的返回。 而后,咱们自定义一个 Contract 来解决这个注解。因为 MethodMetadata 是 final 并且是 package private 的,所以咱们只能继承 Contract.BaseContract 去自定义注解解析: //内部自定义必须继承 BaseContract,因为外面生成的 MethodMetadata 的结构器是 package private 的static class CustomizedContract extends Contract.BaseContract { @Override protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) { //解决类下面的注解,这里没用到 } @Override protected void processAnnotationOnMethod(MethodMetadata data, Annotation annotation, Method method) { //解决办法下面的注解 Get get = method.getAnnotation(Get.class); //如果 Get 注解存在,则指定办法 HTTP 申请形式为 GET,同时 uri 指定为注解 uri() 的返回 if (get != null) { data.template().method(Request.HttpMethod.GET); data.template().uri(get.uri()); } } @Override protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) { //解决参数下面的注解,这里没用到 return false; }}而后,咱们来应用这个 Contract: ...

October 7, 2021 · 5 min · jiezi

关于spring-cloud:Spring-Cloud-Gateway-动态修改请求参数解决-URL-编码错误传参问题

Spring Cloud Gateway 动静批改申请参数解决 # URL 编码谬误传参问题继实现动静批改申请 Body 以及重试带 Body 的申请之后,咱们又遇到了一个小问题。最近很多接口,收到了谬误的参数,在接口层报的错是: class org.springframework.web.method.annotation.MethodArgumentTypeMismatchException, Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "10#scrollTop=8178" 例如下面这个报错即原本应该是一个数字,后果收到的是 10#scrollTop=8178 导致转换异样。 失常的申请,是能够带 # 的,# 前面的局部属于 fragment。一个 URI 包含: 然而对于这些报错的申请,咱们发现,发送的申请的原始 URI 中, # 被谬误的 URL 编码了,变成了 %23,例如下面的申请,发到后端的是: https://zhxhash@example.com:8081/test/service?id=test&number=10%23segment1这样,后端解析到的 number 的值,就是 number=10#segment1,这样就会产生结尾提到的报错。 因为前端没能复现这个问题,并且问题集中于某几个零碎的浏览器版本,这个问题只能通过后盾网关做批改解决。 咱们的网关应用的是 Spring Cloud Gateway,咱们能够针对全局申请增加全局 Filter,动静修改 URI,解决这个问题,代码如下: @Log4j2@Componentpublic class QueryNormalizationFilter implements GlobalFilter, Ordered { @Override @SneakyThrows public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String originUriString = exchange.getRequest().getURI().toString(); if (originUriString.contains("%23")) { //将编码后的 %23 替换为 #,从新用这个字符串生成 URI URI replaced = new URI(originUriString.replace("%23", "#")); return chain.filter( exchange.mutate() .request( new ServerHttpRequestDecorator(exchange.getRequest()) { /** * 这个是影响转发到后盾服务的 uri * * @return */ @Override public URI getURI() { return replaced; } /** * 批改这个次要为了前面的 Filter 获取查问参数是精确的 * * @return */ @Override public MultiValueMap<String, String> getQueryParams() { return UriComponentsBuilder.fromUri(replaced).build().getQueryParams(); } } ).build() ); } else { return chain.filter(exchange); } } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; }}留神点是: ...

October 5, 2021 · 1 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版25OpenFeign简介与使用

本系列代码地址:https://github.com/JoJoTec/sp...OpenFeign 的由来和实现思路在微服务零碎中,咱们常常会进行 RPC 调用。在 Spring Cloud 体系中,RPC 调用个别就是 HTTP 协定的调用。对于每次调用,根本都要通过如下步骤: 找到微服务实例列表并抉择一个实例调用参数序列化应用 Http 客户端将申请发送进来响应解决,反序列化等等除了这些公共逻辑,业务上只须要定义参数,HTTP 办法,HTTP URI,响应就能够,也就是应用接口就能定义: interface HttpBin { @Get(uri = "/get") String get(@Param("param") String param);}例如下面这个接口,就定义了一个 HTTP 申请,HTTP 办法为 GET,门路是 /get,参数是 param,响应为 String 类型。之后只有定义好公共逻辑,就能应用这个接口进行调用了。 对于这些公共逻辑的实现设计,咱们很天然的就能想到切面与动静代理。之前的章节,咱们提到过 JDK 中有针对接口的动静代理,其实就是实现 java.lang.reflect.InvocationHandler 而后针对这个接口实现代理类。之后应用这个代理类进行调用即可走入 InvocationHandler 中定义的逻辑。 以上,就是 OpenFeign 的设计实现思路与用处。 OpenFeign 简介OpenFeign 是一个基于申明式(通过类元数据定义,例如注解等)定义的 HTTP 申请客户端。这个库能够让你通过注解来主动生成调用对应 HTTP 服务的客户端,从代码上看调用这个近程服务和调用本地服务办法一样。OpenFeign 反对多种 HTTP 注解,包含 Feign 注解和 JAX-RS 注解,并且能够通过配置相似于插件的模式反对不同品种的注解。同时,还能够配置编码器,解码器,来编码申请并解码响应。底层的 HTTP Client 也是能够配置的,你能够应用 Java 原生的 Http 链接,也能够应用 Apache HttpClient 还有 OkHttpClient 等等。 ...

October 3, 2021 · 2 min · jiezi

关于spring-cloud:启用-SpringCloudOpenFeign-配置可刷新项目无法启动我-TM-人傻了上

本篇文章波及底层设计以及原理,以及问题定位,比拟深刻,篇幅较长,所以拆分成高低两篇: 上:问题简略形容以及 Spring Cloud RefreshScope 的原理下:以后 spring-cloud-openfeign + spring-cloud-sleuth 带来的 bug 以及如何修复最近在我的项目中想实现 OpenFeign 的配置能够动静刷新(次要是 Feign 的 Options 配置),例如: feign: client: config: default: # 链接超时 connectTimeout: 500 # 读取超时 readTimeout: 8000咱们可能会察看到调用某个 FeignClient 的超时工夫不合理,须要长期批改下,咱们不想因为这种事件重启过程或者刷新整个 ApplicationContext,所以将这部分配置放入 spring-cloud-config 中并应用动静刷新的机制进行刷新。官网提供了这个配置办法,参考:官网文档 - Spring @RefreshScope Support 即在我的项目中减少配置: feign.client.refresh-enabled: true然而在咱们的我的项目中,减少了这个配置后,启动失败,报找不到相干 Bean 的谬误: Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'feign.Request.Options-testService1Client' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:863) at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1344) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1160) at org.springframework.cloud.openfeign.FeignContext.getInstance(FeignContext.java:57) at org.springframework.cloud.openfeign.FeignClientFactoryBean.getOptionsByName(FeignClientFactoryBean.java:363) at org.springframework.cloud.openfeign.FeignClientFactoryBean.configureUsingConfiguration(FeignClientFactoryBean.java:195) at org.springframework.cloud.openfeign.FeignClientFactoryBean.configureFeign(FeignClientFactoryBean.java:158) at org.springframework.cloud.openfeign.FeignClientFactoryBean.feign(FeignClientFactoryBean.java:132) at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:382) at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:371) at org.springframework.cloud.openfeign.FeignClientsRegistrar.lambda$registerFeignClient$0(FeignClientsRegistrar.java:235) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1231) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1173) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ... 74 more问题剖析通过这个 Bean 名称,其实能够看进去这个 Bean 是咱们开始提到要动静刷新的 Feign.Options,外面有连贯超时、读取超时等配置。名字前面的局部是咱们创立的 FeignClient 下面 @FeignClient 注解外面的 contextId。 ...

October 1, 2021 · 8 min · jiezi

关于spring-cloud:Spring-Cloud-Gateway-雪崩了我-TM-人傻了

本系列是 我TM人傻了 系列第六期[捂脸],往期精彩回顾: 降级到Spring 5.3.x之后,GC次数急剧减少,我TM人傻了这个大表走索引字段查问的 SQL 怎么就成全扫描了,我TM人傻了获取异样信息里再出异样就找不到日志了,我TM人傻了spring-data-redis 连贯透露,我 TM 人傻了Spring Cloud Gateway 没有链路信息,我 TM 人傻了 大家好,我又人傻了。这次的教训通知咱们,进去写代码偷的懒,迟早要还的。 问题景象与背景昨晚咱们的网关雪崩了一段时间,景象是: 1.一直有各种微服务报异样:在写 HTTP 响应的时候,连贯曾经敞开: reactor.netty.http.client.PrematureCloseException: Connection prematurely closed BEFORE response 2.同时还有申请还没读取完,连贯曾经敞开的异样: org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: UT000128: Remote peer closed connection before all data could be read 3.前端一直有申请超时的报警,504 Gateway Time-out 4.网关过程一直健康检查失败而被重启 5.重启后的网关过程,立即申请数量激增,每个实例峰值 2000 qps,闲时每个实例 500 qps,忙时因为有扩容也能放弃每个实例在 1000 qps 以内,而后健康检查接口就很长时间没有响应,导致实例一直重启 其中,1 和 2 的问题应该是应为网关一直重启,并且因为某些起因优雅敞开失败导致强制敞开,强制敞开导致连贯被强制断开从而有 1 和 2 相干的异样。 ...

September 27, 2021 · 4 min · jiezi

关于spring-cloud:Spring-Cloud-Gateway-没有链路信息我-TM-人傻了下

本系列是 我TM人傻了 系列第五期[捂脸],往期精彩回顾: 降级到Spring 5.3.x之后,GC次数急剧减少,我TM人傻了这个大表走索引字段查问的 SQL 怎么就成全扫描了,我TM人傻了获取异样信息里再出异样就找不到日志了,我TM人傻了spring-data-redis 连贯透露,我 TM 人傻了 本篇文章波及底层设计以及原理,以及问题定位和可能的问题点,十分深刻,篇幅较长,所以拆分成上中下三篇: 上:问题简略形容以及 Spring Cloud Gateway 根本构造和流程以及底层原理中:Spring Cloud Sleuth 如何在 Spring Cloud Gateway 退出的链路追踪以及为何会呈现这个问题下:现有 Spring Cloud Sleuth 的非侵入设计带来的性能问题,其余可能的问题点,以及如何解决Spring Cloud Gateway 其余的可能失落链路信息的点通过后面的剖析,咱们能够看出,不止这里,还有其余中央会导致 Spring Cloud Sleuth 的链路追踪信息隐没,这里举几个大家常见的例子: 1.在 GatewayFilter 中指定了异步执行某些工作,因为线程切换了,并且这时候可能 Span 曾经完结了,所以没有链路信息,例如: @Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange).publishOn(Schedulers.parallel()).doOnSuccess(o -> { //这里就没有链路信息了 log.info("success"); });}2.将 GatewayFilter 中持续链路的 chain.filter(exchange) 放到了异步工作中执行,下面的 AdaptCachedBodyGlobalFilter 就属于这种状况,这样会导致之后的 GatewayFilter 都没有链路信息,例如: @Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return Mono.delay(Duration.ofSeconds(1)).then(chain.filter(exchange));}Java 并发编程模型与 Project Reactor 编程模型的抵触思考Java 中的很多框架,都用到了 ThreadLocal,或者通过 Thread 来标识唯一性。例如: ...

September 26, 2021 · 3 min · jiezi

关于spring-cloud:Spring-Cloud-Gateway-没有链路信息我-TM-人傻了中

本系列是 我TM人傻了 系列第五期[捂脸],往期精彩回顾: 降级到Spring 5.3.x之后,GC次数急剧减少,我TM人傻了这个大表走索引字段查问的 SQL 怎么就成全扫描了,我TM人傻了获取异样信息里再出异样就找不到日志了,我TM人傻了spring-data-redis 连贯透露,我 TM 人傻了 本篇文章波及底层设计以及原理,以及问题定位和可能的问题点,十分深刻,篇幅较长,所以拆分成上中下三篇: 上:问题简略形容以及 Spring Cloud Gateway 根本构造和流程以及底层原理中:Spring Cloud Sleuth 如何在 Spring Cloud Gateway 退出的链路追踪以及为何会呈现这个问题下:现有 Spring Cloud Sleuth 的非侵入设计带来的性能问题,其余可能的问题点,以及如何解决Spring Cloud Sleuth 是如何减少链路信息通过之前的源码剖析,咱们晓得,在最开始的 TraceWebFilter,咱们将 Mono 封装成了一个 MonoWebFilterTrace,它的外围源码是: @Overridepublic void subscribe(CoreSubscriber<? super Void> subscriber) { Context context = contextWithoutInitialSpan(subscriber.currentContext()); Span span = findOrCreateSpan(context); //将 Span 放入执行上下文中,对于日志其实就是将链路信息放入 org.slf4j.MDC //日志的 MDC 个别都是 ThreadLocal 的 Map,对于 Log4j2 的实现类就是 org.apache.logging.log4j.ThreadContext,其外围 contextMap 就是一个基于 ThreadLocal 实现的 Map //简略了解就是将链路信息放入一个 ThreadLocal 的 Map 中,每个线程拜访本人的 Map 获取链路信息 try (CurrentTraceContext.Scope scope = this.currentTraceContext.maybeScope(span.context())) { //将理论的 subscribe 用 Span 所在的 Context 包裹住,完结时敞开 Span this.source.subscribe(new WebFilterTraceSubscriber(subscriber, context, span, this)); } //在 scope.close() 之后,会将链路信息从 ThreadLocal 的 Map 中剔除}@Overridepublic Object scanUnsafe(Attr key) { if (key == Attr.RUN_STYLE) { //执行的形式必须是不能切换线程,也就是同步的 //因为,日志的链路信息是放在 ThreadLocal 对象中,切换线程,链路信息就没了 return Attr.RunStyle.SYNC; } return super.scanUnsafe(key);}WebFilterTraceSubscriber 干了些什么呢?出现异常,以及 http 申请完结的时候,咱们可能想将响应信息,异样信息记录进入 Span 中,就是通过这个类封装实现的。 ...

September 25, 2021 · 4 min · jiezi

关于spring-cloud:Spring-Cloud-Gateway-没有链路信息我-TM-人傻了上

本系列是 我TM人傻了 系列第五期[捂脸],往期精彩回顾: 降级到Spring 5.3.x之后,GC次数急剧减少,我TM人傻了这个大表走索引字段查问的 SQL 怎么就成全扫描了,我TM人傻了获取异样信息里再出异样就找不到日志了,我TM人傻了spring-data-redis 连贯透露,我 TM 人傻了 本篇文章波及底层设计以及原理,以及问题定位和可能的问题点,十分深刻,篇幅较长,所以拆分成上中下三篇: 上:问题简略形容以及 Spring Cloud Gateway 根本构造和流程以及底层原理中:Spring Cloud Sleuth 如何在 Spring Cloud Gateway 退出的链路追踪以及为何会呈现这个问题下:现有 Spring Cloud Sleuth 的非侵入设计带来的性能问题,其余可能的问题点,以及如何解决咱们的网关应用的是 Spring Cloud Gateway,并且退出了 spring-cloud-sleuth 的依赖,用于链路追踪。并且通过 log4j2 的配置,将链路信息输入到日志中,相干的占位符是: %X{traceId},%X{spanId}然而最近发现,日志中链路信息呈现失落的状况,这是怎么回事呢? Spring Cloud Gateway 的根本流程与实现首先简略介绍一下 Spring Cloud Gateway 的根本构造,以及 Spring Cloud Sleuth 是如何在其中嵌入链路追踪相干代码的。退出 Spring Cloud Sleuth 以及 Prometheus 相干依赖之后, Spring Cloud Gateway 的解决流程如下所示: Spring Cloud Gateway 是基于 Spring WebFlux 开发的异步响应式网关,异步响应式代码比拟难以了解和浏览,我这里给大家分享一种办法去了解,通过这个流程来了解 Spring Cloud Gateway 的工作流程以及底层原理。其实能够了解为,上图这个流程,就是拼出来一个残缺的 Mono(或者 Flux)流,最初 subscribe 执行。 ...

September 24, 2021 · 5 min · jiezi

关于spring-cloud:14-java-Spring-Cloud企业快速开发架构之Eureka自我保护模式和InstanceID的配置

本节咱们次要介绍 Eureka 自我保护模式的开启和敞开和自定义 Eureka 的 InstanceID 的配置。 举荐分布式架构源码 敞开自我爱护保护模式次要在一组客户端和 Eureka Server 之间存在网络分区场景时应用。一旦进入保护模式,Eureka Server 将会尝试爱护其服务的注册表中的信息,不再删除服务注册表中的数据。当网络故障复原后,该 Eureka Server 节点会主动退出保护模式。 如果在 Eureka 的 Web 控制台看到图 1 所示的内容,就证实 Eureka Server 进入保护模式了。能够通过上面的配置将自我保护模式敞开,这个配置是在 eureka-server 中: eureka.server.enableSelfPreservation=false自定义 Eureka 的 InstanceID客户端在注册时,服务的 Instance ID 的默认值的格局如下: ${spring.cloud.client.hostname}:${spring.application.name}:${spring.application. instance_id:${server.port}}翻译过去就是“主机名:服务名称:服务端口”。当咱们在 Eureka 的 Web 控制台查看服务注册信息的时候,就是这样的一个格局: 1user-PC:eureka-client-user-service:808很多时候咱们想把 IP 显示在上述格局中,此时,只有把主机名替换成 IP 就能够了,或者调整程序也能够。能够改成上面的样子,用“服务名称:服务所在 IP:服务端口”的格局来定义: eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}定义之后咱们看到的就是 eureka-client-user-service:192.168.31.245:8081,一看就晓得是哪个服务,在哪台机器上,端口是多少。 咱们还能够点击服务的 Instance ID 进行跳转,这个时候显示的名称尽管变成了 IP,然而跳转的链接却还是主机名。 所以还须要加一个配置能力让跳转的链接变成咱们想要的样子,应用 IP 进行注册,如图 2 所示: 自定义实例跳转链接刚刚咱们通过配置实现了用 IP 进行注册,当点击 Instance ID 进行跳转的时候,就能够用 IP 跳转了,跳转的地址默认是 IP+Port/info。咱们能够自定义这个跳转的地址: ...

September 17, 2021 · 1 min · jiezi

关于spring-cloud:13-java-Spring-Cloud企业快速开发架构之使用Eureka集群搭建实现高可用服务注册中心

后面咱们搭建的注册核心只适宜本地开发应用,在生产环境中必须搭建一个集群来保障高可用。Eureka 的集群搭建办法很简略:每一台 Eureka 只须要在配置中指定另外多个 Eureka 的地址就能够实现一个集群的搭建了。举荐分布式架构源码 上面咱们以 2 个节点为例来阐明搭建形式。假如咱们有 master 和 slaveone 两台机器,须要做的就是: 将 master 注册到 slaveone 下面。将 slaveone 注册到 master 下面。如果是 3 台机器,以此类推: 将 master 注册到 slaveone 和 slavetwo 下面。将 slaveone 注册到 master 和 slavetwo 下面。将 slavetwo 注册到 master 和 slaveone 下面。搭建步骤创立一个新的我的项目 eureka-server-cluster,配置跟 eureka-server 一样。 首先,咱们须要减少 2 个属性文件,在不同的环境下启动不同的实例。减少 application-master.properties: server.port=8761# 指向你的从节点的Eurekaeureka.client.serviceUrl.defaultZone=http://用户名:明码@localhost:8762/eureka/减少 application-slaveone.properties: server.port=8762# 指向你的主节点的Eurekaeureka.client.serviceUrl.defaultZone=http://用户名:明码 @localhost:8761/eureka/在 application.properties 中增加上面的内容: spring.application.name=eureka-server-cluster# 因为该利用为注册核心, 所以设置为false, 代表不向注册核心注册本人eureka.client.register-with-eureka=false# 因为注册核心的职责就是保护服务实例, 并不需要检索服务, 所以也设置为 falseeureka.client.fetch-registry=falsespring.security.user.name=zhangsanspring.security.user.password=123456# 指定不同的环境spring.profiles.active=master在 A 机器上默认用 master 启动,而后在 B 机器上加上 --spring.profiles.active=slaveone 启动即可。 ...

September 17, 2021 · 1 min · jiezi

关于spring-cloud:12-java-Spring-Cloud企业快速开发架构之SpringCloudEureka注册中心开启密码认证

Eureka 自带了一个 Web 的治理页面,不便咱们查问注册到下面的实例信息,然而有一个问题:如果在理论应用中,注册核心地址有公网 IP 的话,必然能间接拜访到,这样是不平安的。所以咱们须要对 Eureka 进行革新,加上权限认证来保障安全性。举荐分布式架构源码革新咱们的 eureka-server,通过集成 Spring-Security 来进行平安认证。 在 pom.xml 中增加 Spring-Security 的依赖包,代码如下所示。 <dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-security</artifactId></dependency>而后在 application.properties 中加上认证的配置信息: spring.security.user.name=yinjihuan #用户名spring.security.user.password=123456 #明码减少 Security 配置类: @Configuration@EnableWebSecuritypublic class WebSecurityConfig extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {        // 敞开csrf        http.csrf().disable();        // 反对httpBasic        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();    }}重新启动注册核心,拜访 http://localhost:8761/,此时浏览器会提醒你输出用户名和明码,输出正确后能力持续拜访 Eureka 提供的治理页面。 在 Eureka 开启认证后,客户端注册的配置也要加上认证的用户名和明码信息: ...

September 17, 2021 · 1 min · jiezi

关于spring-cloud:11java-Spring-Cloud企业快速开发架构之使用Eureka编写服务提供者

本节次要解说如何应用 Eureka 编写服务提供者。 1)创立我的项目注册到 Eureka注册核心曾经创立并且启动好了,接下来咱们实现将一个服务提供者 eureka-client-user-service 注册到 Eureka 中,并提供一个接口给其余服务调用。[举荐分布式架构源码](http://minglisoft.cn/hhcloud/)首先还是创立一个 Maven 我的项目,而后在 pom.xml 中减少相干依赖,代码如下所示。 <!-- Spring Boot --><parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>2.0.6.RELEASE</version>    <relativePath /></parent><dependencies>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <!-- eureka -->    <dependency>        <groupId>org.springframework.cloud</groupId>        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>    </dependency></dependencies><!-- Spring Cloud --><dependencyManagement>    <dependencies>        <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-dependencies</artifactId>            <version>Finchley.SR2</version>            <type>pom</type>            <scope>import</scope>        </dependency>    </dependencies></dependencyManagement>创立一个启动类 App,代码如下所示。 ...

September 16, 2021 · 1 min · jiezi

关于spring-cloud:10java-Spring-Cloud企业快速开发架构之SpringCloud使用Eureka编写服务提供者

本节次要解说如何应用 Eureka 编写服务提供者。 1)创立我的项目注册到 Eureka注册核心曾经创立并且启动好了,接下来咱们实现将一个服务提供者 eureka-client-user-service 注册到 Eureka 中,并提供一个接口给其余服务调用。 首先还是创立一个 Maven 我的项目,而后在 pom.xml 中减少相干依赖,代码如下所示。  <!-- Spring Boot --><parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath /></parent><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency></dependencies><!-- Spring Cloud --><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>创立一个启动类 App,代码如下所示。 @SpringBootApplication@EnableDiscoveryClientpublic class App { public static void main(String[] args) { SpringApplication.run(App.class, args); }}启动类的办法与之前没有多大区别,只是注解换成 @EnableDiscoveryClient,示意以后服务是一个 Eureka 的客户端。 接下来在 src/main/resources 上面创立一个 application.properties 属性文件,减少上面的配置: spring.application.name= eureka-client-user-serviceserver.port=8081eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/# 采纳IP注册eureka.instance.preferIpAddress=true# 定义实例ID格局eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ip-address}:${server.port}eureka.client.serviceUrl.defaultZone 的地址就是咱们之前启动的 Eureka 服务的地址,在启动的时候须要将本身的信息注册到 Eureka 中去。 ...

September 16, 2021 · 1 min · jiezi

关于spring-cloud:9java-Spring-Cloud企业快速开发架构之SpringCloud搭建Eureka服务注册中心

首先创立一个 Maven 我的项目,取名为 eureka-server,在 pom.xml 中配置 Eureka 的依赖信息,代码如下所示。 须要框架源码请看我个人简介 <!-- Spring Boot --><parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath /></parent><dependencies> <!-- eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency></dependencies><!-- Spring Cloud --><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.SR2</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>创立一个启动类 EurekaServerApplication,代码如下所示。 @EnableEurekaServer@SpringBootApplication public static void main(String[] args) { SpringApplication.run(EurekaServer Application.class, args); }}这里所说的启动类,跟咱们之前讲的 Spring Boot 简直齐全一样,只是多了一个 @EnableEurekaServer 注解,示意开启 Eureka Server。 接下来在 src/main/resources 上面创立一个 application.properties 属性文件,减少上面的配置: spring.application.name=eureka-serverserver.port=8761# 因为该利用为注册核心, 所以设置为false, 代表不向注册核心注册本人eureka.client.register-with-eureka=false# 因为注册核心的职责就是保护服务实例, 它并不需要去检索服务, 所以也设置为 falseeureka.client.fetch-registry=false创立一个启动类 EurekaServerApplication,代码如下所示。 ...

September 16, 2021 · 1 min · jiezi

关于spring-cloud:8java-Spring-Cloud企业快速开发架构之SpringCloudSpring-Cloud-Eureka是什么

Spring Cloud Eureka 是 Spring Cloud Netflix 微服务套件的一部分,基于 Netflix Eureka 做了二次封装,次要负责实现微服务架构中的服务治理性能。 Spring Cloud Eureka 是一个基于 REST 的服务,并且提供了基于 Java 的客户端组件,可能十分不便地将服务注册到 Spring Cloud Eureka 中进行对立治理。 服务治理是微服务架构中必不可少的一部分,阿里开源的 Dubbo 框架就是针对服务治理的。服务治理必须要有一个注册核心,除了用 Eureka 作为注册核心外,咱们还能够应用 Consul、Etcd、Zookeeper 等来作为服务的注册核心。 用过 Dubbo 的读者应该分明,Dubbo 中也有几种注册核心,比方基于 Zookeeper、基于 Redis 等,不过用得最多的还是 Zookeeper 形式。 至于应用哪种形式都是能够的,注册核心无非就是治理所有服务的信息和状态。若用咱们生存中的例子来阐明的话,笔者感觉 12306 网站比拟适合。 首先,12306 网站就好比一个注册核心,顾客就好比调用的客户端,当他们须要坐火车时,就会登录 12306 网站上查问余票,有票就能够购买,而后获取火车的车次、工夫等,最初登程。 程序也是一样,当你须要调用某一个服务的时候,你会先去 Eureka 中去拉取服务列表,查看你调用的服务在不在其中,在的话就拿到服务地址、端口等信息,而后调用。 注册核心带来的益处就是,不须要晓得有多少提供方,你只须要关注注册核心即可,就像顾客不用关怀有多少火车在开行,只须要去 12306 网站上看有没有票就能够了。 为什么 Eureka 比 Zookeeper 更适宜作为注册核心呢?次要是因为 Eureka 是基于 AP 准则构建的,而 ZooKeeper 是基于 CP 准则构建的。 在分布式系统畛域有个驰名的 CAP 定理,即 C 为数据一致性;A 为服务可用性;P 为服务对网络分区故障的容错性。这三个个性在任何分布式系统中都不能同时满足,最多同时满足两个。 ...

September 16, 2021 · 1 min · jiezi

关于spring-cloud:7java-Spring-Cloud企业快速开发架构之Spring-Boot-Starter的介绍及使用

Spring Boot 的便利性体现在,它简化了很多繁缛的配置,这对于开发人员来说是一个福音,通过引入各种 Spring Boot Starter 包能够疾速搭建出一个我的项目的脚手架举荐分布式架构源码。 目前提供的 Spring Boot Starter 包有: spring-boot-starter-web:疾速构建基于 Spring MVC 的 Web 我的项目,应用 Tomcat 做默认嵌入式容器。spring-boot-starter-data-redis:操作 Redis。spring-boot-starter-data-mongodb:操作 Mongodb。spring-boot-starter-data-jpa:操作 Mysql。spring-boot-starter-activemq:操作 Activemq。…… 主动配置十分不便,当咱们要操作 Mongodb 的时候,只须要引入 spring-boot-starter-data-mongodb 的依赖,而后配置 Mongodb 的链接信息 spring.data.mongodb.uri=mongodb://localhost/test 就能够应用 MongoTemplate 来操作数据,MongoTemplate 的初始化工作全副交给 Starter 来实现。 主动配置麻烦的是当呈现谬误时,排查问题的难度回升了。主动配置的逻辑都在 Spring Boot Starter 中,要想疾速定位问题,就必须得理解 Spring Boot Starter 的外部原理。接下来咱们本人入手来实现一个 Spring Boot Starter。 Spring Boot Starter我的项目创立创立一个我的项目 spring-boot-starter-demo,pom.xml 配置代码如下所示。 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency></dependencies>创立一个配置类,用于在属性文件中配置值,相当于 spring.data.mongo 这种模式,代码如下所示。 import org.springframework.boot.context.properties.ConfigurationProperties;import lombok.Data;@Data@ConfigurationProperties("spring.user")public class UserPorperties { private String name;}再定义一个 Client,相当于 MongoTemplate,外面定一个办法,用于获取配置中的值,代码如下所示。 ...

September 15, 2021 · 2 min · jiezi

关于spring-cloud:6java-Spring-Cloud企业快速开发架构之SpringCloudSpring-Boot项目详细搭建步骤

在 Spring Tools 4 for Eclipse 中顺次抉择 File->New->Maven Project,而后在呈现的界面中按图所示减少相干信息。 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version></parent><dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency></dependencies> 编写启动类,代码如下所示。 @SpringBootApplicationpublic class App { public static void main(String[] args) { SpringApplication.run(App.class, args); }}启动类应用了 @SpringBootApplication 注解,这个注解示意该类是一个 Spring Boot 利用。间接运行 App 类即可启动,启动胜利后在控制台输入信息,默认端口是 8080,如图所示。举荐分布式架构源码 能够看到,咱们只在 pom.xml 中引入了一个 Web 的 Starter,而后创立一个一般的 Java 类,一个 Main 办法就能够启动一个 Web 我的项目。 与之前的应用形式相比,这种形式简略很多。以前须要配置各种 Spring 相干的包,还须要配置 web.xml 文件,还须要将我的项目放入 Tomcat 中去执行,搭建我的项目的过程还特地容易出错,会呈现各种 jar 包抵触。有了 Spring Boot 后这些问题都解决了。 咱们之所以可能通过一个 Main 办法启动一个 Web 服务,是因为 Sprig Boot 中内嵌了 Tomcat,而后通过内嵌的 Tomcat 来提供服务。当然,咱们也能够应用别的容器来替换 Tomcat,比方 Undertow 或 Jetty。 ...

September 15, 2021 · 7 min · jiezi

关于spring-cloud:5java-Spring-Cloud-企业快速开发架构之SpringCloudSpring-Boot简介

Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目标是简化新 Spring 利用的初始搭建以及开发过程。该框架应用了特定的形式进行配置,从而使开发人员不再须要定义样板化的配置。 Spring Boot 致力于在蓬勃发展的疾速利用开发畛域(rapid application development)成为领导者。 在应用 Spring Boot 之前,咱们须要搭建一个我的项目框架并配置各种第三方库的依赖,还须要在 XML 中配置很多内容。 Spring Boot 齐全突破了咱们之前的应用习惯,一分钟就能够创立一个 Web 开发的我的项目;通过 Starter 的形式轻松集成第三方的框架;去掉了 XML 的配置,全副用注解代替。 Spring Boot Starter 是用来简化 jar 包依赖的,集成一个框架只须要引入一个 Starter,而后在属性文件中配置一些值,整个集成的过程就完结了。 不得不说,Spring Boot 在外部做了很多的解决,让开发人员应用起来更加简略了。 上面笔者总结了一些应用 Spring Boot 开发的长处: 基于 Spring 开发 Web 利用更加容易。采纳基于注解形式的配置,防止了编写大量反复的 XML 配置。能够轻松集成 Spring 家族的其余框架,比方 Spring JDBC、Spring Data 等。提供嵌入式服务器,令开发和部署都变得十分不便。  举荐分布式架构源码

September 15, 2021 · 1 min · jiezi

关于spring-cloud:4java-Spring-Cloud企业快速开发架构之SpringCloud-开发环境的准备和Lombok安装步骤

开发环境的筹备次要波及三个方面:JDK、Maven、Spring Tools 4 for Eclipse。 1.JDKJDK 的版本用 1.8 即可,环境变量大家自行去配置。配置好环境变量,在命令行中输出“java -version”可能显示出版本信息即可,如图所示。2.MavenMaven 是用于我的项目构建的,教程所用的版本是 3.6。装置完之后也须要配置环境变量,配置好后同样须要在命令行中输出“mvn -version”进行检测,如图所示。3.Spring Tools 4 for Eclipse大家能够抉择本人相熟的开发工具,不肯定要用 Spring Tools 4 for Eclipse,Spring Tools 4 for Eclipse 下载的地址:http://spring.io/tools。Lombok 装置步骤下载实现后,还须要装置 Lombok 插件,本教程的示例代码会采纳 Lombok 来简化 get,set 办法。 1)官网下载 lombok.jar(https://projectlombok.org/ind...)。 2)间接运行 jar(java -jar lombok.jar 包的绝对路径),如图 3 所示。而后会显示一个界面,如图所示。点击 Install/Update 按钮即可装置胜利,重启 IDE 即可应用。 举荐分布式架构源码

September 15, 2021 · 1 min · jiezi

关于spring-cloud:苦逼的程序员-520-浪漫表白方式

1、按 ctrl+f 而后输出 9996699999966699999966996666996669999666996666999969999999969999999969966669966996699669966669999669999999999999996699666699699666699699666699996666999999999999666669999666996666996996666999966666699999999666666669966669966669969966669999666666669999666666666699666669966996699666699996666666669966666666666996666669999666699999962、除了"好呀",其余都是不好选 3、你的一句今天见,偷走了我整晚的睡眠 4、意见统一的时候听我的,不同的时候听女朋友的 5、山无陵, 江水为竭, 冬雷震震, 夏雨雪, 天地合, 乃敢与君绝! 6、春风十里不如你 7、直到死之前,每天爱你多一点 8、没有你,我就没方法对世界说"你好" 9、如果你觉的我是一个乏味的人,我想那是最好不过的了 10、当然,有时候也有意外状况 详情看我个人简介

September 14, 2021 · 1 min · jiezi

关于spring-cloud:J2EE分布式微服务云开发架构-Spring-CloudMybatisElementUI-前后端分离

鸿鹄云架构【系统管理平台】是一个大型企业、分布式、微服务、云架构的JavaEE体系疾速研发平台,基于模块化、微服务化、原子化、热部署的设计思维,应用成熟当先的无商业限度的支流开源技术(Spring Cloud+Spring Boot+Mybatis+Oauth2+微服务设计思维)构建。 采纳服务化的组件开发模式,可实现简单的业务性能。应用Maven进行我的项目的构建治理,采纳Jenkins进行继续集成,次要定位于大型分布式企业零碎或大型分布式互联网产品的架构。应用以后最风行最先进的开源技术实现服务组件化及治理,真正为企业打造分布式、微服务、云架构平台。 【平台安全性】平台严格遵循Web平安标准,应用前后端双重验证,对立用户认证及明码安全策略,规范性能权限、数据权限过滤。应用防SQL脚本注入、跨站点脚本编制(XSS)、伪造申请(CSRF)攻打等常见的攻打伎俩。 业务服务与业务服务提供对外规范Restful接口标准,对内Feign的调用模式,实现分布式集群部署,业务与业务之间齐全解耦,应用Zipkin做服务与服务之间的链路追踪,ES做日志数据收集,真正为企业打造分布式、微服务、云架构平台。原码起源

September 14, 2021 · 1 min · jiezi

关于spring-cloud:第六篇云服务器之Spring-Cloud直播商城-b2b2c电子商务技术总结

云服务器云服务器(Elastic Compute Service, ECS)是一种简略高效、安全可靠、解决能力可弹性伸缩的计算服务。 云服务器治理形式比物理服务器更简略高效,咱们无需提前购买低廉的硬件,即可迅速创立或删除云服务器,云服务器费用个别在几十到几百不等,能够依据咱们的需要配置。 目前市场上的云服务器很多,这里次要介绍以下几家: :流动折扣力度很大(1核2G,72.60/年)。 :腾讯云目前流动多一些,性价比也高。 留神:很多云服务器给新用户提供的优惠力度是最大,基本上都是 1~2 折,倡议新注册的用户购买。阿里云新用户购买具体信息,能够点击上面的图片。阿里流动, 不分新老用户,能够领红包参加满减流动,续费也有专门的优惠券,续费优惠券。 留神:阿里云 突发性能型的服务器真的只能本人学习用,如果要用对外提供服务要谨慎抉择,因为它性能瓶颈限度很大,不过价格便宜就是了。当然,你也能够间接到 抉择更多配置及其他地区的云服务器:红框为无需备案地区:腾讯云腾讯云秒杀流动已开始,以下几款性价比十分高,有几款是须要抢购的,大家看好工夫根本能拿到。 1、 1核2G 74/年、219元/3年( 原价:1506/年),能够用来学习,Linux 常识对技术人员的成才十分重要。2、 2核4G 3M 带宽 1 年 328( 原价:3198元)。3、如果须要购买海内服务器(国内要备案),能够点击: https://curl.qcloud.com/5C1FtZ3S。每个工夫点都有不同的配置跟价格,具体信息,能够点击上面的图片( https://curl.qcloud.com/JsztA7Wh)。国内服务器如果要做网站之类的还得备案,中国香港地区和海内的是不须要备案的,能够点击: https://curl.qcloud.com/5C1FtZ3S 链接,抉择不同区域购买,以下红框局部不须要备案。腾讯云服务器应用本章节以腾讯云服务器为例。 1、首先点击下图购买(更多服务器的配置信息见下文):2、登陆腾讯云控制台,查看已购买的服务器:3、在应用腾讯云服务器前,咱们须要先创立一个 SSH 密钥,点击左侧的 SSH 密钥 (应用密钥登录比明码更平安):输出密钥名称,而后点击确定,就会主动生成一个密钥,密钥会主动下载到本地,请保留好下载的密钥,密钥文件名就是你输出的密钥名称。 4、接着咱们勾选曾经创立的密钥,点击 绑定/解绑实例 按钮,弹窗中会呈现咱们的 ECS 服务器,将其绑定到这个密钥即可:5、返回实例列表,点击实例右侧的 登录 按钮,弹窗中点击立刻登录,这是会弹出一个新的浏览器窗口,咱们抉择密钥登录,密钥文件就是在第三个步骤创立的:当然你能够抉择第三方客户端登录(如:SecureCRT),用户名为 ubuntu,其余零碎预计略有不同,而后导入对应的 key 即可。

September 13, 2021 · 1 min · jiezi

关于spring-cloud:第三篇CentOS-Docker-安装之Spring-Cloud直播商城-b2b2c电子商务技术总结

CentOS Docker 装置Docker 反对以下的 64 位 CentOS 版本: CentOS 7CentOS 8更高版本...应用官网装置脚本主动装置装置命令如下: > curl -fsSL | bash -s docker --mirror Aliyun也能够应用国内 daocloud 一键装置命令: curl -sSL | sh卸载旧版本较旧的 Docker 版本称为 docker 或 docker-engine 。如果已装置这些程序,请卸载它们以及相干的依赖项。 $ sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine装置 Docker Engine-Community应用 Docker 仓库进行装置在新主机上首次装置 Docker Engine-Community 之前,须要设置 Docker 仓库。之后,您能够从仓库装置和更新 Docker。 设置仓库 装置所需的软件包。yum-utils 提供了 yum-config-manager ,并且 device mapper 存储驱动程序须要 device-mapper-persistent-data 和 lvm2。 ...

September 13, 2021 · 1 min · jiezi

关于spring-cloud:第四篇Git-工作区暂存区和版本库之Spring-Cloud直播商城-b2b2c电子商务技术总结

基本概念咱们先来了解下 Git 工作区、暂存区和版本库概念: 工作区:就是你在电脑里能看到的目录。暂存区:英文叫 stage 或 index。个别寄存在 .git 目录下的 index 文件(.git/index)中,所以咱们把暂存区有时也叫作索引(index)。版本库:工作区有一个暗藏目录 .git,这个不算工作区,而是 Git 的版本库。上面这个图展现了工作区、版本库中的暂存区和版本库之间的关系:图中左侧为工作区,右侧为版本库。在版本库中标记为 "index" 的区域是暂存区(stage/index),标记为 "master" 的是 master 分支所代表的目录树。 图中咱们能够看出此时 "HEAD" 理论是指向 master 分支的一个"游标"。所以图示的命令中呈现 HEAD 的中央能够用 master 来替换。 图中的 objects 标识的区域为 Git 的对象库,理论位于 ".git/objects" 目录下,外面蕴含了创立的各种对象及内容。 当对工作区批改(或新增)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区批改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,然而工作区不受影响。 当执行 git rm --cached <file> 命令时,会间接从暂存区删除文件,工作区则不做出扭转。 当执行 git checkout . 或者 git checkout -- <file> 命令时,会用暂存区全副或指定的文件替换工作区的文件。这个操作很危险,会革除工作区中未增加到暂存区中的改变。 当执行 git checkout HEAD . 或者 git checkout HEAD <file> 命令时,会用 HEAD 指向的 master 分支中的全副或者局部文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为岂但会革除工作区中未提交的改变,也会革除暂存区中未提交的改变。 ...

September 8, 2021 · 1 min · jiezi

关于spring-cloud:第十六篇-Maven-自动化部署之Spring-Cloud直播商城-b2b2c电子商务技术总结

Maven 自动化部署我的项目开发过程中,部署的过程蕴含需如下步骤: 将所的我的项目代码提交到 SVN 或者代码库中并打上标签。从 SVN 上下载残缺的源代码。构建利用。存储构建输入的 WAR 或者 EAR 文件到一个罕用的网络地位下。从网络上获取文件并且部署文件到生产站点上。更新文档并且更新利用的版本号。问题形容通常状况下下面的提到开发过程中会波及到多个团队。一个团队可能负责提交代码,另一个团队负责构建等等。很有可能因为波及的人为操作和多团队环境的起因,任何一个步骤都可能出错。比方,较旧的版本没有在网络机器上更新,而后部署团队又重新部署了较早的构建版本。 解决方案通过联合以下计划来实现自动化部署: 应用 Maven 构建和公布我的项目应用 SubVersion, 源码仓库来治理源代码应用近程仓库管理软件(Jfrog或者Nexus) 来治理我的项目二进制文件。批改我的项目的 pom.xml咱们将会应用 Maven 公布的插件来创立一个自动化公布过程。 例如,bus-core-api 我的项目的 pom.xml 文件代码如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>bus-core-api</groupId> <artifactId>bus-core-api</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <scm> <url>http://www.svn.com</url> <connection>scm:svn:http://localhost:8080/svn/jrepo/trunk/ Framework</connection> <developerConnection>scm:svn:${username}/${password}@localhost:8080: common_core_api:1101:code</developerConnection> </scm> <distributionManagement> <repository> <id>Core-API-Java-Release</id> <name>Release repository</name> <url>http://localhost:8081/nexus/content/repositories/ Core-Api-Release</url> </repository> </distributionManagement> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-release-plugin</artifactId> <version>2.0-beta-9</version> <configuration> <useReleaseProfile>false</useReleaseProfile> <goals>deploy</goals> <scmCommentPrefix>[bus-core-api-release-checkin]-< /scmCommentPrefix> </configuration> </plugin> </plugins> </build></project>在 pom.xml 文件中,咱们罕用到的一些重要元素节点如下表所示:Maven Release 插件Maven 应用 maven-release-plugin 插件来实现以下工作。mvn release:clean清理工作空间,保障最新的公布过程胜利进行。mvn release:rollback在上次公布过程不胜利的状况下,回滚批改的工作空间代码和配置保障公布过程胜利进行。 ...

September 8, 2021 · 1 min · jiezi

关于spring-cloud:第十五篇-Maven-依赖管理之Spring-Cloud直播商城-b2b2c电子商务技术总结

Maven 依赖治理Maven 一个外围的个性就是依赖治理。当咱们解决多模块的我的项目(蕴含成千盈百个模块或者子项目),模块间的依赖关系就变得非常复杂,治理也变得很艰难。针对此种情景,Maven 提供了一种高度管制的办法。 可传递性依赖发现一种相当常见的状况,比如说 A 依赖于其余库 B。如果,另外一个我的项目 C 想要应用 A ,那么 C 我的项目也须要应用库 B。 Maven 能够防止去搜寻所有所需库的需要。Maven 通过读取我的项目文件(pom.xml),找出它们我的项目之间的依赖关系。 咱们须要做的只是在每个我的项目的 pom 中定义好间接的依赖关系。其余的事件 Maven 会帮咱们搞定。 通过可传递性的依赖,所有被蕴含的库的图形会疾速的增长。当有反复库时,可能呈现的情景将会持续上升。Maven 提供一些性能来管制可传递的依赖的水平。依赖范畴传递依赖发现能够通过应用如下的依赖范畴来失去限度:依赖治理通常状况下,在一个共通的我的项目下,有一系列的我的项目。在这种状况下,咱们能够创立一个公共依赖的 pom 文件,该 pom 蕴含所有的公共的依赖关系,咱们称其为其余子项目 pom 的 pom 父。 接下来的一个例子能够帮忙你更好的了解这个概念。 接下来是下面依赖图的详情阐明: App-UI-WAR 依赖于 App-Core-lib 和 App-Data-lib。 Root 是 App-Core-lib 和 App-Data-lib 的父我的项目。 Root 在它的依赖局部定义了 Lib1、lib2 和 Lib3 作为依赖。 App-UI-WAR 的 pom.xml 文件代码如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.companyname.groupname</groupId> <artifactId>App-UI-WAR</artifactId> <version>1.0</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>com.companyname.groupname</groupId> <artifactId>App-Core-lib</artifactId> <version>1.0</version> </dependency> </dependencies> <dependencies> <dependency> <groupId>com.companyname.groupname</groupId> <artifactId>App-Data-lib</artifactId> <version>1.0</version> </dependency> </dependencies> </project>App-Core-lib 的 pom.xml 文件代码如下: ...

September 8, 2021 · 1 min · jiezi

关于spring-cloud:第十四篇-Maven-自动化构建之Spring-Cloud直播商城-b2b2c电子商务技术总结

Maven 自动化构建自动化构建定义了这样一种场景: 在一个我的项目胜利构建实现后,其相干的依赖工程即开始构建,这样能够保障其依赖我的项目的稳固。 比方一个团队正在开发一个我的项目 bus-core-api, 并且有其余两个我的项目 app-web-ui 和 app-desktop-ui 依赖于这个我的项目。 app-web-ui 我的项目应用的是 bus-core-api 我的项目的 1.0 快照: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>app-web-ui</groupId> <artifactId>app-web-ui</artifactId> <version>1.0</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>bus-core-api</groupId> <artifactId>bus-core-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies></project>app-desktop-ui 我的项目应用的是 bus-core-api 我的项目的 1.0 快照: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>app-desktop-ui</groupId> <artifactId>app-desktop-ui</artifactId> <version>1.0</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>bus-core-api</groupId> <artifactId>bus-core-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies></project>bus-core-api 我的项目: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>bus-core-api</groupId> <artifactId>bus-core-api</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> </project>当初 app-web-ui 和 app-desktop-ui 我的项目的团队要求不论 bus-core-api 我的项目何时变动,他们的构建过程都该当能够启动。 ...

September 7, 2021 · 2 min · jiezi

关于spring-cloud:第五篇Maven-构建配置文件之Spring-Cloud直播商城-b2b2c电子商务技术总结

Maven 构建配置文件构建配置文件是一系列的配置项的值,能够用来设置或者笼罩 Maven 构建默认值。 应用构建配置文件,你能够为不同的环境,比如说生产环境(Production)和开发(Development)环境,定制构建形式。 配置文件在 pom.xml 文件中应用 activeProfiles 或者 profiles 元素指定,并且能够通过各种形式触发。配置文件在构建时批改 POM,并且用来给参数设定不同的指标环境(比如说,开发(Development)、测试(Testing)和生产环境(Production)中数据库服务器的地址)。 构建配置文件的类型构建配置文件大体上有三种类型:配置文件激活Maven的构建配置文件能够通过多种形式激活。 应用命令控制台输出显式激活。通过 maven 设置。基于环境变量(用户或者零碎变量)。操作系统设置(比如说,Windows系列)。文件的存在或者缺失。配置文件激活实例假设我的项目构造如下:其中在src/main/resources文件夹下有三个用于测试文件:留神:这三个配置文件并不是代表构建配置文件的性能,而是用于本次测试的目标;比方,我指定了构建配置文件为 prod 时,我的项目就应用 env.prod.properties文件。 留神:上面的例子依然是应用 AntRun 插件,因为此插件能绑定 Maven 生命周期阶段,并通过 Ant 的标签不必编写一点代码即可输入信息、复制文件等,经此而已。其余的与本次构建配置文件无关。 1、配置文件激活profile 能够让咱们定义一系列的配置信息,而后指定其激活条件。这样咱们就能够定义多个 profile,而后每个 profile 对应不同的激活条件和配置信息,从而达到不同环境应用不同配置信息的成果。 以下实例,咱们将 maven-antrun-plugin:run 指标增加到测试阶段中。这样咱们能够在不同的 profile 中输入文本信息。咱们将应用 pom.xml 来定义不同的 profile,并在命令控制台中应用 maven 命令激活 profile。 pom.xml 文件如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jsoft.test</groupId> <artifactId>testproject</artifactId> <packaging>jar</packaging> <version>0.1-SNAPSHOT</version> <name>testproject</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <profiles> <profile> <id>test</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.8</version> <executions> <execution> <phase>test</phase> <goals> <goal>run</goal> </goals> <configuration> <tasks> <echo>Using env.test.properties</echo> <copy file="src/main/resources/env.test.properties" tofile="${project.build.outputDirectory}/env.properties" overwrite="true"/> </tasks> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> <profile> <id>normal</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.8</version> <executions> <execution> <phase>test</phase> <goals> <goal>run</goal> </goals> <configuration> <tasks> <echo>Using env.properties</echo> <copy file="src/main/resources/env.properties" tofile="${project.build.outputDirectory}/env.properties" overwrite="true"/> </tasks> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> <profile> <id>prod</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.8</version> <executions> <execution> <phase>test</phase> <goals> <goal>run</goal> </goals> <configuration> <tasks> <echo>Using env.prod.properties</echo> <copy file="src/main/resources/env.prod.properties" tofile="${project.build.outputDirectory}/env.properties" overwrite="true"/> </tasks> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles></project>留神:构建配置文件采纳的是 <profiles> 节点。 ...

September 7, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版24测试Spring-Cloud-LoadBalancer

本系列代码地址:https://github.com/HashZhang/...通过单元测试,咱们也能够理解下个别咱们实现 spring cloud 自定义的根底组件,怎么去单元测试。 这里的单元测试次要测试三个场景: 只返回同一个 zone 下的实例,其余 zone 的不会返回对于多个申请,每个申请返回的与上次的实例不同。对于多线程的每个申请,如果重试,返回的都是不同的实例同时,咱们也须要针对同步和异步两个配置,别离进行测试,同步和异步两种配置测试逻辑是一样的,只是测试的 Bean 不一样: 同步环境是 DiscoveryClient,异步环境是 ReactiveDiscoveryClient同步环境负载均衡器是 LoadBalancer,异步环境负载均衡器是 ReactiveLoadBalancer同步测试代码请参考:LoadBalancerTest.java,异步测试代码请参考:LoadBalancerTest.java 咱们这里应用同步测试代码作为例子展现: //SpringExtension也蕴含了MockitoJUnitRunner,所以 @Mock 等注解也失效了@ExtendWith(SpringExtension.class)@SpringBootTest(properties = {LoadBalancerEurekaAutoConfiguration.LOADBALANCER_ZONE + "=zone1"})public class LoadBalancerTest { @EnableAutoConfiguration @Configuration public static class App { @Bean public DiscoveryClient myDiscoveryClient() { ServiceInstance zone1Instance1 = Mockito.spy(ServiceInstance.class); ServiceInstance zone1Instance2 = Mockito.spy(ServiceInstance.class); ServiceInstance zone2Instance3 = Mockito.spy(ServiceInstance.class); Map<String, String> zone1 = Map.ofEntries( Map.entry("zone", "zone1") ); Map<String, String> zone2 = Map.ofEntries( Map.entry("zone", "zone2") ); when(zone1Instance1.getMetadata()).thenReturn(zone1); when(zone1Instance1.getInstanceId()).thenReturn("instance1"); when(zone1Instance2.getMetadata()).thenReturn(zone1); when(zone1Instance2.getInstanceId()).thenReturn("instance2"); when(zone2Instance3.getMetadata()).thenReturn(zone2); when(zone2Instance3.getInstanceId()).thenReturn("instance3"); DiscoveryClient spy = Mockito.spy(DiscoveryClient.class); Mockito.when(spy.getInstances("testService")) .thenReturn(List.of(zone1Instance1, zone1Instance2, zone2Instance3)); return spy; } } @SpyBean private LoadBalancerClientFactory loadBalancerClientFactory; @SpyBean private Tracer tracer; /** * 只返回同一个 zone 下的实例 */ @Test public void testFilteredByZone() { ReactiveLoadBalancer<ServiceInstance> testService = loadBalancerClientFactory.getInstance("testService"); for (int i = 0; i < 100; i++) { ServiceInstance server = Mono.from(testService.choose()).block().getServer(); //必须处于和以后实例同一个zone下 Assertions.assertEquals(server.getMetadata().get("zone"), "zone1"); } } /** * 返回不同的实例 */ @Test public void testReturnNext() { ReactiveLoadBalancer<ServiceInstance> testService = loadBalancerClientFactory.getInstance("testService"); Span span = tracer.nextSpan(); for (int i = 0; i < 100; i++) { try (Tracer.SpanInScope cleared = tracer.withSpanInScope(span)) { ServiceInstance server1 = Mono.from(testService.choose()).block().getServer(); ServiceInstance server2 = Mono.from(testService.choose()).block().getServer(); //每次抉择的是不同实例 Assertions.assertNotEquals(server1.getInstanceId(), server2.getInstanceId()); } } } /** * 跨线程,默认状况下是可能返回同一实例的,在咱们的实现下,放弃 * span 则会返回下一个实例,这样保障多线程环境同一个 request 重试会返回下一实例 * * @throws Exception */ @Test public void testSameSpanReturnNext() throws Exception { Span span = tracer.nextSpan(); for (int i = 0; i < 100; i++) { try (Tracer.SpanInScope cleared = tracer.withSpanInScope(span)) { ReactiveLoadBalancer<ServiceInstance> testService = loadBalancerClientFactory.getInstance("testService"); ServiceInstance server1 = Mono.from(testService.choose()).block().getServer(); AtomicReference<ServiceInstance> server2 = new AtomicReference<>(); Thread thread = new Thread(() -> { try (Tracer.SpanInScope cleared2 = tracer.withSpanInScope(span)) { server2.set(Mono.from(testService.choose()).block().getServer()); } }); thread.start(); thread.join(); System.out.println(i); Assertions.assertNotEquals(server1.getInstanceId(), server2.get().getInstanceId()); } } }}运行测试,测试通过。 ...

August 29, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版23订制Spring-Cloud-LoadBalancer

本系列代码地址:https://github.com/HashZhang/...咱们应用 Spring Cloud 官网举荐的 Spring Cloud LoadBalancer 作为咱们的客户端负载均衡器。上一节咱们理解了 Spring Cloud LoadBalancer 的构造,接下来咱们来说一下咱们在应用 Spring Cloud LoadBalancer 要实现的性能: 咱们要实现不同集群之间不相互调用,通过实例的metamap中的zone配置,来辨别不同集群的实例。只有实例的metamap中的zone配置一样的实例能力相互调用。这个通过实现自定义的 ServiceInstanceListSupplier 即可实现负载平衡的轮询算法,须要申请与申请之间隔离,不能共用同一个 position 导致某个申请失败之后的重试还是原来失败的实例。上一节看到的默认的 RoundRobinLoadBalancer 是所有线程共用同一个原子变量 position 每次申请原子加 1。在这种状况下会有问题:假如有微服务 A 有两个实例:实例 1 和实例 2。申请 A 达到时,RoundRobinLoadBalancer 返回实例 1,这时有申请 B 达到,RoundRobinLoadBalancer 返回实例 2。而后如果申请 A 失败重试,RoundRobinLoadBalancer 又返回了实例 1。这不是咱们冀望看到的。针对这两个性能,咱们别离编写本人的实现。 Spring Cloud LoadBalancer 中的 zone 配置Spring Cloud LoadBalancer 定义了 LoadBalancerZoneConfig: public class LoadBalancerZoneConfig { //标识以后负载均衡器处于哪一个 zone private String zone; public LoadBalancerZoneConfig(String zone) { this.zone = zone; } public String getZone() { return zone; } public void setZone(String zone) { this.zone = zone; }}如果没有引入 Eureka 相干依赖,则这个 zone 通过 spring.cloud.loadbalancer.zone 配置:LoadBalancerAutoConfiguration ...

August 28, 2021 · 4 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版22Spring-Cloud-LoadBalancer核心源码

本系列代码地址:https://github.com/HashZhang/...通过上一节的详细分析,咱们晓得能够通过 LoadBalancerClientFactory 晓得默认配置类为 LoadBalancerClientConfiguration. 并且获取微服务名称能够通过 environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); [LoadBalancerClientFactory]() public static final String NAMESPACE = "loadbalancer";public static final String PROPERTY_NAME = NAMESPACE + ".client.name";public LoadBalancerClientFactory() { super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);}查看配置类 LoadBalancerClientConfiguration,咱们能够发现这个类次要定义两种 Bean,别离是 ReactorLoadBalancer<ServiceInstance> 和 ServiceInstanceListSupplier。 ReactorLoadBalancer 是负载均衡器,次要提供依据服务名称获取服务实例列表并从从中抉择的性能。 [ReactorLoadBalancer]() Mono<Response<T>> choose(Request request);在默认配置中的实现是: [LoadBalancerClientConfiguration]() @Bean@ConditionalOnMissingBeanpublic ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer( Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { //获取微服务名称 String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); //创立 RoundRobinLoadBalancer //留神这里注入的是 LazyProvider,这次要因为在注册这个 Bean 的时候相干的 Bean 可能还没有被加载注册,利用 LazyProvider 而不是间接注入所需的 Bean 避免报找不到 Bean 注入的谬误。 return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);}能够看出,默认配置的 ReactorLoadBalancer 实现是 RoundRobinLoadBalancer。这个负载均衡器实现很简略,有一个原子类型的 AtomicInteger position,从 ServiceInstanceListSupplier 中读取所有的服务实例列表,而后对于 position 原子加1,对列表大小取模,返回列表中这个地位的服务实例 ServiceInstance。 ...

August 27, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版21Spring-Cloud-LoadBalancer简介

本系列代码地址:https://github.com/HashZhang/...咱们应用 Spring Cloud 官网举荐的 Spring Cloud LoadBalancer 作为咱们的客户端负载均衡器。 Spring Cloud LoadBalancer背景Spring Cloud LoadBalancer是一个客户端负载均衡器,相似于Ribbon,然而因为Ribbon曾经进入保护模式,并且Ribbon 2并不与Ribbon 1互相兼容,所以Spring Cloud全家桶在Spring Cloud Commons我的项目中,增加了Spring cloud Loadbalancer作为新的负载均衡器,并且做了向前兼容,就算你的我的项目中持续用 Spring Cloud Netflix 套装(包含Ribbon,Eureka,Zuul,Hystrix等等)让你的我的项目中有这些依赖,你也能够通过简略的配置,把ribbon替换成Spring Cloud LoadBalancer。 负载均衡器在哪里应用?Spring Cloud 中外部微服务调用默认是 http 申请,次要通过上面三种 API: RestTemplate:同步 http APIWebClient:异步响应式 http API三方客户端封装,例如 openfeign如果我的项目中退出了 spring-cloud-loadbalancer 的依赖并且配置启用了,那么会主动在相干的 Bean 中退出负载均衡器的个性。 对于 RestTemplate,会主动对所有 @LoadBalanced 注解润饰的 RestTemplate Bean 减少 Interceptor 从而加上了负载均衡器的个性。对于 WebClient,会主动创立 ReactorLoadBalancerExchangeFilterFunction,咱们能够通过退出ReactorLoadBalancerExchangeFilterFunction会退出负载均衡器的个性。对于三方客户端,个别不须要咱们额定配置什么。这些应用的示例,会在咱们系列降级完最初的测试局部看到。 Spring Cloud LoadBalancer 构造简介系列之前的文章咱们提到了 NamedContextFactory,Spring Cloud LoadBalancer 这里也是应用了这个机制实现了不同微服务应用不同的 Spring Cloud LoadBalancer 配置。相干外围实现是 @LoadBalancerClient 和 @LoadBalancerClients 这两个注解,以及 NamedContextFactory.Specification 的实现 LoadBalancerClientSpecification,NamedContextFactory 的实现 LoadBalancerClientFactory。如下图所示: ...

August 26, 2021 · 1 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版20-启动一个-Eureka-Server-集群

本系列代码地址:https://github.com/HashZhang/... 咱们的业务集群构造是这样的: 不同 Region,应用不同的 Eureka 集群治理,不同 Region 之间不相互拜访。同一 Region 内,可能有不同的业务集群,不同业务集群之间也不相互拜访,共用同一套业务集群。同一业务集群内能够随便拜访,同时同一业务集群会做跨可用区的容灾。在咱们这里的形象中,zone 代表不同集群,而不是理论的不同可用区。 在这里,咱们提供一个 Eureka Server 的集群模板,供大家参考。 首先,我的项目依赖是: <dependencies> <dependency> <groupId>com.github.hashjang</groupId> <artifactId>spring-cloud-iiford-spring-cloud-webmvc</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency></dependencies>其实就是蕴含之前咱们定义的所有同步微服务的依赖,以及 eureka-server 的相干依赖。 编写启动类,其实外围就是增加注解 @EnableEurekaServer package com.github.hashjang.spring.cloud.iiford.eureka.server;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication@EnableEurekaServerpublic class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); }}咱们筹备启动一个两个 Eureka Server 实例的集群,首先编写两个实例公共的配置,放入 application.yml: spring: application: name: eureka-servereureka: server: #被动查看服务实例是否生效的工作执行距离,默认是 60s eviction-interval-timer-in-ms: 1000 #这个配置在两个中央被应用: #如果启用用了自我爱护,则会 renewal-threshold-update-interval-ms 指定的工夫内,收到的心跳申请个数是否小于实例个数乘以这个 renewal-percent-threshold #定时工作查看过期实例,每次最多过期 1 - renewal-percent-threshold 这么多比例的实例 renewal-percent-threshold: 0.85 #留神,最好所有的客户端实例配置的心跳工夫相干的配置,是雷同的。这样应用自我爱护的个性最精确。 #敞开自我爱护 #咱们这里不应用自我爱护,因为: #自我爱护次要针对集群中网络呈现问题,导致有很多实例无奈发送心跳导致很多实例状态异样,然而理论实例还在失常工作的状况,不要让这些实例不参加负载平衡 #启用自我爱护的状况下,就会进行对于实例的过期 #然而,如果呈现这种状况,其实也代表很多实例无奈读取注册核心了。 #并且还有一种状况就是,Eureka 重启。尽管不常见,然而对于镜像中其余的组件更新咱们还是很频繁的 #我偏向于从客户端对于实例缓存机制来解决这个问题,如果返回实例列表为空,则应用上次的实例列表进行负载平衡,这样既能解决 Eureka 重启的状况,又能解决一些 Eureka 网络隔离的状况 #自我保护模式基于每分钟须要收到 renew (实例心跳)申请个数,如果启用了自我保护模式,只有上一分钟接管到的 renew 个数,大于这个值,实例过期才会被登记 enable-self-preservation: false # 增量实例队列实例过期工夫,默认 3 分钟 retention-time-in-m-s-in-delta-queue: 180000 # 增量实例队列过期工作距离,默认 30s delta-retention-timer-interval-in-ms: 30000 # 响应缓存中有两个次要元素,一个是 readOnlyCacheMap,另一个是 readWriteCacheMap # 是否应用 readOnlyCacheMap,默认为 true # 如果为是,则从 readOnlyCacheMap 读取,否则间接读取 readWriteCacheMap use-readonly-response-cahce: true # 初始 readWriteCacheMap 大小,默认 1000 initial-capacity-of-response-cache: 1000 # LoadingCache 缓存过期工夫,默认 180s response-cache-auto-expiration-in-seconds: 9 # 定时从 LoadingCache 同步到只读缓存的间隔时间,默认为 30s response-cache-update-interval-ms: 3000 client: service-url: # 默认eureka集群,这里必须是defaultZone,不能用-替换大写,与其余的配置不一样,因为切实EurekaClientConfigBean外面写死的 defaultZone: 'http://127.0.0.1:8211/eureka/,http://127.0.0.1:8212/eureka/' # 是否从 eureka 下面拉取实例, eureka server 不调用其余微服务,所以没必要拉取 fetch-registry: false # 是否将本人注册到 eureka 下面,eureka server 不参加负载平衡,所以没必要注册 register-with-eureka: falseserver: undertow: # 以下的配置会影响buffer,这些buffer会用于服务器连贯的IO操作 # 如果每次须要 ByteBuffer 的时候都去申请,对于堆内存的 ByteBuffer 须要走 JVM 内存调配流程(TLAB -> 堆),对于间接内存则须要走零碎调用,这样效率是很低下的。 # 所以,个别都会引入内存池。在这里就是 `BufferPool`。 # 目前,UnderTow 中只有一种 `DefaultByteBufferPool`,其余的实现目前没有用。 # 这个 DefaultByteBufferPool 绝对于 netty 的 ByteBufArena 来说,非常简单,相似于 JVM TLAB 的机制 # 对于 bufferSize,最好和你零碎的 TCP Socket Buffer 配置一样 # `/proc/sys/net/ipv4/tcp_rmem` (对于读取) # `/proc/sys/net/ipv4/tcp_wmem` (对于写入) # 在内存大于 128 MB 时,bufferSize 为 16 KB 减去 20 字节,这 20 字节用于协定头 buffer-size: 16364 # 是否调配的间接内存(NIO间接调配的堆外内存),这里开启,所以java启动参数须要配置下间接内存大小,缩小不必要的GC # 在内存大于 128 MB 时,默认就是应用间接内存的 directBuffers: true threads: # 设置IO线程数, 它次要执行非阻塞的工作,它们会负责多个连贯, 默认设置每个CPU外围一个读线程和一个写线程 io: 4 # 阻塞工作线程池, 当执行相似servlet申请阻塞IO操作, undertow会从这个线程池中获得线程 # 它的值设置取决于零碎线程执行工作的阻塞系数,默认值是IO线程数*8 worker: 128 # http post body 大小,默认为 -1B ,即不限度 max-http-post-size: -1B # 是否在启动时创立 filter,默认为 true,不必批改 eager-filter-init: true # 限度门路参数数量,默认为 1000 max-parameters: 1000 # 限度 http header 数量,默认为 200 max-headers: 200 # 限度 http header 中 cookies 的键值对数量,默认为 200 max-cookies: 200 # 是否容许 / 与 %2F 本义。/ 是 URL 保留字,除非你的利用明确须要,否则不要开启这个本义,默认为 false allow-encoded-slash: false # 是否容许 URL 解码,默认为 true,除了 %2F 其余的都会解决 decode-url: true # url 字符编码集,默认是 utf-8 url-charset: utf-8 # 响应的 http header 是否会加上 'Connection: keep-alive',默认为 true always-set-keep-alive: true # 申请超时,默认是不超时,咱们的微服务因为可能有长时间的定时工作,所以不做服务端超时,都用客户端超时,所以咱们放弃这个默认配置 no-request-timeout: -1 # 是否在跳转的时候放弃 path,默认是敞开的,个别不必配置 preserve-path-on-forward: false options: # spring boot 没有形象的 xnio 相干配置在这里配置,对应 org.xnio.Options 类 socket: SSL_ENABLED: false # spring boot 没有形象的 undertow 相干配置在这里配置,对应 io.undertow.UndertowOptions 类 server: ALLOW_UNKNOWN_PROTOCOLS: false # access log相干配置 accesslog: # 寄存目录,默认为 logs dir: ./logs/${server.port} # 是否开启 enabled: true # 格局,各种占位符前面会具体阐明 pattern: '{ "transportProtocol":"%{TRANSPORT_PROTOCOL}", "scheme":"%{SCHEME}", "protocol":"%{PROTOCOL}", "method":"%{METHOD}", "reqHeaderUserAgent":"%{i,User-Agent}", "reqHeaderUserId":"%{i,uid}", "traceId":"%{i,X-B3-TraceId}", "spanId":"%{i,X-B3-SpanId}", "queryString": "%q", "uri": "%U", "thread": "%I", "hostPort": "%{HOST_AND_PORT}", "localIp": "%A", "localPort": "%p", "localServerName": "%v", "remoteIp": "%a", "bytesSent": "%b", "time":"%{time,yyyy-MM-dd HH:mm:ss.S}", "status":"%s", "reason":"%{RESPONSE_REASON_PHRASE}", "timeUsed":"%Dms" }' # 文件前缀,默认为 access_log prefix: access. # 文件后缀,默认为 log suffix: log # 是否另起日志文件写 access log,默认为 true # 目前只能依照日期进行 rotate,一天一个日志文件 rotate: truemanagement: endpoint: health: show-details: always endpoints: jmx: exposure: exclude: '*' web: exposure: include: '*'除了同步微服务 undertow 的配置以及 actuator 的配置,Eureka 配置中,因为 Eureka Server 感知其余实例,仅仅通过 eureka.client.service-url 这个配置读取,所以不须要 eureka server 注册到 eureka server 或者读取 eureka server 下面的实例,因而这里咱们配置不注册也不读取。而后,咱们这里依照之前剖析的,敞开了自我爱护,开启了定时过期工作,并且将相干的定时工作工夫距离都调低了不少,因为咱们的集群不是万个实例级别的,而是一千左右,所以能够调高这些工作频率。 ...

August 25, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版19Eureka的服务端设计与配置

本系列代码地址:https://github.com/HashZhang/... Eureka Server 配置是 Eureka Server 须要的一些配置,包含之前屡次提到的定时查看实例过期的配置,自我爱护相干的配置,同一 zone 内集群相干的配置和跨 zone 相干的配置。在 Spring Cloud 中,Eureka 客户端配置以 eureka.server 结尾,对应配置类为 EurekaServerConfigBean 依据上一节 Eureka 客户端剖析,咱们晓得 Eureka 客户端次要拜访如下几个接口: 注册:POST /eureka/apps/appID心跳:PUT /eureka/apps/appID/instanceID获取所有服务实例:GET /eureka/apps增量获取所有服务实例:GET /eureka/apps/deltaEureka Server 解决这些申请的外围逻辑,以及相干配置如下图所示: 实例注册后须要发送心跳证实这个实例是活着的,Eureka Server 中也有定时工作查看实例是否曾经过期。 eureka: server: #被动查看服务实例是否生效的工作执行距离,默认是 60s eviction-interval-timer-in-ms: 3000 #这个配置在两个中央被应用: #如果启用用了自我爱护,则会 renewal-threshold-update-interval-ms 指定的工夫内,收到的心跳申请个数是否小于实例个数乘以这个 renewal-percent-threshold #定时工作查看过期实例,每次最多过期 1 - renewal-percent-threshold 这么多比例的实例 renewal-percent-threshold: 0.85 服务器中有定时过期的工作,查看迟迟没有心跳的实例,并登记他们。自我爱护次要针对集群中网络呈现问题,导致有很多实例无奈发送心跳导致很多实例状态异样,然而理论实例还在失常工作的状况,不要让这些实例不参加负载平衡。 eureka: server: #留神,最好所有的客户端实例配置的心跳工夫相干的配置,是雷同的。这样应用自我爱护的个性最精确。 #敞开自我爱护 #咱们这里不应用自我爱护,因为: #自我爱护次要针对集群中网络呈现问题,导致有很多实例无奈发送心跳导致很多实例状态异样,然而理论实例还在失常工作的状况,不要让这些实例不参加负载平衡 #启用自我爱护的状况下,就会进行对于实例的过期 #然而,如果呈现这种状况,其实也代表很多实例无奈读取注册核心了。 #并且还有一种状况就是,Eureka 重启。尽管不常见,然而对于镜像中其余的组件更新咱们还是很频繁的 #我偏向于从客户端对于实例缓存机制来解决这个问题,如果返回实例列表为空,则应用上次的实例列表进行负载平衡,这样既能解决 Eureka 重启的状况,又能解决一些 Eureka 网络隔离的状况 #自我保护模式基于每分钟须要收到 renew (实例心跳)申请个数,如果启用了自我保护模式,只有上一分钟接管到的 renew 个数,大于这个值,实例过期才会被登记 enable-self-preservation: false # 每分钟须要收到 renew (实例心跳)申请个数是须要动静刷新的,这个刷新距离就是 renewal-threshold-update-interval-ms #更新流程大略是:计算以后一共有多少实例,如果大于之前冀望的实例量 * renewal-percent-threshold(或者没开启自我保护模式),则更新冀望的实例数量为以后一共有多少实例 #之后依据冀望的实例数量,计算冀望须要收到的实例心跳申请个数 = 冀望的实例数量 * (60 / expected-client-renewal-interval-seconds) * renewal-percent-threshold #公式中 60 代表一分钟,因为公式用到了 expected-client-renewal-interval-seconds,也就是实例均匀心跳距离,为了使这个公式精确,最好每个实例配置一样的心跳工夫 #默认 900000ms = 900s = 15min renewal-threshold-update-interval-ms: 900000 #下面提到的实例均匀心跳距离,或者说是冀望的心跳距离,为了使这个公式精确,最好每个实例配置一样的心跳工夫 #默认 30s expected-client-renewal-interval-seconds: 30 #这个配置在两个中央被应用: #如果启用用了自我爱护,则会 renewal-threshold-update-interval-ms 指定的工夫内,收到的心跳申请个数是否小于实例个数乘以这个 renewal-percent-threshold #定时工作查看过期实例,每次最多过期 1 - renewal-percent-threshold 这么多比例的实例 renewal-percent-threshold: 0.85 ...

August 24, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版18Eureka的客户端核心设计和配置

本系列代码地址:https://github.com/HashZhang/... Eureka 客户端配置就是拜访 Eureka Server 的客户端相干配置,包含 Eureka Server 地址的配置,拉取服务实例信息相干配置,以后实例注册相干配置和 http 连贯相干配置。在 Spring Cloud 中,Eureka 客户端配置以 eureka.client 结尾,对应配置类为 EurekaClientConfigBean 其中,Eureka 客户端有三个比拟重要的定时工作,以及相干配置,这里用图的形式给大家展现进去了: 读取服务实例相干流程: 定时查看实例信息以及实例状态并同步到 Eureka Server: 定时心跳相干流程: 能够间接指定 Eureka Server 的地址,并且,这些配置能够动静批改,并且能够配置刷新工夫。例如: eureka: client: service-url: # 默认eureka集群,这里必须是defaultZone,不能用-替换大写,与其余的配置不一样,因为切实EurekaClientConfigBean外面写死的 defaultZone: http://127.0.0.1:8211/eureka/ zone1: http://127.0.0.1:8212/eureka/ zone2: http://127.0.0.1:8213/eureka/ zone3: http://127.0.0.1:8214/eureka/ # 如果下面 eureka server 地址相干配置更新了,多久之后会从新读取感知到 eureka-service-url-poll-interval-seconds: 300也能够通过 DNS 获取 Eureka Server,例如: eureka: client: # 是否应用 dns 获取,如果指定了则通过上面的 dns 配置获取,而不是下面的 service-url use-dns-for-fetching-service-urls: true # dns 配置 # eureka-server-d-n-s-name: eureka.com # dns 配置的 eureka server 的 port # eureka-server-port: 80 # dns 配置的 eureka server 的 port 前面的 uri 前缀 context # eureka-server-u-r-l-context: /eureka同时,可能有不同的 Eureka Server 部署在不同的可用区域(zone)上,这里也能够配置 Eureka Client 的 zone 配置: ...

August 23, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版16Eureka架构和核心概念

本系列代码地址:https://github.com/HashZhang/... Eureka 目前 1.x 版本还在更新,然而应该不会更新新的性能了,只是对现有性能进行保护,降级并兼容所需的依赖。 Eureka 2.x 曾经胎死腹中了。然而,这也不代表 Eureka 就是不能用了。如果你须要一个简便易于部署的注册核心,Eureka 还是一个很好的抉择。云服务环境中,基本上所有实例地址和微服务名称都在一直变动,也并不太须要 Eureka 所短少的长久化个性。当你的集群属于中小规模的时候(节点小于 1000 个), Eureka 仍然是一个不错的抉择。当你的集群很大的时候,Eureka 的同步机制可能就限度了他的体现。 Eureka 的设计比拟玲珑,没有简单的同步机制(例如 Nacos 基于 Raft,Zookeeper 基于 Zab),也没有简单的长久化机制,集群关系只是简略的将收到的客户端申请转发到集群内的其余 Eureka 实例。Eureka 自身也只有注册核心的性能,不像其余品种的注册核心那样,将注册核心和配置核心合在一起,例如 Consul 和 nacos。 这里咱们疏忽所有的 AWS 相干的术语以及配置还有相干逻辑解决。 Eureka 中的术语: Eureka 实例:每个注册到 Eureka 下面的实例就是 Eureka 实例。Eureka 实例状态:包含 UP(能够解决申请),DOWN(健康检查失败,不能失常解决申请),STARTING(启动中,不能解决申请),OUT_OF_SERVICE(人为下线,临时不解决申请),UNKNOWN(未知状态)。Eureka 服务器:作为注册核心运行,次要提供实例治理性能(解决实例注册(register)申请、解决实例登记(cancel)申请、解决实例心跳(renew)申请、外部解决实例过期(evict))、实例查问性能(各种查问实例信息的接口,例如通过 AppName 获取实例列表,通过实例 id 获取实例信息等等)Eureka 服务器集群:Eureka 服务器的集群,每个 Eureka 服务器都配置了区域以及可用区,Eureka 服务器收到的客户端申请会转发到同一区域内的其余 Eureka 服务器,能够配置优先发到同一可用区的 Eureka 服务器。非同一区域内 Eureka 服务器,通过定时拉取的形式进行同步。Eureka 客户端:申请 Eureka 服务器的客户端。封装发送实例注册(register)申请、实例登记(cancel)申请和实例心跳(renew)申请。VIP(或者是 Virtual Hostname): Eureka 中能够通过两种形式获取实例,一个是通过服务名称,另一种是通过 VIP。每个实例都有服务名称,以及 VIP。Eureka 服务器中的索引形式是以服务名称为 key 的索引,咱们也能够通过遍历所有实例信息的形式通过 VIP 字符串匹配获取相干的实例。在 Spring Cloud 体系中,一个实例的 VIP、SVIP(其实就是 Secure VIP,即 https 的地址)以及服务名称都是 spring.application.name 指定的服务名称。 ...

August 20, 2021 · 1 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版13UnderTow-核心配置

本系列代码地址:https://github.com/HashZhang/... Undertow 的配置能够参考 Undertow 的 Builder,并且其中也有一些默认的配置参数: Undertow private Builder() { ioThreads = Math.max(Runtime.getRuntime().availableProcessors(), 2); workerThreads = ioThreads * 8; long maxMemory = Runtime.getRuntime().maxMemory(); //smaller than 64mb of ram we use 512b buffers if (maxMemory < 64 * 1024 * 1024) { //use 512b buffers directBuffers = false; bufferSize = 512; } else if (maxMemory < 128 * 1024 * 1024) { //use 1k buffers directBuffers = true; bufferSize = 1024; } else { //use 16k buffers for best performance //as 16k is generally the max amount of data that can be sent in a single write() call directBuffers = true; bufferSize = 1024 * 16 - 20; //the 20 is to allow some space for protocol headers, see UNDERTOW-1209 }}ioThreads 大小为可用 CPU 数量 * 2,即 Undertow 的 XNIO 的读线程个数为可用 CPU 数量,写线程个数也为可用 CPU 数量。workerThreads 大小为 ioThreads 数量 * 8.如果内存大小小于 64 MB,则不应用间接内存,bufferSize 为 512 字节如果内存大小大于 64 MB 小于 128 MB,则应用间接内存,bufferSize 为 1024 字节如果内存大小大于 128 MB,则应用间接内存,bufferSize 为 16 KB 减去 20 字节,这 20 字节用于协定头。 ...

August 17, 2021 · 3 min · jiezi

关于spring-cloud:05篇-Nacos-Client服务订阅之事件机制剖析

学习不必那么功利,二师兄带你从更高维度轻松浏览源码~上篇文章,咱们剖析了Nacos客户端订阅的外围流程:Nacos客户端通过一个定时工作,每6秒从注册核心获取实例列表,当发现实例发生变化时,公布变更事件,订阅者进行业务解决,而后更新内存中和本地的缓存中的实例。 这篇文章为服务订阅的第二篇,咱们重点来剖析,定时工作获取到最新实例列表之后,整个事件机制是如何解决的。 回顾整个流程先回顾一下客户端服务订阅的根本流程: 在第一步调用subscribe办法时,会订阅一个EventListener事件。而在定时工作UpdateTask定时获取实例列表之后,会调用ServiceInfoHolder#processServiceInfo办法对ServiceInfo进行本地解决,这其中就包含和事件处理。 监听事件的注册在subscribe办法中,通过如下形式进行了监听事件的注册: @Overridepublic void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener) throws NacosException { if (null == listener) { return; } String clusterString = StringUtils.join(clusters, ","); changeNotifier.registerListener(groupName, serviceName, clusterString, listener); clientProxy.subscribe(serviceName, groupName, clusterString);}这里的changeNotifier.registerListener便是进行具体的事件注册逻辑。追进去看一下实现源码: // InstancesChangeNotifierpublic void registerListener(String groupName, String serviceName, String clusters, EventListener listener) { String key = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters); ConcurrentHashSet<EventListener> eventListeners = listenerMap.get(key); if (eventListeners == null) { synchronized (lock) { eventListeners = listenerMap.get(key); if (eventListeners == null) { eventListeners = new ConcurrentHashSet<EventListener>(); // 将EventListener缓存到listenerMap listenerMap.put(key, eventListeners); } } } eventListeners.add(listener);}能够看出,事件的注册便是将EventListener存储在InstancesChangeNotifier的listenerMap属性当中了。 ...

August 16, 2021 · 4 min · jiezi

关于spring-cloud:第一章-微服务简介

本章从架构倒退的角度来形容技术的倒退过程,依据不同阶段所面临的问题来推动架构的演变,从而更好地了解微服务的实质以及它所带来的的益处,本章内容次要会通过架构的演进过程帮忙大家建设一个整体意识,从而更好地把握微服务体系。 1.1 从单体架构到微服务架构的演进 1.1.1 单体架构 通过咱们之前的学习,咱们开发一个一个Web我的项目,能够应用Spring、SpringMVC、Mybatis等技术。比方之前的快递驿站我的项目,旅游网我的项目SSM版,账单治理我的项目等,我的项目构造如下图1-1所示。 图1-1 单体架构整个零碎的架构非常简单,应用Spring+SpringMVC+Mybatis构建一个根底工程、MySQL数据库作为长久化存储,在这个工程中创立不同的Service实现商场中不同的业务场景,如线路、线路分类、用户等。最初把我的项目构建成一个war包部署在Tomcat容器上即可应用,这时咱们之前常常采纳的架构。通常来说,如果一个war包或者jar包外面蕴含一个利用的所有性能,则咱们称这种架构为单体架构。很多传统互联网公司或者守业型公司晚期根本都会采纳这样的架构,因为这样的架构足够简略,可能疾速开发和上线。而且对于我的项目初期用户量不大的状况,这样的架构足以撑持业务的失常运行。 1.1.2 集群和垂直化 以商城零碎为例。随着业务的倒退,产品被越来越多的人应用,那么对于整个技术架构来说,可能会面临以下挑战:用户量越来越大,网络访问量一直增大,导致后端服务器的负载越来越高。用户量大了,产品须要满足不同用户的需要来留住用户,使得业务场景越来越多并且越来越简单。当服务器的负载越来越高的时候,如果不进行任何解决,用户在网站上操作的响应会越来越慢,甚至呈现无法访问的状况,对于十分重视用户体验的互联网产品来说,这是无奈容忍的。业务的场景越多越简单,意味着war包中的代码量会持续上升,并且各个业务代码之间的耦合度也会越来越高,前期的代码保护和版本公布波及的测试和上线,也会很困那。举个最简略的例子,当你须要在库存模块外面增加一个办法时,带来的影响是须要把整个零碎从新测试和部署,而当一个war包有几GB的大小时,部署的过程也是相当苦楚的。因而,咱们能够从两个方面进行优化:通过横向减少服务器,把单台机器变成多台机器的集群。依照业务的垂直畛域进行拆分,缩小业务的耦合度,以及升高单个war包带来的伸缩性艰难问题。如图1-2所示,咱们把商城零碎依照业务维度进行了垂直拆分:用户子系统、库存子系统、商品子系统,每个子系统由不同的业务团队负责保护并且独立部署。同时,咱们针对Tomcat服务器进行了集群部署,也就是把多台Tomcat服务器通过网络进行连贯组合,造成一个整体对外提供服务。这样做的益处是可能在扭转利用自身的前提下,通过减少服务器来进行程度扩容从而晋升整个零碎的吞吐量。须要留神的是,图1-2中针对数据库进行了垂直分库,次要是思考到Tomcat服务器可能承载的流量大了之后,如果流量都传导到数据库上,会给数据库造成比拟大的压力。总体来说,数据库层面的拆分思维和业务零碎的拆分思维是一样的,都是采纳分而治之的思维。 图1-2 集群及垂直化之后的架构1.1.3 SOA为了让大家更好地了解SOA,咱们来看两个场景:假如一个用户执行下单操作,零碎的解决逻辑是先去库存子系统检杳商品的库存,只有在库存足够的状况下才会提交订单,那么这个查看库存的逻辑是放在订单子系统中还是库存子系统呢?在整个零碎中,肯定会存在十分多相似的共享业务的场景,这些业务场景的逻辑必定会被反复创立,从而产生十分多冗余的业务代码,这些冗余代码的保护老本会随着工夫的推移越来越高,能不能够把这些共享业务逻辑抽离进去造成可重用的服务呢?在一个集团公司下有很多子公司,每个子公司都有本人的业务模式和信息积淀,各个子公司之间不进行交互和共享。这个时候每个子公司尽管可能发明肯定的价值,然而因为各个子公司之间信息不是互联互通的,彼此之间造成了信息孤岛,使得价值无奈最大化。基于这些问题,就引入了SOA (Service-Oriented Architecture ),也就是面向服务的架构,从语义上说,它和面向过程、面向对象、面向组件的思维是一样的,都是一种软件组建及开发的形式。外围指标是把一些通用的、会被多个下层服务调用的共享业务提取成独立的根底服务。这些被提取进去的共享服务相对来说比拟独立,并且能够重用。所以在SOA中,服务是最外围的形象伎俩,业务被划分为一些粗粒度的业务服务和业务流程。如图1-3所示,提取出了用户服务、库存服务、商品服务等多个共享服务。在SOA中,会采纳ESB (企业服务总线)来作为零碎和服务之间的通信桥梁,ESB自身还提供服务地址的治理、不同零碎之间的协定转化和数据格式转化等。调用端不离要关怀指标服务的地位,从而使得服务之间的交互是动静的,这样做的益处是实现了服务的调用者和服务的提供者之间的高度解耦。总的来说,SOA次要解决的问题是:信息孤岛。共享业务的重用。 图1-3 SOA架构 1.1.4 微服务架构 业务系统实施服务化革新之后,本来共享的业务被拆分造成可复用的服务,能够在最大水平上防止共享业务的反复建设、资源连贯瓶颈瓶颈等问题。那么被拆分进去的服务是否也须要以业务性能为维度来进行拆分和独立部署,以升高业务的耦合及晋升容错性呢? 微服务就是这样一种解决方案,从名字上来看,面向服务(SOA)和微服务实质上都是服务化思维的一种体现。如果SOA是面向服务开发的思维的雏形,那么微服务就是针对可重用业务服务的更进一步优化,咱们能够把SOA看成微服务的超集,一但服务规模扩充就意味着服务的构建、公布、运维的复杂度也会成倍增加,所以施行微服务的前提是软件交付链路及基础设施的成熟化。因而微服务在我看来并不是一个新的概念,他实质上是服务化思维的最佳实际方向。因为SOA和微服务两者的关注点不一样,造成了这两者有十分大的区别:SOA关注的是服务的重用性及解决信息孤岛问题。微服务关注的是解耦,尽管解耦和可重用性从特定的角度来看是一样的,但实质上是有区别的,解耦是升高业务之间的耦合度,而重用性关注的是服务的复用。微服务会更多地关注在DevOps的继续交付上,因为服务粒度细化之后使得开发运维变得更加重要,因而微服务与容器化技术的联合更加严密。如图1-4所示,将每个具体的业务服务形成可独立运行的微服务,每个微服务只关注某个特定的性能,服务之间采纳轻量级通信机制REST API进行通信。仔细的读者会发现SOA中的服务和微服务架构中的服务粒度是一样的,不是说SOA是微服务的超集吗?其实咱们能够把用户服务拆分的更细,比方用户注册服务、用户鉴权服务等。实际上,微服务到底要拆分到多大的粒度没有对立的规范,更多的时候是须要在粒度和团队之间找均衡的,微服务的粒度越小,服务独立性带来的益处就越多,然而治理大量的微服务也会越简单。 图1-4 微服务1.2 微服务简介 比方咱们网上购物,首先应该去购物网站搜寻商品,这个搜寻性能就能够开发成一个微服务。咱们也能够看到相干商品的举荐,这些举荐项也能够是一个微服务。前面比方退出购物车、下订单、领取等性能都能够开发成一个一个的独立运行的微服务。 In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.-- James Lewis and Martin Fowler (2014) ...

August 9, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版1背景

本系列为之前系列的整顿重启版,随着我的项目的倒退以及我的项目中的应用,之前系列外面很多货色产生了变动,并且还有一些货色之前系列并没有提到,所以重启这个系列重新整理下,欢送各位留言交换,谢谢!~ Spring Cloud 官网文档说了,它是一个残缺的微服务体系,用户能够通过应用 Spring Cloud 疾速搭建一个本人的微服务零碎。那么 Spring Cloud 到底是如何应用的呢?他到底有哪些组件? spring-cloud-commons组件外面,就有 Spring Cloud 默认提供的所有组件性能的形象接口,有的还有默认实现。目前的 2020.0.x (依照之前的命名规定应该是 iiford),也就是spring-cloud-commons-3.0.x包含: 服务发现:DiscoveryClient,从注册核心发现微服务。服务注册:ServiceRegistry,注册微服务到注册核心。负载平衡:LoadBalancerClient,客户端调用负载平衡。其中,重试策略从spring-cloud-commons-2.2.6退出了负载平衡的形象中。断路器:CircuitBreaker,负责什么状况下将服务断路并降级调用 http 客户端:外部 RPC 调用都是 http 调用而后,个别一个残缺的微服务零碎还包含: 对立网关配置核心全链路监控与监控核心Spring Cloud 始终处于十分沉闷,十分疾速迭代的过程,并且 Spring Cloud 高度依赖 Spring Boot,Spring Boot 与 Spring Cloud 相辅相成。然而,疾速迭代带来的不只是新性能的引入以及原有性能的优化,还有就是降级过程中带来了很多兼容性,功能性,完整性,稳定性的懊恼。本系列旨在帮忙广大读者理解不同大版本 Spring Boot & Spring Cloud 的个性性能以及底层原理的同时,应用这些组件实现一个具备残缺性能的微服务体系,同时这个体系会适应目前最新的云原生环境。 咱们应用的是目前最风行的 Docker + Kubernetes 的组合。目前个别微服务架构,都不会间接应用物理机,因为古代的互联网业务个别都具备这样的个性(咱们拿电子商城举例): 业务会在某一时刻开始忽然开始快速增长,例如咱们开始在各地投放广告,用户一直进入网站,随着口碑一直变好,用户增长速度越来越快。业务在一段时间内,有顶峰有低谷。例如在一天内,白天个别都在下班,早晨拜访网站下单的人数比拟多。业务在一段时间内,最高峰与最低峰之间的差距随着业务增长越来越大。因为大部分用户都在早晨拜访网站下单,导致白天和早晨的流量相差越来越大。会忽然呈现流量尖峰,并且很难预测这个工夫点以及估计量。例如双 11 促销的时候,人们大量涌入,很难能预计的好会有多少流量。还有就是忽然大家须要某个商品的时候,例如新冠刚开始的时候,口罩抢购一空。对于这些个性,依据业务压力,智能并且疾速动静扩容缩容这个性能变得越来越重要,然而这个性能在间接部署业务到物理机上很难实现。这时候呈现了虚拟机,将物理机虚拟化形象成多个虚拟机,比方 vmware 和 openstack,咱们能够应用虚拟机在咱们的操作系统中模拟出多台子电脑,子电脑之间是互相隔离的,这样能够更粗疏动静的调配物理机的资源。然而虚拟机对于开发和运维人员而言,还是太过于轻便了,存在启动慢,占用空间大,不易迁徙的毛病。接着,容器化技术应运而生,它不须要虚构出整个操作系统,只须要虚构一个小规模的环境即可,而且启动速度很快,除了运行其中利用以外,根本不耗费额定的系统资源。Docker 是利用最为宽泛的容器技术,通过打包镜像,启动容器来创立一个服务。然而随着利用越来越简单,容器的数量也越来越多,由此衍生了治理运维容器的这个重要场景。这个场景目前最风行的解决方案就是 Kubernetes(k8s)。 Kubernetes 能为咱们提供如下性能: 容器编排与治理,机器资源管理以及存储卷挂载服务的健康检查以及自愈服务弹性扩容配置核心服务发现与调度负载平衡 在咱们公司中,我的项目团队包含了运维团队以及后端开发团队。对于 Docker 镜像打包与治理以及对于 K8s 的开发保护部署,次要交给运维团队。微服务业务开发保护,实现微服务个性的框架的开发保护是交给后端开发团队的。所以对于 K8s 的性能,咱们只应用了前三个,对于配置核心、服务发现与调度还有负载平衡,咱们还是次要交给实现微服务个性的框架实现的,将来可能会将这三个性能应用起来。 微服务框架须要思考与 K8s 的交互,次要是服务的健康检查以及自愈以及服务弹性扩容: ...

August 1, 2021 · 1 min · jiezi

关于spring-cloud:跟二师兄学Nacos吧EXT04篇-Nacos竟然是这样使用代理模式的

学习不必那么功利,二师兄带你从更高维度轻松浏览源码~随着对Nacos源码的深刻浏览,感觉越来越有意思了,大量的设计模式和根底知识点都在其中被使用。不管你是否浏览源码,都值得借鉴一下Nacos的使用案例。 明天这篇文章,给大家介绍一下Nacos Client中对代理模式的使用。浏览这篇文章,你能够不懂Nacos源码,但可能学到代理模式的使用;如果你筹备浏览Nacos源码,不仅能够学到代理模式的案例,还能够更加粗浅的感知到Nacos中的设计思维。 代理模式简介艰深的来讲,代理模式就是让他人(代理)帮忙做你并不关怀的事,作用就相当于日常生活中的中介。 比方,日常生活中,你想买辆车,你能够间接去本人筛选、质检等,但这个过程会消耗你大量的工夫和精力。那么,此时你就能够找一个代理,来帮忙实现筛选、质检的事件。 对于软件设计来说,代理模式的定义为:代理模式给某一个对象提供一个代理对象,并由代理对象管制对原对象的援用。艰深的来讲代理模式就是咱们生存中常见的中介。 代理模式的构造在不应用代理模式时,咱们大略是这样应用一个接口: 客户端在应用CarService接口时须要创立CarServiceImpl类的实例,而后进行业务逻辑解决。 但在某些场景下,一个客户类不想或者不能间接援用一个委托对象(CarServiceImpl),此时代理类对象能够在客户类和委托对象之间起到中介的作用,并提供雷同的性能。 如果提供雷同的性能,那么代理类和委托类就须要实现雷同的接口。此时,上图就演变成了代理模式: 在代理模式的图中,比照一般的间接应用,新增了代理类,并且代理类持有了委托类(实在对象)的援用。代理类自身并不真正实现服务,而是通过调用委托类的相干办法,来提供特定的服务,所以要持有实在类的援用。 代理类能够在业务性能执行的前后退出一些公共的服务,比方负责为委托类预处理音讯、过滤音讯、把音讯转发给委托类,以及预先对返回后果的解决等。 代理模式中的角色: 形象主题类(Subject):申明了指标对象和代理对象的独特接口,在任何能够应用指标对象的中央都能够应用代理对象。具体主题类(RealSubject):也称为委托角色或者被代理角色。定义了代理对象所代表的指标对象。代理类(Proxy):也叫委托类、代理类。代理对象外部含有指标对象的援用,从而能够在任何时候操作指标对象;代理对象提供一个与指标对象雷同的接口,以便能够在任何时候代替指标对象。代理对象通常在客户端调用传递给指标对象之前或之后,执行某个操作,而不是单纯地将调用传递给指标对象。代理模式实现以下面的结构图为例,来看看代理模式的代码实现。 定义形象主题类(CarService)、具体主题类(CarServiceImpl)、代理类(CarServiceProxy): // 形象主题类public interface CarService { // 选车 Car chooseCar(); // 质量检查 boolean qualityCheck();}// 具体主题类public class CarServiceImpl implements CarService { @Override public Car chooseCar() { System.out.println("实在操作:选车"); return new Car(); } @Override public boolean qualityCheck() { System.out.println("实在操作:品质检测"); return true; }}// 代理类public class CarServiceProxy implements CarService { private CarServiceImpl real; public CarServiceProxy() { real = new CarServiceImpl(); } @Override public Car chooseCar() { System.out.println("代理类CarServiceProxy选车:先增加一些日志"); return real.chooseCar(); } @Override public boolean qualityCheck() { System.out.println("代理类CarServiceProxy品质检测:先增加一些日志"); return real.qualityCheck(); }}对应的客户端测试类: ...

July 28, 2021 · 2 min · jiezi

关于spring-cloud:跟二师兄学Nacos吧EXT01篇-看看Nacos是怎么活学活用简单工厂模式的

学习不必那么功利,二师兄带你一起轻松读源码~番外篇简介Nacos源码剖析系列文章,在开篇曾经提到过,写作的指标有两个:第一,可能零碎的学习Nacos常识;第二,可能基于Nacos学到波及到的知识点或面。 为了不便大家学习,绝对应的文章题目会有所区别,Nacos原理局部命名依照失常编号进行。而番外篇,也就是技术点的解说则会在文章编号上增加“EXT-”的前缀。这样,如果大家只想学习Nacos原理常识,则可跳过EXT前缀的文章。 这篇文章咱们来看看Nacos Client中对工厂模式的应用。这里分两个步骤来理解,首先看看规范的工厂模式是什么样子的,而后再比照一下Nacos中的实现与规范实现有什么区别。 工厂模式概述在23种设计模式当中,工厂模式蕴含两种:工厂办法模式和形象工厂模式。它们都属于创立型模式,而还有一种简略工厂模式,尽管常常被用到,但可能是过于简略,未被纳入23种设计模式当中。 简略工厂模式上面先介绍一下,简略工厂模式,并对Nacos中的应用进行比照,并思考为什么会这样设计。 简略工厂模式简介简略工厂模式,又叫做动态工厂办法(Static Factory Method)模式。简略工厂模式是由一个工厂对象依据不同的参数类型返回不同实例。简略工厂模式是工厂模式家族中最简略实用的模式,能够了解为是不同工厂模式的一个非凡实现。 对于简略工厂模式,要解决的问题便是封装实例创立的过程。须要什么类,只需传入一个对应的参数,就能够取得所需的对象,调用者无需晓得实例的创立过程。被创立的实例通常都具备独特的父类。 简略工厂模式的构造UML图展现如下: 简略工厂通常包含三局部: Factory(工厂):外围局部,负责实现创立所有产品的外部逻辑,工厂类能够被外界间接调用,创立所需对象;AbstractProduct(形象产品类):工厂类所创立的所有对象的父类,封装了产品对象的公共办法,所有的具体产品为其子类对象;ConcreteProduct(具体产品):简略工厂模式的创立指标,实现了形象产品类,所有被创立的对象都是某个具体类的实例;其中形象产品类能够是接口,也能够说抽象类。 简略工厂模式的实现这里假如Nacos的配置核心服务和命名服务都继承自对立的NacosService,同时都须要提供一个注册办法。 形象产品类定义如下: public interface NacosService { /** * 注册实例信息 * @param object 实例信息,这里用Object代替 */ void register(Object object);}命名服务NamingService的具体实现: public class NamingService implements NacosService { @Override public void register(Object object) { System.out.println("注册命名服务胜利"); }}配置服务ConfigService的具体实现: public class ConfigService implements NacosService { @Override public void register(Object object) { System.out.println("配置核心实例注册胜利"); }}提供一个工厂类NacosFactory: public class NacosFactory { public static NacosService getService(String name) { if ("naming".equals(name)) { return new NamingService(); } else { return new ConfigService(); } }}其中依据传入的参数,生成不同类型的NacosService具体实现。 ...

July 19, 2021 · 1 min · jiezi

关于spring-cloud:使用DebeziumPostgres和Kafka进行数据实时采集CDC

1. 背景始终在欠缺本人的微服务架构,其中蕴含分布式工作流服务的建设,目前采纳的是Camunda工作流引擎。应用Camunda工作流,就会波及到工作流引擎的用户体系如何与现有用户体系集成的问题(Flowable、Activity也相似)。现有设计中,工作流定位偏重于企业外部流程的流转,因而零碎中设计了单位、部门、人员以及人事归属与Camunda工作流用户体系对应。 功能设计实现,就面临另外一个问题,如何解决现有人事体系数据如何【实时】同步至Camunda工作流引擎中。如果现有体系数据与工作流数据在同一个库中,绝对比拟好解决。而微服务架构中,不同服务的数据通常寄存在不同数据库中,那么就须要进行数据的同步。采纳的形式不同,能够获得的成果也雷同。 最后思考如下两种计划,然而都略感有余: ETL:应用ETL工具进行数据同步是典型的形式,能够抉择工具也比拟多。开源的ETL工具增量同步问题解决的并不现实,不应用增量同步数那么数据同步始终存在时间差;商业的ETL工具增量同步解决的比拟好,然而宏大且低廉。音讯队列:音讯队列是多系统集成广泛采纳的形式,能够很好的解决数据同步的实时问题。然而数据同步的两端都须要本人编写代码,一端写生产代码一端写生产代码,生产端代码还要捆绑现有体系数据所有操作,须要的编写量比拟大。查问比照的大量的材料,最终抉择了Debezimu来解决以上问题以及将来更多数据同步的问题。 2. Debezium介绍RedHat开源的Debezium是一个将多种数据源实时变更数据捕捉,造成数据流输入的开源工具。它是一种CDC(Change Data Capture)工具,工作原理相似大家所熟知的Canal, DataBus, Maxwell等,是通过抽取数据库日志来获取变更的。官网介绍为: Debezium is an open source distributed platform for change data capture. Start it up, point it at your databases, and your apps can start responding to all of the inserts, updates, and deletes that other apps commit to your databases. Debezium is durable and fast, so your apps can respond quickly and never miss an event, even when things go wrongDebezium是一个分布式平台,它将您现有的数据库转换为事件流,因而应用程序能够看到数据库中的每一个行级更改并立刻做出响应。Debezium构建在Apache Kafka之上,并提供Kafka连贯兼容的连接器来监督特定的数据库管理系统。 ...

July 18, 2021 · 5 min · jiezi

关于spring-cloud:Spring-Cloud-Netflix整合Eureka

Spring-Cloud Euraka是Spring Cloud汇合中一个组件,它是对Euraka的集成,用于服务注册和发现。Eureka是Netflix中的一个开源框架。它和 zookeeper、Consul一样,都是用于服务注册治理的,同样,Spring-Cloud 还集成了Zookeeper和Consul。 搭建eureka服务注册核心引入以下依赖<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 最新版的 eureka 服务端包 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <!-- SpringCloud依赖,起到治理版本的作用 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR9</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>Spring Cloud 和 Spring Boot 之间版本对应关系Release TrainBoot Version2020.0.x aka Ilford2.4.xHoxton2.2.x, 2.3.x (Starting with SR5)Greenwich2.1.xFinchley2.0.xEdgware1.5.xDalston1.5.x在启动类上增加@EnableEurekaServer注解,表明这是一个Eureka服务端@SpringBootApplication@EnableEurekaServerpublic class SpringCloudEurekaApplication { public static void main(String[] args) { SpringApplication.run(SpringCloudEurekaApplication.class, args); }}在application.properties中增加一些配置server.port=8080spring.application.name=Eureka-Server# 指定了Eureka服务端的IPeureka.instance.hostname=localhosteureka.instance.statusPageUrl=http://${eureka.instance.hostname}:${server.port}/infoeureka.instance.healthCheckUrl=http://${eureka.instance.hostname}:${server.port}/healtheureka.instance.homePageUrl=http://${eureka.instance.hostname}/# 示意是否将服务注册到Eureka服务端,因为本身就是Eureka服务端,所以设置为false# eureka.client.register-with-eureka=false# 示意是否从Eureka服务端获取服务信息,因为这里只搭建了一个Eureka服务端,并不需要从别的Eureka服务端同步服务信息,所以这里设置为false# eureka.client.fetch-registry=false# 指定Eureka服务端的地址,默认值为http://localhost:8761/eureka 指定Eureka服务端的地址为另外一个Eureka服务端的地址8081eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/# 用于定义服务续约工作的调用间隔时间,默认30秒eureka.client.serviceUrl.registry-fetch-interval-seconds=5配置结束后启动服务,拜访http://localhost:8080/ 因为还没有Eureka客户端将服务注册进来,所以Instances currently registered with Eureka列表是空的 ...

June 29, 2021 · 2 min · jiezi

关于spring-cloud:Spring-Cloud-升级之路20200x-7使用-Spring-Cloud-LoadBalancer-2

本我的项目代码地址:https://github.com/HashZhang/...咱们应用 Spring Cloud 官网举荐的 Spring Cloud LoadBalancer 作为咱们的客户端负载均衡器。上一节咱们理解了 Spring Cloud LoadBalancer 的构造,接下来咱们来说一下咱们在应用 Spring Cloud LoadBalancer 要实现的性能: 咱们要实现不同集群之间不相互调用,通过实例的metamap中的zone配置,来辨别不同集群的实例。只有实例的metamap中的zone配置一样的实例能力相互调用。这个通过实现自定义的 ServiceInstanceListSupplier 即可实现负载平衡的轮询算法,须要申请与申请之间隔离,不能共用同一个 position 导致某个申请失败之后的重试还是原来失败的实例。上一节看到的默认的 RoundRobinLoadBalancer 是所有线程共用同一个原子变量 position 每次申请原子加 1。在这种状况下会有问题:假如有微服务 A 有两个实例:实例 1 和实例 2。申请 A 达到时,RoundRobinLoadBalancer 返回实例 1,这时有申请 B 达到,RoundRobinLoadBalancer 返回实例 2。而后如果申请 A 失败重试,RoundRobinLoadBalancer 又返回了实例 1。这不是咱们冀望看到的。针对这两个性能,咱们别离编写本人的实现。 实现不同集群不相互调用Spring Cloud LoadBalancer 中的 zone 配置Spring Cloud LoadBalancer 定义了 LoadBalancerZoneConfig: public class LoadBalancerZoneConfig { //标识以后负载均衡器处于哪一个 zone private String zone; public LoadBalancerZoneConfig(String zone) { this.zone = zone; } public String getZone() { return zone; } public void setZone(String zone) { this.zone = zone; }}如果没有引入 Eureka 相干依赖,则这个 zone 通过 spring.cloud.loadbalancer.zone 配置:LoadBalancerAutoConfiguration ...

May 29, 2021 · 5 min · jiezi

关于spring-cloud:Spring-Cloud-升级之路-20200x-5-理解-NamedContextFactory

spring-cloud-commons 中参考了 spring-cloud-netflix 的设计,引入了 NamedContextFactory 机制,个别用于对于不同微服务的客户端模块应用不同的 子 ApplicationContext 进行配置。 spring-cloud-commons 是 Spring Cloud 对于微服务根底组件的形象。在一个微服务中,调用微服务 A 与调用微服务 B 的配置可能不同。比较简单的例子就是,A 微服务是一个简略的用户订单查问服务,接口返回速度很快,B 是一个报表微服务,接口返回速度比较慢。这样的话咱们就不能对于调用微服务 A 和微服务 B 应用雷同的超时工夫配置。还有就是,咱们可能对于服务 A 通过注册核心进行发现,对于服务 B 则是通过 DNS 解析进行服务发现,所以对于不同的微服务咱们可能应用不同的组件,在 Spring 中就是应用不同类型的 Bean。 在这种需要下,不同微服务的客户端有不同的以及雷同的配置,有不同的 Bean,也有雷同的 Bean。所以,咱们能够针对每一个微服务将他们的 Bean 所处于 ApplicationContext 独立开来,不同微服务客户端应用不同的 ApplicationContext。NamedContextFactory 就是用来实现这种机制的。 通过实例理解 NamedContextFactory 的应用编写源码: package com.github.hashjang.spring.cloud.iiford.service.common;import org.junit.Assert;import org.junit.Test;import org.springframework.cloud.context.named.NamedContextFactory;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.env.Environment;import java.util.List;import java.util.Objects;public class CommonNameContextTest { private static final String PROPERTY_NAME = "test.context.name"; @Test public void test() { //创立 parent context AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(); //增加 BaseConfig 相干配置 parent.register(BaseConfig.class); //初始化 parent parent.refresh(); //创立 testClient1,默认配置应用 ClientCommonConfig TestClient testClient1 = new TestClient(ClientCommonConfig.class); //创立 service1 与 service2 以及指定对应额定的配置类 TestSpec testSpec1 = new TestSpec("service1", new Class[]{Service1Config1.class, Service1Config2.class}); TestSpec testSpec2 = new TestSpec("service2", new Class[]{Service2Config.class}); //设置 parent ApplicationContext 为 parent testClient1.setApplicationContext(parent); //将 service1 与 service2 的配置退出 testClient1 testClient1.setConfigurations(List.of(testSpec1, testSpec2)); BaseBean baseBean = testClient1.getInstance("service1", BaseBean.class); System.out.println(baseBean); //验证失常获取到了 baseBean Assert.assertNotNull(baseBean); ClientCommonBean commonBean = testClient1.getInstance("service1", ClientCommonBean.class); System.out.println(commonBean); //验证失常获取到了 commonBean Assert.assertNotNull(commonBean); Service1Bean1 service1Bean1 = testClient1.getInstance("service1", Service1Bean1.class); System.out.println(service1Bean1); //验证失常获取到了 service1Bean1 Assert.assertNotNull(service1Bean1); Service1Bean2 service1Bean2 = testClient1.getInstance("service1", Service1Bean2.class); System.out.println(service1Bean2); //验证失常获取到了 service1Bean2 Assert.assertNotNull(service1Bean2); BaseBean baseBean2 = testClient1.getInstance("service2", BaseBean.class); System.out.println(baseBean2); //验证失常获取到了 baseBean2 并且 baseBean2 就是 baseBean Assert.assertEquals(baseBean, baseBean2); ClientCommonBean commonBean2 = testClient1.getInstance("service2", ClientCommonBean.class); System.out.println(commonBean2); //验证失常获取到了 commonBean2 并且 commonBean 和 commonBean2 不是同一个 Assert.assertNotNull(commonBean2); Assert.assertNotEquals(commonBean, commonBean2); Service2Bean service2Bean = testClient1.getInstance("service2", Service2Bean.class); System.out.println(service2Bean); //验证失常获取到了 service2Bean Assert.assertNotNull(service2Bean); } @Configuration(proxyBeanMethods = false) static class BaseConfig { @Bean BaseBean baseBean() { return new BaseBean(); } } static class BaseBean {} @Configuration(proxyBeanMethods = false) static class ClientCommonConfig { @Bean ClientCommonBean clientCommonBean(Environment environment, BaseBean baseBean) { //在创立 NamedContextFactory 外面的子 ApplicationContext 的时候,会指定 name,这个 name 对应的属性 key 即 PROPERTY_NAME return new ClientCommonBean(environment.getProperty(PROPERTY_NAME), baseBean); } } static class ClientCommonBean { private final String name; private final BaseBean baseBean; ClientCommonBean(String name, BaseBean baseBean) { this.name = name; this.baseBean = baseBean; } @Override public String toString() { return "ClientCommonBean{" + "name='" + name + '\'' + ", baseBean=" + baseBean + '}'; } } @Configuration(proxyBeanMethods = false) static class Service1Config1 { @Bean Service1Bean1 service1Bean1(ClientCommonBean clientCommonBean) { return new Service1Bean1(clientCommonBean); } } static class Service1Bean1 { private final ClientCommonBean clientCommonBean; Service1Bean1(ClientCommonBean clientCommonBean) { this.clientCommonBean = clientCommonBean; } @Override public String toString() { return "Service1Bean1{" + "clientCommonBean=" + clientCommonBean + '}'; } } @Configuration(proxyBeanMethods = false) static class Service1Config2 { @Bean Service1Bean2 service1Bean2() { return new Service1Bean2(); } } static class Service1Bean2 { } @Configuration(proxyBeanMethods = false) static class Service2Config { @Bean Service2Bean service2Bean(ClientCommonBean clientCommonBean) { return new Service2Bean(clientCommonBean); } } static class Service2Bean { private final ClientCommonBean clientCommonBean; Service2Bean(ClientCommonBean clientCommonBean) { this.clientCommonBean = clientCommonBean; } @Override public String toString() { return "Service2Bean{" + "clientCommonBean=" + clientCommonBean + '}'; } } static class TestSpec implements NamedContextFactory.Specification { private final String name; private final Class<?>[] configurations; public TestSpec(String name, Class<?>[] configurations) { this.name = name; this.configurations = configurations; } @Override public String getName() { return name; } @Override public Class<?>[] getConfiguration() { return configurations; } } static class TestClient extends NamedContextFactory<TestSpec> { public TestClient(Class<?> defaultConfigType) { super(defaultConfigType, "testClient", PROPERTY_NAME); } }}后果输入为: ...

May 26, 2021 · 4 min · jiezi

关于spring-cloud:学习Nacos咱先把服务搞起来实战教程

前言后面曾经写不少Nacos相干的文章了,比方《Spring Cloud集成Nacos服务发现源码解析?翻了三套源码,保质保鲜!》,而且目前也打算写一个Spring Cloud的技术解析专栏,一个技术框架一个技术框架的为大家拆解剖析原理和实现。 既然拿Nacos作为一个开始,那么咱们这篇文章就来补充一下Nacos Server的部署以及Nacos Client的调用,直观的理解一下Nacos都蕴含了什么性能。这是应用Nacos的根底,也是后续进行深度分析的根据。强烈建议一起学习一下。 Nacos Server的部署对于Nacos Server的部署,官网手册中曾经进行了很具体的阐明,对应链接地址(https://nacos.io/zh-cn/docs/d... )。其余形式的部署咱们暂且不说,咱们重点阐明通过源码的模式进行构建和部署,这也是学习的最好形式。 Nacos部署的根本环境要求:JDK 1.8+,Maven 3.2.x+,筹备好即可。 从Github上下载源码: // 下载源码git clone https://github.com/alibaba/nacos.git// 进入源码目录cd nacos/// 执行编译打包操作mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U// 查看生成的jar包ls -al distribution/target/// 进入到打包好的文件目录,后续可执行启动cd distribution/target/nacos-server-$version/nacos/bin通过上述命令进入到bin目录下,通常有不同环境的启动脚本: shutdown.cmd shutdown.sh startup.cmd startup.sh执行对应环境的脚本即可进行启动,参数standalone代表着单机模式运行: // Linux/Unix/Macsh startup.sh -m standalone// ubuntubash startup.sh -m standalone// Windowsstartup.cmd -m standalone上述操作实用于打包和部署,也实用于本地启动服务,但如果是学源码,则能够间接执行console(nacos-console)中的main办法(Nacos类)即可。 执行main办法启动,默认也是集群模式,可通过JVM参数来指定单机启动: -Dnacos.standalone=true如果为了不便,也能够间接在启动类的源码中间接增加该参数: @SpringBootApplication(scanBasePackages = "com.alibaba.nacos")@ServletComponentScan@EnableSchedulingpublic class Nacos { public static void main(String[] args) { // 通过环境变量的模式设置单机启动 System.setProperty(Constants.STANDALONE_MODE_PROPERTY_NAME, "true"); SpringApplication.run(Nacos.class, args); }}通过上述步骤,咱们曾经能够启动一个Nacos Server了,前面就来看如何应用。 ...

May 21, 2021 · 2 min · jiezi

关于spring-cloud:Eurynome-Cloud-微服务能力管理和开发平台

Eurynome Cloud 微服务能力治理和开发平台Eurynome Cloud是一款微服务能力治理和开发平台。基于SpringBoot2.4.5、Spring Cloud 2020.0.2、Spring Cloud Alibaba 2021.1、Nacos 2.0.1等最新版本开发,遵循SpringBoot编程思维,高度模块化和可配置化。具备服务发现、配置、熔断、限流、降级、监控、多级缓存、分布式事务、工作流等性能,代码简洁,架构清晰,非常适合学习和企业作为根底框架应用。 1、性能介绍 特点: 优化的代码分包和包依赖,代码包职责明确,躲避无意义的依赖以及反复依赖,对根底依赖组件进行高度封装,升高IDE索引工夫,晋升开发效率遵循微服开发模式,强化整体的可配置性,依赖性能均能够通过@EnableXXX开启,反对策略化的注入扭转局部外围代码的实现逻辑。提供的starter,开箱即用,可零配置创立服务,疾速进行开发基于JetCache自研缓存拓展,反对分页和条件查问缓存动静更新拓展OAuth2默认登录,反对多种验证码和登录数据加密传输,可通过配置进行自定义设置。多数据库反对,默认采纳Postgresql数据库,同时反对Spring Data Jpa 和Mybatis多种音讯队列反对,适配RabbitMQ和Kafka,默认应用Kafka,反对音讯总线(Spring Cloud Bus)Rest接口自动化扫描生成权限数据,反对扫描包和扫描注解动静配置采纳Camunda实现工作流服务,反对在线编辑同时反对分布式和单体式两种架构,基于单体式架构可疾速搭建基于OAuth2的前后端拆散利用共享式、统一化多环境配置模式,Yml、Docker均采纳此形式配置,防止同类配置多出批改的问题2、技术栈和版本阐明(1)Spring全家桶及核心技术版本组件版本Spring Boot2.4.5Spring Cloud2020.0.2Spring Cloud Alibaba2021.1Spring Boot Admin2.4.1Nacos2.0.1 Sentinel1.8.0 Seata1.3.0 Spring 全家桶版本对应关系,详见:版本阐明(2)所波及的相干的技术:JSON序列化:Jackson & FastJson音讯队列:Kafka 适配RabbitMQ,反对音讯总线(Spring Cloud Bus)数据缓存:JetCache + Redis (两级缓存)数据库: Postgresql,MySQL,Oracle ...前端实现:Vue + Vuetify(单体版Vue + Vuetify + Typescript + 模块化)长久层框架: Spring Data Jpa & MybatisAPI网关:Gateway服务注册&发现和配置核心: Nacos服务生产:OpenFeign & RestTemplate & OkHttp3负载平衡:Ribbon服务熔断&降级&限流:Sentinel我的项目构建:Maven分布式事务:Seata服务监控:Spring Boot Admin链路跟踪:Skywalking文件服务:阿里云OSS/Minio数据调试:p6spy日志核心:ELK日志收集:Logstash Logback Encoder3、 版本号阐明本零碎版本号,分为四段。 第一段和第二段,与Spring Boot 版本对应,依据采纳的Spring Boot版本变更。例如,以后采纳Spring Boot 2.4.5版本,那么就以2.4.X.X结尾第三段,示意零碎性能的变动第四段,示意零碎性能保护及优化状况4、工程构造eurynome-cloud├── configurations -- 配置文件脚本和对立Docker build上下文目录├── dependencies -- 工程Maven顶级依赖,对立管制版本和依赖├── documents -- 工程相干文档├── packages -- 根底通用依赖包├ ├── eurynome-cloud-common -- 公共工具类├ ├── eurynome-cloud-data -- 数据长久化、数据缓存以及Redis等数据处理相干代码组件├ ├── eurynome-cloud-rest -- Rest相干代码组件├ ├── eurynome-cloud-crud -- CRUD相干代码组件├ ├── eurynome-cloud-sercurity -- Security通用代码├ ├── eurynome-cloud-oauth -- OAuth2通用代码├ ├── eurynome-cloud-message -- 音讯队列、BUG相干代码组件├ ├── eurynome-cloud-kernel -- 微服务接入平台必备组件├ ├── eurynome-cloud-oauth-starter -- 自定义OAuth2 Starter├ └── eurynome-cloud-starter -- 微服务外围Starter├── platform -- 平台外围服务├ ├── eurynome-cloud-gateway -- 服务网关├ ├── eurynome-cloud-management -- Spring Boot Admin 监控服务├ └── eurynome-cloud-uaa -- 对立认证模块├── services -- 平台业务服务├ ├── eurynome-cloud-upms-api -- 通用用户权限api ├ ├── eurynome-cloud-upms-logic -- 通用用户权限service├ ├── eurynome-cloud-upms-rest -- 通用用户权限rest 接口├ ├── eurynome-cloud-upms-ability -- 通用用户权限服务└── └── eurynome-cloud-bpmn-ability -- 工作流服务 5、我的项目地址后端Gitee地址:https://gitee.com/herodotus/eurynome-cloud单体版示例工程:https://gitee.com/herodotus/eurynome-cloud-athena前端Gitee地址:https://gitee.com/herodotus/eurynome-cloud-ui6、开源协定Apache Licence 2.0 (英文原文) Apache Licence是驰名的非盈利开源组织Apache采纳的协定。该协定和BSD相似,同样激励代码共享和尊重原作者的著作权,同样容许代码批改,再公布(作为开源或商业软件)。 须要满足的条件如下: ...

May 18, 2021 · 1 min · jiezi

关于spring-cloud:Spring-Cloud-Bus-消息总线介绍

简介: 本文配套可交互教程已登录阿里云知口头手实验室,PC 端登录 start.aliyun.com 在浏览器中立刻体验。 作者 | 洛夜起源 | 阿里巴巴云原生公众号 本文配套可交互教程已登录阿里云知口头手实验室,PC 端登录 start.aliyun.com 在浏览器中立刻体验。 Spring Cloud Bus 对本人的定位是 Spring Cloud 体系内的音讯总线,应用 message broker 来连贯分布式系统的所有节点。Bus 官网的 Reference 文档 比较简单,简略到连一张图都没有。 这是最新版的 Spring Cloud Bus 代码构造(代码量比拟少): Bus 实例演示在剖析 Bus 的实现之前,咱们先来看两个应用 Spring Cloud Bus 的简略例子。 1. 所有节点的配置新增Bus 的例子比较简单,因为 Bus 的 AutoConfiguration 层都有了默认的配置,只须要引入消息中间件对应的 Spring Cloud Stream 以及 Spring Cloud Bus 依赖即可,之后所有启动的利用都会应用同一个 Topic 进行音讯的接管和发送。 Bus 对应的 Demo 曾经放到了 github 上, 该 Demo 会模仿启动 5 个节点,只须要对其中任意的一个实例新增配置项,所有节点都会新增该配置项。 ...

May 12, 2021 · 4 min · jiezi

关于spring-cloud:Spring-Cloud-升级之路-20200x-4-使用-Eureka-作为注册中心

Eureka 目前的状态:Eureka 目前 1.x 版本还在更新,然而应该不会更新新的性能了,只是对现有性能进行保护,降级并兼容所需的依赖。 Eureka 2.x 曾经胎死腹中了。然而,这也不代表 Eureka 就是不能用了。如果你须要一个简便易于部署的注册核心,Eureka 还是一个很好的抉择。云服务环境中,基本上所有实例地址和微服务名称都在一直变动,也并不太须要 Eureka 所短少的长久化个性。当你的集群属于中小规模的时候(节点小于 1000 个), Eureka 仍然是一个不错的抉择。当你的集群很大的时候,Eureka 的同步机制可能就限度了他的体现。 Eureka 的设计Eureka 的设计比拟玲珑,没有简单的同步机制,也没有简单的长久化机制,集群关系只是简略的将收到的客户端申请转发到集群内的其余 Eureka 实例。Eureka 自身也只有注册核心的性能,不像其余品种的注册核心那样,将注册核心和配置核心合在一起,例如 Consul 和 nacos。 Eureka 的交互流程如下: 首先,Service A 通过 Eureka Client 发送注册申请(Register)到同一可用区的 Eureka Server 1。之后通过发送心跳申请(Renew)到这个 Eureka Server 1. Eureka Server 1 收到这些申请的时候,会解决这些申请并将这些申请转发到其余的集群内的 Eureka Server 2 和 Eureka Server 3. Eureka Server 2 和 Eureka Server 3 不会再转发收到的 Eureka Server 1 转发过去的申请。而后,Service B 还有 Service C 通过 Eureka 获取到了 Service A 的地位,最初调用了 Service A。 ...

May 10, 2021 · 5 min · jiezi

关于spring-cloud:Spring-Cloud-2020-bootstrap-配置文件失效

Spring Cloud 2020版本 bootstrap 配置文件(properties 或者 yml)有效 如何解决? 背景介绍微服务是基于Spring Cloud框架搭建的,Spring Cloud Config作为服务配置核心。 业务服务只配置服务名称、启用环境和config的URL地址,其余都配置在配置核心,例如服务端口、服务注册核心地址等。可在开发环境(dev)、测试环境(test)和生产环境(prod)别离配置。 所以料想的启动流程是:先加载配置文件,再启动服务。 之前的做法是,将配置文件名称改为:bootstrap.properties。 问题之前间接就能够用,而当初,启动的端口是8080,显著没有加载到bootstrap.properties文件,我认为我的文件名字写错了,核查了几次,确认无误,我猜测预计是bootstramp.properties配置文件没有失效。 之前的版本: spring boot 2.3.1.RELEASE spring cloud Hoxton.SR4 以后版本: spring boot 2.4.2 spring cloud 2020.0.1 查找起因依据下面呈现的问题,我应用百度搜寻了下,大略的起因晓得了:从Spring Boot 2.4版本开始,配置文件加载形式进行了重构。 另外也有配置的默认值变动,如下: Spring Boot 2.3.8.RELEASE package org.springframework.cloud.bootstrap;public class BootstrapApplicationListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered { public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { ConfigurableEnvironment environment = event.getEnvironment(); if ((Boolean)environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class, true)) {Spring Boot 2.4.2 package org.springframework.cloud.util;public abstract class PropertyUtils { public static boolean bootstrapEnabled(Environment environment) { return (Boolean)environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class, false) || MARKER_CLASS_EXISTS; }传统解决方案其实官网说得很明确。看上面这段: ...

February 6, 2021 · 2 min · jiezi