关于springcloud:SpringCloudAlibaba微服务开发实战一个案例手把手带你入门

技术实践随处可见,咱们还缺什么?缺实战案例,夸夸其谈经不住考验,从头到尾经验一次能力记忆粗浅。本篇文章就带你实实在在走一次。联合SpringCloud、SpringCloudAlibaba、Dubbo等开源套件,基于某商场停车业务需要,进行微服务开发实战,力争通过一个案例的实操,把握微服务架构中罕用的技能点,轻松入门。 为什么要写这个专栏(为什么?)微服务近两年的炽热,也将很多公司的架构缓缓转向微服务,但要间接上手微服务,还须要能过实操演练,一直晋升,能力在工作中熟能生巧。 网络上相干资源很多,但大多散乱无章,不成体系,不利于系统性把握,无奈一步步的深刻其中,更不能粗浅把握各个组件在我的项目中理论交融状况。 尽管也有一些案例,但短少相干的文档细节形容,对初学者而言,仅靠浏览代码,难免会只知其一;不知其二。于是,我就推敲写一个贴合理论场景的小例子,业务无需很简单,能将这一套技术体系串连起来,本人能够跟着入手实操,通过一步一步的上手,加深对技术栈的了解。 通过本专栏要达成什么指标(到哪里去?)本专栏将带你完整性的施行一个我的项目,从需要整顿、剖析设计、存储设计、要害业务流程设计、编码、测试(单元测试,零碎测试)、部署上线、日常监控保护等等。 时下采纳麻利研发模式做产品曾经不是什么新鲜事,本专栏中也会适当融入一些麻利办法,进行团队合作演练。程序员同学广泛比拟关注硬技能的晋升,所以把握要害技能很重要。同时,软技能也要随着硬技能的晋升,同样失去锤炼升华,比拟团队合作能力、沟通理解能力、解决问题能力、领导治理能力等等。 本专栏实战案例波及到的技术栈做Java,绕不开Spring。用Java做微服务开发,也绕不开Spring Cloud。但随着Dubbo的重启,并交给Apache开源社区保护后,Dubbo生态越来越欠缺。尽管拿Spring Cloud与Dubbo作比拟不适合,但不少敌人在技术选型时会纠结抉择Dubbo还是Spring Cloud,spring-cloud-alibaba的呈现,将Dubbo生态完满的与Spring Cloud生态交融在一起。你不必再纠结抉择Dubbo还是Spring Cloud,两者能够兼容的很好。 上面列举下可能会应用到的技术栈: 反向代理:Nginx,可做动静拆散部署对立网关:基于spring-cloud-gateway,配合JWT进行的简略的验权操作分布式事务:Seata,阿里外部分布式事务产品一直迭代演进而来。降级、限流:Hysrix/Sentinel服务治理:Nacos分布式配置核心:Nacos客户端负载平衡:OpenFeign异步音讯:RocketMQ,阿里开源,交由Apache孵化链路跟踪:Skywalking,华为开源,交由Apache孵化分布式缓存:Redis衰弱监控:spring-boot-admin分布式锁:Redission代码简化:Lambok,mybatis-plus,mybatis-generatorRPC框架:Apache dubbo实操我的项目中也会波及到一些小组件、小技巧,更加贴近商业我的项目开发实战,一起入手口头起来吧,微服务架构并不深奥,你能够把握的更好。 专栏合适人群程序员、零碎架构师、IT从业者、项目管理人员、IT管理人员、产品经理、业务架构师 源码地址https://xiaozhuanlan.com/msa-practice

October 6, 2020 · 1 min · jiezi

关于springcloud:Spring-Cloud-2020-年路线图发布

JetBrains 发文介绍了其 IntelliJ 平台 2020 年的路线图。 文章次要介绍了以后 JetBrains 在改良 IntelliJ IDEA 和基于 IntelliJ 平台的 IDE 方面所做的一些工作,次要包含性能和对古代开发工作流的反对两个方面。改良后果将会在明年公布,其中一些会公布在秋季的 2020.1 版本中。 性能索引性能与 IDE 性能无关的两个次要痛点是启动性能,索引耗时较长的工具被认为是重量级的。JetBrains 示意,明年关注点将转向索引性能方面。 针对此问题官网采取了多管齐下的办法。首先,反对应用预建的索引块,这样每个用户 IntelliJ 实例都不用执行索引java.lang.String类的工作。 打算明年逐渐提供反对,从 JDK 开始,而后涵盖 Maven Central 的库以及其它 IDE 中的解释器和包。同时还在钻研反对团队或企业内我的项目源代码的索引块共享的办法,尽管这一块目前还没有任何具体打算。 其次,打算通过在索引时提供更多的 IDE 操作来缩小索引的破坏性。 第三,将检测并告诉用户无关索引异样的信息,包含索引破费工夫太长的文件、索引从新建设频率太高的文件以及异样导致的索引重建,目标是提供解决这些问题并进步 IDE 在我的项目上的性能的清晰步骤。 同时也打算反对进行旧性能优化,以确保索引零碎不会执行任何不必要的工作并且不会产生可防止的开销。 读/写锁线程模型从新设计UI 卡死(freeze,解冻)是一个很大的问题。往年尽管曾经构建了用于报告此类卡死问题的根底,并进行了架构更改以修复许多相干问题,比方文件系统事件的异步侦听器,然而接下来的一年中,打算迈出更大的一步:将须要写锁定的操作移出 UI 线程。 早在 IntelliJ IDEA 晚期就做出了一项架构决定,该决定要求大多数操作须要批改 IDE 的外部数据结构能力在 UI 线程上运行,也就是包含基本操作(将字符插入文档中)和大规模操作(重新命名具备数千种用法的办法)。 这种架构的益处是简略的编程模型,然而显著的毛病是 UI 响应能力在许多状况下都会受到影响。 多年以来,官网始终在寻找办法来解决此架构的局限性,次要是将大型操作拆分为在后盾运行并利用于 UI 线程的局部。一个更根本的解决方案是齐全解脱 UI 线程的要求,然而直到最近,还不晓得如何在不对本人的代码和第三方插件进行重大重写的状况下做到这一点。 不过当初,JetBrains 曾经有了一个容许逐渐迁徙的架构解决方案,并且正在开始施行。明年将重构 IntelliJ 平台的根本 UI 组件和 API,以采纳新的线程模型。一旦新模型稳固并且能够看到改良,将在所有 IDE 中切换到新模型,从而使 UI 平滑且没有滞后。 ...

September 25, 2020 · 1 min · jiezi

关于springcloud:Spring-Cloud在k8s下使用IDEA进行本地开发

写在后面咱们在k8s去掉了Eureka组件,引入spring-cloud-kubernetes组件。一、所需工具或命令kubectl命令Shadowsocks ServerShadowsocks ClientKT Connect原本只须要kubectl命令和kt connect就行了,次要是kt connect现有的socks5代理服务有点问题,至多在我这边是这样,0.0.12版本的话idea外面的程序起不来,0.0.13-rc11版本的话vpn和socks5延时高,常常超时。所以萌发了用shadowsocks server来替换kt connect外面的socks5服务(也就是kt connect这一步),kt其余的性能还是依旧,这样就完满联合了。 如果是mac电脑或者ubuntu零碎的电脑的话用0.0.12版本的kt的vpn连贯是没有问题的,然而我还是倡议应用socks5的模式,因为这样不是所有的流量都走vpn,而且其余的开发人员不须要在本机启动vpn代理,只须要通过shadowsocks client连上k8s内的服务,就能够应用kt命令了。 二、装置2.1 装置kubectl命令参考官网地址装置:https://kubernetes.io/zh/docs/tasks/tools/install-kubectl/ ,装置实现后在用户目录下(Mac或Ubuntu用户:/Users/xxxxxx ; Windows用户: C:UsersAdministrator)下手动建设 .kube 文件夹,而后将群外面的config文件拷贝到这外面。操作完后应用命令kubectl get pods查看是否装置实现。如果失败认真查看官网装置步骤,重新安装。 装置实现后,批改hosts文件在其中增加上面记录(联合本人的k8s集群的apiserver地址来设置) 192.168.1.236 k8s.apiserver 2.2 装置Shadowsocks Server服务端编写yml文件,并在k8s集群的default命名空间中执行。 ---apiVersion: apps/v1kind: Deploymentmetadata: name: shadowsocks-server-deployment namespace: default labels: app: shadowsocks-server-deploymentspec: replicas: 1 selector: matchLabels: app: shadowsocks-server-pod template: metadata: labels: app: shadowsocks-server-pod spec: containers: - name: shadowsocks-server-container image: shadowsocks/shadowsocks-libev command: [ # need to modify "-d" to k8s core-dns "--fast-open" "ss-server","-s","0.0.0.0", "-p", "8388", "-t", "300","-k", "代理明码", "-m", "aes-256-cfb", "-d", "10.96.0.10,114.114.114.114", "-u" ] ports: - containerPort: 8388 protocol: TCP name: tcp - containerPort: 8388 protocol: UDP name: udp---apiVersion: v1kind: Servicemetadata: name: shadowsocks-server namespace: defaultspec: type: NodePort ports: - port: 8388 targetPort: 8388 nodePort: 32088 protocol: TCP name: tcp - port: 8388 targetPort: 8388 nodePort: 32088 protocol: UDP name: udp selector: app: shadowsocks-server-pod我这里间接用的是NodePort来开发端口,你们也能够应用ingress来裸露服务 ...

September 25, 2020 · 1 min · jiezi

关于springcloud:springcloud和zookeeper

springcloud的eureka注册核心1.注册每当一个提供者开启服务时就会一直的向注册发动注册申请,直到胜利注册2.拉取每30秒拉取一次注册表,更新注册表(当一个服务器拉取取得注册表就会在本地保留,注册核心宕了也不受影响)3.自我爱护当注册核心有心跳检测85%以上的心跳异样时开启注册核心,不删除表中的注册信息4.心跳检测当有服务器心跳异样时不会第一工夫删除该服务器注册的信息,而是每30秒向服务器发动心跳检测,3次没有回应则判断服务器挂了,删除该服务器注册信息zookeeper注册核心与eureka注册核心区别eurekaAP模式(强调可用性每阁一段时间更新,最终达到统一即可)集群(同级构造)zookeeperCP模式(强调一致性及时更新注册信息表)集群(主从构造)

September 23, 2020 · 1 min · jiezi

关于springcloud:SpringcloudMybatis使用多数据源的四种方式

前段时间在做会员中心和中间件零碎开发时,屡次碰到多数据源配置问题,次要用到分包形式、参数化切换、注解+AOP、动静增加 这四种形式。这里做一下总结,分享下应用心得以及踩过的坑。 分包形式数据源配置文件在yml中,配置两个数据源,id别离为master和s1。 spring: datasource: master: jdbcUrl: jdbc:mysql://192.168.xxx.xxx:xxxx/db1?......... username: xxx password: xxx driverClassName: com.mysql.cj.jdbc.Driver s1: jdbcUrl: jdbc:mysql://192.168.xxx.xxx:xxxx/db2?........ username: xxx password: xxx driverClassName: com.mysql.cj.jdbc.Driver数据源配置类master数据源配置类留神点: 须要用@Primary注解指定默认数据源,否则spring不晓得哪个是主数据源; @Configuration@MapperScan(basePackages = "com.hosjoy.xxx.xxx.xxx.xxx.mapper.master", sqlSessionFactoryRef = "masterSqlSessionFactory")public class MasterDataSourceConfig { //默认数据源 @Bean(name = "masterDataSource") @Primary @ConfigurationProperties(prefix = "spring.datasource.master") public HikariDataSource masterDataSource() { return DataSourceBuilder.create().type(HikariDataSource.class).build(); } @Bean(name = "masterSqlSessionFactory") @Primary public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource datasource, PaginationInterceptor paginationInterceptor) throws Exception { MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); bean.setDataSource(datasource); bean.setMapperLocations( // 设置mybatis的xml所在位置 new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/master/**/**.xml")); bean.setPlugins(new Interceptor[]{paginationInterceptor}); return bean.getObject(); } @Bean(name = "masterSqlSessionTemplate") @Primary public SqlSessionTemplate masterSqlSessionTemplate( @Qualifier("masterSqlSessionFactory") SqlSessionFactory sessionfactory) { return new SqlSessionTemplate(sessionfactory); }}s1数据源配置类@Configuration@MapperScan(basePackages = "com.hosjoy.xxx.xxx.xxx.xxx.mapper.s1", sqlSessionFactoryRef = "s1SqlSessionFactory")public class S1DataSourceConfig { @Bean(name = "s1DataSource") @ConfigurationProperties(prefix = "spring.datasource.s1") public HikariDataSource s1DataSource() { return DataSourceBuilder.create().type(HikariDataSource.class).build(); } @Bean(name = "s1SqlSessionFactory") public SqlSessionFactory s1SqlSessionFactory(@Qualifier("s1DataSource") DataSource datasource , PaginationInterceptor paginationInterceptor) throws Exception { MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean(); bean.setDataSource(datasource); bean.setMapperLocations( // 设置mybatis的xml所在位置 new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/s1/**/**.xml")); bean.setPlugins(new Interceptor[]{paginationInterceptor}); return bean.getObject(); } @Bean(name = "s1SqlSessionTemplate") public SqlSessionTemplate s1SqlSessionTemplate( @Qualifier("s1SqlSessionFactory") SqlSessionFactory sessionfactory) { return new SqlSessionTemplate(sessionfactory); }}应用能够看出,mapper接口、xml文件,须要依照不同的数据源分包。在操作数据库时,依据须要在service类中注入dao层。 ...

September 22, 2020 · 5 min · jiezi

关于springcloud:SpringCloud-简介

SpringCloudSpringCloud是什么是工具集--集成了多个工具,来解决微服务中遇到的各种问题是微服务大礼包--用于解决各种各样的微服务问题是微服务的整体解决方案--一站式解决微服务问题 SpringCloud不是什么不是解决繁多问题的框架--如:mybatis解决长久层问题/springmvc解决mvcweb问题... SpringCloud技术组成eureka微服务治理,服务注册和发现ribbon负载平衡、申请重试hystrix断路器,服务降级、熔断feignribbon + hystrix 集成,并提供申明式客户端hystrix dashboard 和 turbinehystrix 数据监控zuulAPI 网关,提供微服务的对立入口,并提供对立的权限验证config配置核心bus音讯总线, 配置刷新sleuth+zipkin链路跟踪SpringCloud与Dubbo比照DubboDubbo只是一个近程调用(RPC)框架默认基于长连贯,反对多种序列化格局 Spring Cloud框架集提供了一整套微服务解决方案(全家桶)基于http调用, Rest API

September 22, 2020 · 1 min · jiezi

关于springcloud:SpringCloud源码解析-Eureka原理探究

本文通过浏览Eureka源码,分享Eureka的实现原理。本文次要梳理Eureka整体设计及实现,并不一一列举Eureka源码细节。 源码剖析基于Spring Cloud Hoxton,Eureka版本为1.9 Eureka分为Eureka Client,Eureka Server,多个Eureka Server节点组成一个Eureka集群,服务通过Eureka Client注册到Eureka Server。 CAP实践指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。 因为分布式系统中必须保障分区容错性,因而咱们只能在A和C之间进行衡量。Zookeeper保障的是CP, 而Eureka则是保障AP。为什么呢?在注册核心这种场景中,可用性比一致性更重要。作为注册核心,其实数据是不常常变更的,只有服务公布,机器高低线,服务扩缩容时才变更。因而Eureka抉择AP,即便出问题了,也返回旧数据,保障服务能(最大水平)失常调用, 避免出现因为注册核心的问题导致服务不可用这种得失相当的状况。所以,Eureka各个节点都是平等的(去中心化的架构,无master/slave辨别),挂掉的节点不会影响失常节点的工作,残余的节点仍然能够提供注册和查问服务。 Eureka ClientEureka 1.9只有引入spring-cloud-starter-netflix-eureka-client依赖,即便不应用@EnableDiscoveryClient或@EnableEurekaClient注解,服务也会注册到Eureka集群。 client次要逻辑在com.netflix.discovery.DiscoveryClient实现,EurekaClientAutoConfiguration中构建了其子类CloudEurekaClient。 定时工作DiscoveryClient#initScheduledTasks办法设置定时工作,次要有CacheRefreshThread,HeartbeatThread,以及InstanceInfoReplicator。 同步服务注册信息缓存在DiscoveryClient#localRegionApps变量中,CacheRefreshThread负责定时从Eureka Server读取最新的服务注册信息,更新到本地缓存。CacheRefreshThread -> DiscoveryClient#refreshRegistry -> DiscoveryClient#fetchRegistry当存在多个Eureka Server节点时,Client会与eureka.client.serviceUrl.defaultZone配置的第一个Server节点同步数据,当第一个Server节点同步失败,才会同步第二个节点,以此类推。 从DiscoveryClient#fetchRegistry能够看到,同步数据有两个办法(1)全量同步由DiscoveryClient#getAndStoreFullRegistry办法实现,通过Http Get调用Server接口apps/,获取Server节点中所有服务注册信息替换DiscoveryClient#localRegionApps 留神:Client申请Server端的服务,都是通过EurekaHttpClient接口发动,该接口实现类EurekaHttpClientDecorator通过RequestExecutor接口将申请委托给其余EurekaHttpClient实现类,并提供execute办法给子类实现扩大解决(该扩大解决能够针对每一个EurekaHttpClient办法,相似AOP)。子类RetryableEurekaHttpClient#execute中,会获取eureka.client.service-url.defaultZone中配置的地址,通过TransportClientFactory#newClient,结构一个RestTemplateTransportClientFactory,再真正发动申请。 (2)增量同步由DiscoveryClient#getAndUpdateDelta办法实现,通过Http Get调用Server接口apps/delta,获取最新ADDED、MODIFIED,DELETED操作,更新本地缓存。如果获取最新操作失败,则会发动全量同步。 配置:eureka.client.fetch-registry,是否定时同步信息,默认trueeureka.client.registry-fetch-interval-seconds,距离多少秒同步一次服务注册信息,默认30 心跳HeartbeatThread -> DiscoveryClient#renew -> EurekaHttpClient#sendHeartBeat通过Http Put调用Server接口apps/{appName}/{instanceId}appName是服务的spring.application.name,instanceId是服务IP加服务端口。 留神:如果Server返回NOT_FOUND状态,则从新注册。 配置:eureka.client.register-with-eureka,以后利用是否注册到Eureka集群,默认trueeureka.instance.lease-renewal-interval-in-seconds,距离多少秒发送一次心跳,默认30 注册DiscoveryClient#构造函数 -> DiscoveryClient#register通过Http Post调用Server接口apps/{appName},发送以后利用的注册信息到Server。配置:eureka.client.register-with-eureka,以后利用是否注册到Eureka集群,默认trueeureka.client.should-enforce-registration-at-init,是否在初始化时注册,默认false InstanceInfoReplicatorInstanceInfoReplicator工作会去监测利用本身的IP信息以及配置信息是否产生扭转,如果产生扭转,则会从新发动注册。配置:eureka.client.initial-instance-info-replication-interval-seconds,距离多少秒查看一次本身信息,默认40 下线EurekaClientAutoConfiguration配置了CloudEurekaClient的销毁办法 @Bean(destroyMethod = "shutdown")DiscoveryClient#shutdown办法实现下线的解决工作,包含勾销定时工作,调用unregister办法(通过Http Delete调用Server接口apps/{appName}/{id}),勾销监控工作等 Eureka Server@EnableEurekaServer引入EurekaServerMarkerConfiguration,EurekaServerMarkerConfiguration构建EurekaServerMarkerConfiguration.Marker。EurekaServerAutoConfiguration会在Spring上下文中存在EurekaServerMarkerConfiguration.Marker时失效,结构Server端组件类。 Eureka Server也要应用DiscoveryClient,拉取其余Server节点的服务注册信息或者将本身注册到Eureka集群中。 启动同步Server启动时,须要从相邻Server节点获取服务注册信息,同步到本身内存。 Server的服务注册信息寄存在AbstractInstanceRegistry#registry变量中,类型为ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>。外层Map Key为appName,外层Map Key为instanceId,Lease代表Client与Server之间维持的一个契约。InstanceInfo保留具体的服务注册信息,如instanceId,appName,ipAddr,port等。 EurekaServerBootstrap是Server端的启动疏导类,EurekaServerInitializerConfiguration实现了Lifecycle接口,start办法调用eurekaServerBootstrap.contextInitialized实现Server端初始化。eurekaServerBootstrap.contextInitialized -> EurekaServerBootstrap#initEurekaServerContext -> PeerAwareInstanceRegistryImpl#syncUp -> AbstractInstanceRegistry#registerPeerAwareInstanceRegistryImpl#syncUp调用DiscoveryClient#getApplications办法,获取相邻server节点的所有服务注册信息,再调用AbstractInstanceRegistry#register办法,注册到AbstractInstanceRegistry#registry变量中。 ...

September 19, 2020 · 2 min · jiezi

关于springcloud:架构设计-基于Seata中间件微服务模式下事务管理

源码地址:GitHub·点这里 || GitEE·点这里 一、Seata简介1、Seata组件Seata是一款开源的分布式事务解决方案,致力于提供高性能和简略易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA、XA事务模式,为用户打造一站式的分布式解决方案。 2、反对模式AT 模式 基于反对本地 ACID 事务的关系型数据库。Java利用,通过 JDBC 拜访数据库。一阶段:业务数据和回滚日志记录在同一个本地事务中提交,开释本地锁和连贯资源。 二阶段:提交异步化,十分疾速地实现。回滚通过一阶段的回滚日志进行反向弥补。 TCC模式 一个分布式的全局事务,整体是两阶段提交的模型,全局事务是由若干分支事务组成的,分支事务要满足两阶段提交的模型要求,即须要每个分支事务都具备本人的: 一阶段 prepare 行为 二阶段 commit 或 rollback 行为 Saga模式 Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当呈现某一个参与者失败则弥补后面曾经胜利的参与者,一阶段正向服务和二阶段弥补服务都由业务开发实现。 XA模式 XA是一个分布式事务协定,对业务无侵入的分布式事务解决方案,XA提交协定须要事务参与者的数据库反对,XA事务具备强一致性,在两阶段提交的整个过程中,始终会持有资源的锁,性能不现实的毛病很显著。 二、服务端部署1、下载组件包1.2版本:seata-server-1.2.0.zip 解压目录 bin:寄存服务端运行启动脚本;lib:寄存服务端依赖的资源jar包;conf:配置文件目录。2、批改配置file.conf配置 mode:db 即应用数据库存储事务信息,这里还能够抉择file存储形式。 file模式为单机模式,全局事务会话信息内存中读写并长久化本地文件root.data,性能较高; db模式为高可用模式,全局事务会话信息通过db共享,相应性能差些; redis模式Seata-Server 1.3及以上版本反对,性能较高,存在事务信息失落危险,请提前配置适合以后场景的redis长久化配置. store { ## store mode: file、db mode = "db" db { datasource = "druid" dbType = "mysql" driverClassName = "com.mysql.jdbc.Driver" url = "jdbc:mysql://127.0.0.1:3306/seata_server" user = "root" password = "123456" minConn = 5 maxConn = 30 globalTable = "global_table" branchTable = "branch_table" lockTable = "lock_table" queryLimit = 100 maxWait = 5000 }}registry.conf配置 ...

September 14, 2020 · 2 min · jiezi

关于springcloud:SpringCloud源码解析-Spring-Cloud-Sleuth原理探究

本文分享spring cloud sleuth如何构建申请调用链路,并上报zipkin。如果大家在应用spring cloud sleuth时遇到traceId失落,上报zipkin失败等问题,心愿本文能够给大家一个思路。源码剖析基于Spring Cloud Hoxton,Spring Cloud Sleuth版本为2.2.0.RELEASE 首先明确几个概念Span:一个工作单元,比方一次RPC(Http)申请过程,其SpanId变量应用惟一的64位ID标识一个Span,Span还有其余数据,如形容,工夫戳,Annotation(tags)。Trace:一条申请调用链路组成的span汇合,相似于tree构造,同样,TraceId变量标识一个Trace。 Annotation:用于记录事件理论产生工夫,可用于zipkin统计和绘制报表。cs:Client Sent,客户端发动一个申请工夫sr:Server Received,服务端接管到申请工夫ss:Server Sent,服务端返回响应工夫cr:Client Received,客户端接管到响应工夫 SpringBoot 2开始应用了brave框架实现日志收集,brave是zipkin官网提供的java版本客户端,它将收集的跟踪信息,以Span的模式上报给Zipkin零碎。brave框架具体可见https://github.com/openzipkin...。 上面假如有client,server两个工程,调用链路如下:用户 -> client --> server 本文咱们来探讨以下几个问题 用户调用client时,client如何生成Span信息client调用server时,如何将Span发送到serverserver如何接管cliend的Span信息client,server如何发送Span到zipkin留神,本文是基于SpringMvc+RestTeamplate的申请调用的,而非WebFlux异步调用。 问题1问题1和问题3,都由LazyTracingFilter解决,它在TraceWebServletAutoConfiguration中初始化。 (本文局部源码来自于brave框架)LazyTracingFilter#doFilter -> (brave)TracingFilter#doFilter public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {... // #1 Span span = handler.handleReceive(new HttpServerRequest(httpRequest)); // #2 request.setAttribute(SpanCustomizer.class.getName(), span.customizer()); request.setAttribute(TraceContext.class.getName(), span.context()); Throwable error = null; // #3 Scope scope = currentTraceContext.newScope(span.context()); try { chain.doFilter(httpRequest, httpResponse); } ... finally { // #4 scope.close(); if (servlet.isAsync(httpRequest)) { // we don't have the actual response, handle later servlet.handleAsync(handler, httpRequest, httpResponse, span); } else { // we have a synchronous response, so we can finish the span handler.handleSend(servlet.httpServerResponse(httpRequest, httpResponse), error, span); } }}#1 从Http Request的Header里获取Span数据,如果Header中存在X-B3-TraceId,X-B3-SpanId,X-B3-ParentSpanId属性,就阐明调用链前一个节点曾经生成Span,并传递下来,这时能够间接应用这些Span数据。否则,创立一个新的Span。#2 记录一些Span的属性#3 调用ThreadLocalCurrentTraceContext#newScope,保留以后的Span信息,当利用向下传递Span信息时须要应用这些信息。这里会调用ThreadLocalCurrentTraceContext#decorateScope,它会获取上下文的ScopeDecorator,并触发其decorateScope办法。SleuthLogAutoConfiguration构建了默认的ScopeDecorator -- Slf4jScopeDecorator,它会获取Span中的traceId,parentId,spanId,搁置MDC中,不便日志打印。TraceAutoConfiguration负责构建ThreadLocalCurrentTraceContext,并将Slf4jScopeDecorator增加到ThreadLocalCurrentTraceContext#decorateScope中#4 敞开Scope,记录server finishTimestamp(ss)。 ...

September 12, 2020 · 2 min · jiezi

关于springcloud:SpringCloud源码解析-Zuul实现原理

本文次要分享Zuul的应用和原理。 因为工作须要,我第一个深刻理解的SpringCloud组件其实是Zuul,心愿这篇文章能说分明Zuul的相干实现原理。 Zuul通过ZuulFilter对申请进行拦挡,过滤,转发等操作。ZuulFilter也是提供给咱们扩大的接口。ZuulFilter有四种类型pre:在申请被路由之前调用,次要负责过滤,request申请解决等工作route:负责申请路由,转发工作post:负责发送响应到客户端error:下面流程产生谬误时被调用,做一些异样善后工作 Zuul的整体流程在ZuulServlet或ZuulServletFilter,这两个类性能根本一样,默认应用的是ZuulServlet,在ZuulServerAutoConfiguration初始化。ZuulServlet#service public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException { try { init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); RequestContext context = RequestContext.getCurrentContext(); context.setZuulEngineRan(); try { preRoute(); } catch (ZuulException e) { error(e); postRoute(); return; } try { route(); } catch (ZuulException e) { error(e); postRoute(); return; } try { postRoute(); } catch (ZuulException e) { error(e); return; } } catch (Throwable e) { error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName())); } finally { RequestContext.getCurrentContext().unset(); }}整体流程如下 ...

September 12, 2020 · 3 min · jiezi

关于springcloud:SpringCloudSpringCloudAlibaba学习笔记

服务注册核心eurekaap 高可用 分布式容错 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>eureka: instance: hostname: eureka7003.com #eureka服务端的实例名称 instance-id: payment8001 prefer-ip-address: true client: register-with-eureka: false #false示意不向注册核心注册本人。 fetch-registry: false #false示意本人端就是注册核心,我的职责就是保护服务实例,并不需要去检索服务 service-url: #集群指向其它eureka #defaultZone: http://eureka7002.com:7002/eureka/ #单机就是7001本人 defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ #server: #敞开自我爱护机制,保障不可用服务被及时踢除 #enable-self-preservation: false #eviction-interval-timer-in-ms: 2000Ribbon 启用负载平衡@EnableEurekaServer@EnableDiscoveryClient@LoadBalancedpublic RestTemplate getTemp() { return new RestTemplate();}zookeppercp 强统一 分布式容错 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions></dependency><dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.1</version></dependency>spring: application: name: cloud-zoo-consumer-order cloud: zookeeper: connect-string: 192.168.10.58:2181@SpringBootApplication@EnableDiscoveryClientconsulcp 强统一 分布式容错 ...

August 25, 2020 · 4 min · jiezi

关于springcloud:Spring-Cloud微服务实战

Spring Cloud微服务实战 下载地址: https://pan.baidu.com/s/1GThtjsNrcakbVD8gyY0x0Q 扫码上面二维码关注公众号回复100016 获取分享码 本书目录构造如下: 第1章基础知识............................................................. 1 什么是微服务架构.......................................................... 1 与单体零碎的区别.......................................................... I 如何施行微服务.............................................................2 为什么抉择Spring Cloud ................................................. 6 Sp门ng Cloud简介.........................................................7 版本阐明·································································8 第2章微服务构建: Spring Boot... ....................................... 11 框架简介................................................................ 12 疾速入r'l .............................................................. 13 我的项目构建与解析..............................................。。。。。... 13 实现RESTful API ........................................................ 17 自定义参数...............................................................22 命令行参数...............................................................23 第3章服务治理: Spring Cloud Eureka .............................................................................. 39 月屈务治理......................................................................................................................................39 Netflix Eureka 40 搭建服务压册核心 41 注册服务提供者..................................................................................................................43 高可用注册核心 46 服务发现与生产 48 Eureka详解..................................................................................................................................51 基础架构..............................................................................................................................52 服务治理机制......................................................................................................................52 源码剖析······························································································································56 配置详解 65 服务汪册类配置 65 服务实例类配置..................................................................................................................67 跨平台反对..................................................................................................................................71 第4章 客户端负载平衡: Spring Cloud Ribbon ................................................................... 73 客户端负载平衡..........................................................................................................................73 RestTemplate详解.......................................................................................................................75 GET申请.............................................................................................................................75 POST申请...........................................................................................................................77 PUT申请..............................................................................................................................79 DELETE申请......................................................................................................................79 第7章 API网关服务: Spring Cloud Zuul ......................................................................... 217 疾速入11 .................................................................................................................................... 219 构建网关............................................................................................................................220 申请路由 .................................221 申请过滤 .................................223 路由详解 .................................226 传统路由配置 .................................226 服务路由配置................................. 228 服务路由的默认规定 .................................229 自定义路由映射规定........................................................................................................229 二: ::: 本地跳转............................................................................................................................234 Cookie与头信息...................................................................................................235 Hystr    ................................................................................................... 235 ix和Ribbo? 反对.................................................................. 236 过滤器详解 ..................................................................238 过滤器 ...................................................................................................238 申请生命周期....................................................................................................................239 外围过滤器 ....................................................................................................................................240 ...

August 13, 2020 · 1 min · jiezi

关于springcloud:SpringCloud-alibaba实战系列文章汇总

个人感觉这是全网比拟齐全,写的比拟好的SpringCloud alibaba系列教程了,举荐给大家! SpringCloud Alibaba微服务实战一 - 根底环境筹备SpringCloud Alibaba微服务实战二 - 服务注册SpringCloud Alibaba微服务实战三 - 服务调用SpringCloud Alibaba微服务实战四 - 版本治理SpringCloud Alibaba微服务实战五 - 限流熔断SpringCloud Alibaba微服务实战六 - 配置隔离SpringCloud Alibaba微服务实战七 - 分布式事务SpringCloud Alibaba微服务实战八 - Seata 整合NacosSpringCloud Alibaba微服务实战九 - Seata 容器化SpringCloud Alibaba微服务实战十 - 服务网关SpringCloud Alibaba微服务实战十一 - Swagger接口文档聚合SpringCloud Alibaba微服务实战十二 - 网关限流SpringCloud Alibaba微服务实战十三 - Oauth2.0平安认证SpringCloud Alibaba微服务实战十四 - SpringCloud Gateway集成Oauth2.0SpringCloud Alibaba微服务实战十五 - SpringCloud 容器化部署SpringCloud Alibaba微服务实战十六 - 2.2.1.RELEASE版本升级SpringCloud Alibaba微服务实战十七 - JWT认证SpringCloud Alibaba微服务实战十八 - Oauth2.0 自定义受权模式SpringCloud Alibaba微服务实战十九 - 集成RBAC受权SpringCloud Alibaba微服务番外篇一 - Swagger自定义主动配置SpringCloud Alibaba微服务番外篇二 - Feign传递Access_Token ...

August 7, 2020 · 1 min · jiezi

关于springcloud:SpringCloud微服务基于Nacos组件整合Dubbo框架

源码地址:GitHub·点这里 || GitEE·点这里 一、根底组件简介1、Dubbo框架Dubbo服务化治理的外围框架,之前几年在国内被宽泛应用,后续因为微服务的架构的崛起,更多的公司转向微服务下成熟的技术栈,然而Dubbo自身的确是十分优良的框架。 常见的利用迭代和降级的过程根本如下: 当利用访问量逐步增大,繁多利用减少机器带来的加速度越来越小,晋升效率的办法之一是将利用拆成互不相干的几个利用,以晋升效率。此时,用于减速前端页面开发的Web框架(MVC)是要害。随着垂直利用越来越多,利用之间交互不可避免,将外围业务抽取进去,作为独立的服务,逐步造成稳固的服务中心,使前端利用能更疾速的响应多变的市场需求。此时,用于进步业务复用及整合的分布式服务框架(RPC)是要害。随同业务倒退,服务越来越多,容量的评估,小服务资源的节约等问题逐步浮现,此时需减少一个调度核心基于拜访压力实时治理集群容量,进步集群利用率。此时,用于进步机器利用率的资源调度和治理核心(SOA)是要害。 而Dubbo框架的外围能力:面向接口的近程办法调用,智能容错和负载平衡,以及服务主动注册和发现。正好能够解决上述业务倒退的痛点。 2、微服务框架SpringCloud是一系列框架的有序汇合。它利用SpringBoot的开发便利性奇妙地简化了分布式系统基础设施的开发,如服务发现注册、配置核心、音讯总线、负载平衡、断路器、数据监控等,都能够用SpringBoot的开发格调做到一键启动和部署。 后续AliCloud微服务系列组件也一直被应用起来,其中最根底的组件Nacos注册核心,更是间接反对Dubbo框架,这样Cloud和Dubbo两大框架就胜利的整合在了一起。 3、Nacos注册核心Nacos注册核心次要用于发现、配置、治理微服务。并且提供一组简略易用的个性集,疾速实现动静服务发现、服务配置、服务元数据及流量治理。 如上图Nacos无缝反对一些支流的开源生态框架,例如SprinCloud,Dubbo两大框架。在AliCloud的系列组件中,还蕴含了Seata,RocketMQ,Sentinel等一系列组件。 二、服务构造图解SpringCloud和Dubbo整合的构造示意图如下,应用的Nacos核心: Provider提供方:提供外围的Dubbo服务接口; Consumer生产方:生产注册的Dubbo服务接口; Nacos注册核心:配置、发现和治理Dubbo服务; 通过上述流程不难发现,不论从架构上看,还是用法过程,基于外围Dubbo框架和微服务原生框架是十分相似,上述流程也遵循这样一个规定:dubbo-server连贯本人的业务库DB,并通过dubbo-facade中接口向外提供服务,如果不同dubbo-server须要拜访其余服务接口,也必须要通过其余服务的facade接口操作,dubbo-client作为接口服务生产端,能够通过facade接口拜访很多业务模块的服务,整体架构档次非常明了。 三、编码案例实现1、案例构造和依赖案例构造 蕴含三个模块:server、facade、client。 外围依赖 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> <version>2.1.1.RELEASE</version></dependency><dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.1.1.RELEASE</version></dependency><dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.1.1.RELEASE</version></dependency>2、服务端配置配置文件 次要是Nacos注册核心和Dubbo两个外围配置。 server: port: 9010spring: application: name: node10-dubbo-server cloud: nacos: discovery: server-addr: http://localhost:8848 config: server-addr: http://localhost:8848 file-extension: yaml# Dubbo服务配置dubbo: scan: base-packages: com.cloud.dubbo.service protocol: name: dubbo port: -1 registry: address: spring-cloud://localhost服务接口实现 这里DubboService即dubbo-facade包中对外提供的接口。 import org.apache.dubbo.config.annotation.Service;import org.slf4j.Logger;import org.slf4j.LoggerFactory;@Servicepublic class DubboServiceImpl implements DubboService { private static final Logger LOGGER = LoggerFactory.getLogger(DubboServiceImpl.class) ; @Override public String getInfo() { LOGGER.info("node10-dubbo-server start ..."); return "node10-dubbo-server"; }}留神:@Service是Dubbo框架中的注解,不是Spring框架的注解。 ...

August 5, 2020 · 1 min · jiezi

关于springcloud:SpringCloud微服务基于Nacos组件整合Dubbo框架

源码地址:GitHub·点这里 || GitEE·点这里 一、根底组件简介1、Dubbo框架Dubbo服务化治理的外围框架,之前几年在国内被宽泛应用,后续因为微服务的架构的崛起,更多的公司转向微服务下成熟的技术栈,然而Dubbo自身的确是十分优良的框架。 常见的利用迭代和降级的过程根本如下: 当利用访问量逐步增大,繁多利用减少机器带来的加速度越来越小,晋升效率的办法之一是将利用拆成互不相干的几个利用,以晋升效率。此时,用于减速前端页面开发的Web框架(MVC)是要害。随着垂直利用越来越多,利用之间交互不可避免,将外围业务抽取进去,作为独立的服务,逐步造成稳固的服务中心,使前端利用能更疾速的响应多变的市场需求。此时,用于进步业务复用及整合的分布式服务框架(RPC)是要害。随同业务倒退,服务越来越多,容量的评估,小服务资源的节约等问题逐步浮现,此时需减少一个调度核心基于拜访压力实时治理集群容量,进步集群利用率。此时,用于进步机器利用率的资源调度和治理核心(SOA)是要害。 而Dubbo框架的外围能力:面向接口的近程办法调用,智能容错和负载平衡,以及服务主动注册和发现。正好能够解决上述业务倒退的痛点。 2、微服务框架SpringCloud是一系列框架的有序汇合。它利用SpringBoot的开发便利性奇妙地简化了分布式系统基础设施的开发,如服务发现注册、配置核心、音讯总线、负载平衡、断路器、数据监控等,都能够用SpringBoot的开发格调做到一键启动和部署。 后续AliCloud微服务系列组件也一直被应用起来,其中最根底的组件Nacos注册核心,更是间接反对Dubbo框架,这样Cloud和Dubbo两大框架就胜利的整合在了一起。 3、Nacos注册核心Nacos注册核心次要用于发现、配置、治理微服务。并且提供一组简略易用的个性集,疾速实现动静服务发现、服务配置、服务元数据及流量治理。 如上图Nacos无缝反对一些支流的开源生态框架,例如SprinCloud,Dubbo两大框架。在AliCloud的系列组件中,还蕴含了Seata,RocketMQ,Sentinel等一系列组件。 二、服务构造图解SpringCloud和Dubbo整合的构造示意图如下,应用的Nacos核心: Provider提供方:提供外围的Dubbo服务接口; Consumer生产方:生产注册的Dubbo服务接口; Nacos注册核心:配置、发现和治理Dubbo服务; 通过上述流程不难发现,不论从架构上看,还是用法过程,基于外围Dubbo框架和微服务原生框架是十分相似,上述流程也遵循这样一个规定:dubbo-server连贯本人的业务库DB,并通过dubbo-facade中接口向外提供服务,如果不同dubbo-server须要拜访其余服务接口,也必须要通过其余服务的facade接口操作,dubbo-client作为接口服务生产端,能够通过facade接口拜访很多业务模块的服务,整体架构档次非常明了。 三、编码案例实现1、案例构造和依赖案例构造 蕴含三个模块:server、facade、client。 外围依赖 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> <version>2.1.1.RELEASE</version></dependency><dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.1.1.RELEASE</version></dependency><dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.1.1.RELEASE</version></dependency>2、服务端配置配置文件 次要是Nacos注册核心和Dubbo两个外围配置。 server: port: 9010spring: application: name: node10-dubbo-server cloud: nacos: discovery: server-addr: http://localhost:8848 config: server-addr: http://localhost:8848 file-extension: yaml# Dubbo服务配置dubbo: scan: base-packages: com.cloud.dubbo.service protocol: name: dubbo port: -1 registry: address: spring-cloud://localhost服务接口实现 这里DubboService即dubbo-facade包中对外提供的接口。 import org.apache.dubbo.config.annotation.Service;import org.slf4j.Logger;import org.slf4j.LoggerFactory;@Servicepublic class DubboServiceImpl implements DubboService { private static final Logger LOGGER = LoggerFactory.getLogger(DubboServiceImpl.class) ; @Override public String getInfo() { LOGGER.info("node10-dubbo-server start ..."); return "node10-dubbo-server"; }}留神:@Service是Dubbo框架中的注解,不是Spring框架的注解。 ...

August 5, 2020 · 1 min · jiezi

关于springcloud:使用springcloud-alibaba搭建的微服务系统

1.git仓库地址https://gitee.com/QingXinDeChengXuYuan/xiayuedu.git2.阐明注册核心及配置核心应用nacos网关应用springcloud gateway服务调用应用 openfeignxiayu-admin-gateway 后盾治理网关次要负责后盾接口,管理员token生成等等逻辑同公共网关xiayu-common 专用模块:次要是工具类,配置类等等redis采纳哨兵模式,并且创立缓存管理器,redisson客户端kafka 音讯确认形式应用all,音讯幂等性通过数据库进行确认数据库应用一主一从国际化,主动注入MessageSource即可权限管制应用spring security,权限信息存储在token,基于角色信息管制权限分布式id应用雪花算法每个服务的nodeId,应用zookeeper的长期程序节点可依据配置文件项,设置开启与敞开每次申请的traceId通过以后线程局部变量+1封装CommonResponse、CommonRequest和异样加密工具类xiayu-integration 发送短信,邮件服务 //todoxiayu-job 定时工作服务定义了定时工作模版,每个定时工作须要分布式锁xiayu-public-gateway 用户网关服务网关服务次要对token进行签发,签发之后会保留到redis中,签发是通过注册或登录接口返回response的值进行判断的token验证,首先查看redis中是否存在每次申请,验证token并更新过期工夫xiayu-user 用户服务用户注册登录,角色权限依照需要能够额定增加服务

August 5, 2020 · 1 min · jiezi

关于springcloud:使用springcloud-alibaba搭建的微服务系统

1.git仓库地址https://gitee.com/QingXinDeChengXuYuan/xiayuedu.git2.阐明注册核心及配置核心应用nacos网关应用springcloud gateway服务调用应用 openfeignxiayu-admin-gateway 后盾治理网关次要负责后盾接口,管理员token生成等等逻辑同公共网关xiayu-common 专用模块:次要是工具类,配置类等等redis采纳哨兵模式,并且创立缓存管理器,redisson客户端kafka 音讯确认形式应用all,音讯幂等性通过数据库进行确认数据库应用一主一从国际化,主动注入MessageSource即可权限管制应用spring security,权限信息存储在token,基于角色信息管制权限分布式id应用雪花算法每个服务的nodeId,应用zookeeper的长期程序节点可依据配置文件项,设置开启与敞开每次申请的traceId通过以后线程局部变量+1封装CommonResponse、CommonRequest和异样加密工具类xiayu-integration 发送短信,邮件服务 //todoxiayu-job 定时工作服务定义了定时工作模版,每个定时工作须要分布式锁xiayu-public-gateway 用户网关服务网关服务次要对token进行签发,签发之后会保留到redis中,签发是通过注册或登录接口返回response的值进行判断的token验证,首先查看redis中是否存在每次申请,验证token并更新过期工夫xiayu-user 用户服务用户注册登录,角色权限依照需要能够额定增加服务

August 5, 2020 · 1 min · jiezi

关于springcloud:SpringCloud-应用在-Kubernetes-上的最佳实践-线上发布可回滚

简介: 本篇是《SpringCloud 利用在 Kubernetes 上的最佳实际》系列文章的第七篇,次要介绍了新性能上线时,如何尽快缩小对线上用户的影响?公布零碎须要提供回滚到前一个或前几个版本的能力,达到疾速复原线上业务的目标。 通常一次利用的线上公布就示意了一次新性能的上线。在上线过程中,可能产生一些非预期的状况,如新版本软件有bug,或者性能不达预期,就会影响了线上客户的应用。 为了尽快缩小对线上用户的影响,公布零碎须要提供回滚到前一个或前几个版本的能力。达到疾速复原线上业务的目标。 从利用的部署变更档次来看,能够分为以下三层: 所以对应了以下的回滚场景: 回滚利用内的配置,实用于因为利用配置变更导致的问题。此时如果利用可能实现动静的配置加载,通过回滚配置就能实现业务复原的目标。否则须要重启利用回滚利用代码的版本,实用于代码批改导致的问题。此时须要回滚代码的版本(镜像),重启利用。回滚利用的工作负载与运维配置(基础设施层)。利用内配置回滚利用内的配置通常与利用零碎须要或业务逻辑配置无关,如配置数据库的连贯信息,业务规定配置等,配置的变更也很容易造成线上零碎的问题,个别的做法是通过configmap或properties配置文件来实现,这种状况下很难做到动静推送和回滚的能力,因为回滚须要保留不同版本的配置。 通过 散布配置管理(ACM)(EDAS默认反对)很容易实现配置的集中管理,回滚和灰度,分布式推送,审计等性能。能够在ACM或EDAS的管制台上实现一键回滚,如下图所示: 利用代码回滚Deployment是一种常见部署的利用的workload,回滚代码其实对应了回滚对应代码版本的镜像,其实就是对应就是Deployment的回滚,Kubernetes能够通过以下形式反对Deployment的回滚。 Deployment回滚在一个规范的 Kubernetes 体系下,如果呈现新版本的pod不能失常工作,须要将deployment回滚到历史版本,Kubernetes 提供了原生的反对;其原理是在默认状况下,kubernetes 会将历史记录保留在零碎中,间接应用应用 rollout 命令回滚即可,如下:。 回滚到上一个版本kubectl rollout undo deployment.v1.apps/{deployment.name}回滚到指定的版本 能够通过kubectl rollout history查看历史的版本kubectl rollout history deployment.v1.apps/{deployment.name}能够通过以下命令回滚到指定的版本kubectl rollout undo deployment.v1.apps/{deployment.name} --to-revision={version}EDAS中利用回滚而在 EDAS 中,联合了原生的能力做了更丰盛的白屏的体验,咱们就公布过程中和公布实现后两个场景别离形容。 公布过程中回滚公布过程中回滚是指在利用公布过程中,就发现了问题,须要将利用回滚到前一个版本。此时的操作就是中断公布流程,将曾经降级实现后或正在降级的服务器回滚到前一个版本。 EDAS在每次变更时候,能够间接中断公布流程,一键回滚。如下图所示: 另外,EDAS公布零碎提供单批,分批,金丝雀灰度等多种公布模式,在分批和金丝雀灰度的公布的时候,EDAS还提供不同批次的监控信息,如零碎指标,利用指标,利用异样检测等能力,提供疾速发现问题能力,如果存在问题,能够立刻进行回滚。如下图所示: 咱们举荐的形式也是在公布过程中尽量应用分批和金丝雀的能力,以将公布引起的不可用降至最小。 公布实现后回滚公布后回滚是指一次部署过程曾经实现,蕴含部署胜利或失败。这个时候,能够通过部署历史的版本来实现回滚的性能。EDAS 默认会存储最多十个部署过的版本,如下图所示: 通过以上的性能,基本上能够笼罩利用在上线过程中须要回滚的场景。缩小因为零碎公布出问题,造成零碎性能应用上的影响。 利用主动回滚从下面的介绍,能够看到回滚的操作都是人工进行的,其实在一些场景里,能够依据一些监控指标,如CPU,load,内存等维度,疾速发现问题,就能做到主动回滚,能够可能更快地复原零碎。在 Kubernetes 的体系中,Flagger(https://github.com/weaveworks/flagger) 就是可能实现主动回滚的一个很好的工具。 利用工作负载和运维配置回滚下面介绍了利用内配置和利用代码回滚的形式,在常见的变更中,还存在工作负载及运维配置的变更,如更改工作负载的类型,变更JVM参数,日志配置, 弹性伸缩等。其中JVM参数等通常能够随Deployment进行回滚,然而相似Kubernetes service,日志,弹性伸缩规定等这些基础设施和运维相干的能力回滚就很难做到了。须要将利用的代码,工作负载,运维配置等实现配置化来实现回滚的能力。 这里举荐阿里巴巴与微软联结提出的OAM(Open Application Model)的标准,他定义了利用的对立交付模型. 在OMA中,一个应用程序蕴含以下几个外围的理念: Component: 是指利用中的组件,能够是利用运行所依赖的服务如MySQL数据库等,也能够是利用的自身,如Spring cloud的服务提供者。能够通过Component的定义标准来编写一个组件。Trait:是指利用的运维特色,形容了利用部署在具体环境中的运维特色,比方弹性伸缩规定和Ingress配置等,这些运维特色会利用到具体的组件上。Applicationconfiguration:是将Components和traits组装成一个真正能运行起来利用的定义。这个配置文件就是OAM标准中的一个申明式是API,通过它就能实例化出对应的,实在运行的利用。一个OAM的利用例子如下: apiVersion: core.oam.dev/v1alpha2kind: ApplicationConfigurationmetadata: name: springcloud-provider-deployment annotations: version: v1.0.0 description: "Description of this deployment"spec: components: - componentName: springcloud-provider-component parameterValues: - name: PARAMETER_NAME value: SUPPLIED_VALUE - name: ANOTHER_PARAMETER value: "AnotherValue" traits: - name: manualscaler.core.oam.dev version: v1 spec: replicaCount: 3 scopes: - scopeRef: apiVersion: core.oam.dev/v1alpha2 kind: NetworkScope name: example-vpc-network通过OAM的ApplicationConfiguration这份配置,就能形容线上真正运行的利用,结合能将配置版本化的零碎,如Git,ACM等,采纳对应的ApplicationConfiguration的版本,就能实现利用的一键回滚。EDAS里就是通过OAM标准来治理Kubernetes的利用,联合OAM申明式API的形式,EDAS里将会实现多种利用回滚的场景,为线上业务保驾护航。 ...

August 4, 2020 · 1 min · jiezi

关于springcloud:基于SpringCloud的enum枚举值国际化处理实践

背景选用SpringCloud框架搭建微服务做业务后盾利用时,会波及到大量的业务状态值定义,个别惯例做法是: 长久层(数据库)存储int类型的值后盾零碎里用浏览性好一点儿的常量将int类型的值做一层映射前端(app或浏览器)同样定义一套常量去映射这些关系前端调用后盾零碎的接口时,应用常量定义的int类型进行提交源于长久层存储的优化规定,int类型要比varchar类型效率高很多,这套做法也是大家接受度十分高的。 只是这里有一个不是很不便的中央:状态值映射的常量定义波及前端和后盾两局部,沟通的老本是一方面,另外如果状态值有变动,须要两组人员同时批改。 预期指标在保障长久层的int类型存储状态值的前提下,次要是思考业务状态的可浏览性问题和多处批改的问题,可浏览性问题一部分能够通过前后端人员定义常量来解决,但接口调试时还是间接应用int类型,这部分的可浏览性问题还是存在,多处批改的问题须要重点解决。 本篇举荐的计划: 长久层(数据库)存储没用原先的int类型值,这点放弃不变后盾零碎应用enum定义业务状态,不同的业务状态集能够由多个enum来实现,enum反对国际化前端展现enum国际化的文本内容前端调用后盾零碎接口时,应用enum国际化的文本内容进行提交后盾接管enum国际化的文本内容转换成int类型值,存储在数据库计划的长处: 长久层原有的设计,效率性问题不受影响业务状态的定义、映射全副内聚到后盾零碎,后续有状态值变动时,只需后盾做相应批改即可前端展现的内容,接口传输的内容均为浏览性更好的文本,并且反对国际化计划的毛病: 后盾零碎存储、读取状态值时,须要用enum进行转换通信传输的内容报文比原有的int类型大一点点计划实际实际原理此实际计划次要蕴含三局部: Enum类应用Jackson进行JSON序列化和反序列化Enum枚举项的messages国际化解决Enum的定义Enum自定义序列化和反序列化先定义Enum国际化类,自定义Enum的序列化和反序列化类,并应用注解@JsonSerialize、@JsonDeserialize注册到Spring的ObjectMapper中 @JsonDeserialize(using = DescEnumDeserializer.class)@JsonSerialize(using = DescEnumSerializer.class)public interface I18NEnum { /** * 获取枚举形容 * * @return */ String getDesc();}参考一下自定义的序列化实现: /** * @author huangying */public class DescEnumSerializer extends JsonSerializer<I18NEnum> { @Override public void serialize(I18NEnum value, JsonGenerator gen, SerializerProvider serializers) throws IOException { // 按类名+枚举值名称拼接配置文件key,全副大写解决 String key = value.getClass().getSimpleName() + "." + StringUtils.upperCase(value.toString()); // I18NUtil为国际化解决工具类 String data = I18NUtil.get(key, value.getDesc()); gen.writeString(data); }}自定义的反序列化实现: ...

July 31, 2020 · 2 min · jiezi

关于springcloud:Spring-Cloud1入门总结

Spring Cloud 入门总结看过的最棒的spring cloud入门简介文章首先我给大家看一张图,如果大家对这张图有些中央不太了解的话,我心愿你们看完我这篇文章会豁然开朗。 总体架构 什么是Spring cloud构建分布式系统不须要简单和容易出错。Spring Cloud 为最常见的分布式系统模式提供了一种简略且易于承受的编程模型,帮忙开发人员构建有弹性的、牢靠的、协调的应用程序。Spring Cloud 构建于 Spring Boot 之上,使得开发者很容易动手并疾速利用于生产中。官网果然官网,介绍都这么一板一眼的。 我所了解的 Spring Cloud 就是微服务零碎架构的一站式解决方案,在平时咱们构建微服务的过程中须要做如 服务发现注册 、配置核心 、音讯总线 、负载平衡 、断路器 、数据监控 等操作,而 Spring Cloud 为咱们提供了一套繁难的编程模型,使咱们能在 Spring Boot 的根底上轻松地实现微服务项目的构建。 Spring Cloud 的版本当然这个只是个题外话。 Spring Cloud 的版本号并不是咱们通常见的数字版本号,而是一些很奇怪的单词。这些单词均为英国伦敦地铁站的站名。同时依据字母表的程序来对应版本工夫程序,比方:最早 的 Release 版本 Angel,第二个 Release 版本 Brixton(英国地名),而后是 Camden、 Dalston、Edgware、Finchley、Greenwich、Hoxton。 Spring Cloud 的服务发现框架——EurekaEureka是基于REST(代表性状态转移)的服务,次要在AWS云中用于定位服务,以实现负载平衡和中间层服务器的故障转移。咱们称此服务为Eureka服务器。Eureka还带有一个基于Java的客户端组件Eureka Client,它使与服务的交互变得更加容易。客户端还具备一个内置的负载平衡器,能够执行根本的循环负载平衡。在Netflix,更简单的负载均衡器将Eureka包装起来,以基于流量,资源应用,谬误条件等多种因素提供加权负载平衡,以提供杰出的弹性。总的来说,Eureka 就是一个服务发现框架。何为服务,何又为发现呢? 举一个生存中的例子,就比方咱们平时租房子找中介的事件。 在没有中介的时候咱们须要一个一个去寻找是否有屋宇要出租的房东,这显然会十分的费劲,一你找凭一个人的能力是找不到很多房源供你抉择,再者你也懒得这么找上来(找了这么久,没有适合的只能将就)。这里的咱们就相当于微服务中的 Consumer ,而那些房东就相当于微服务中的 Provider 。消费者 Consumer 须要调用提供者 Provider 提供的一些服务,就像咱们当初须要租他们的房子一样。 然而如果只是租客和房东之间进行寻找的话,他们的效率是很低的,房东找不到租客赚不到钱,租客找不到房东住不了房。所以,起初房东必定就想到了播送本人的房源信息(比方在街边贴贴小广告),这样对于房东来说曾经实现他的工作(将房源颁布进来),然而有两个问题就呈现了。第一、其余不是租客的都能收到这种租房音讯,这在事实世界没什么,然而在计算机的世界中就会呈现资源耗费的问题了。第二、租客这样还是很难找到你,试想一下我须要租房,我还须要东一个西一个地去找街边小广告,麻不麻烦? 那怎么办呢?咱们当然不会那么傻乎乎的,第一工夫就是去找 中介 呀,它为咱们提供了对立房源的中央,咱们消费者只须要跑到它那里去找就行了。而对于房东来说,他们也只须要把房源在中介那里公布就行了。 ...

July 31, 2020 · 4 min · jiezi

关于springcloud:springcloud-sleuth学习一

1.什么是分布式链路追踪 随着分布式服务架构的风行,特地是微服务等设计理念在零碎中的利用,业务的调用链越来越简单。相干产品还有skywalking、zipkin 分布式服务跟踪是整个分布式系统中跟踪一个用户申请的过程(包含数据采集、数据传输、数据存储、数据分析、数据可视化),捕捉此类跟踪让咱们构建用户交互背地的整个调用链的视图,这是调试和监控微服务的要害工具。Spring Cloud Sleuth是Spring Cloud为分布式服务跟踪提供的解决方案,有了它,咱们能够: 提供链路追踪,故障疾速定位:能够通过调用链联合业务日志疾速定位错误信息。可视化各个阶段耗时,进行性能剖析各个调用环节的可用性、梳理服务依赖关系以及优化数据分析,优化链路:能够失去用户的行为门路,汇总剖析利用在很多业务场景。2.疾速应用springcloud-sleuth 2.1 springboot启动日志 springboot我的项目启动时日志如下: 当有申请进入时,控制台打印日志如下:(本我的项目没有配置spring.application.name) 2.2 日志含意 第一个值:trace1,它示意利用的名称,也就是配置文件spring.application.name的值。 第二个值:454445a6a7d9ea44,它是SpringCloudSleuth生成的一个ID,称为Trace ID,它用来标识一条申请链路,一条申请链路中蕴含一个Trace ID,多个Span ID。 第三个值:912a7c66c17214e0,它是SpringCloudSleuth生成的另外一个ID,称为Span ID,它示意一个根本的工作单元,比方发送一个http申请。 第四个值:false,示意是否要将该信息输入到Zipkin等服务中来收集和展现。 3. 集成与利用 3.1 与zipkin整合 提供web页面,能够方便快捷的展现申请的残缺生命周期和链式调用,便于疾速定位、剖析、解决问题 3.2 与ELK日志收集零碎整合 日志收集零碎,便于进行日志的收集、剖析与计算 官网链接:https://spring.io/projects/sp...

July 29, 2020 · 1 min · jiezi

SpringCloud-第十一篇-FeignRibbon

1:概述因为Spring Cloud Feign的客户端负载平衡是通过Spring Cloud Ribbon实现的,所以能够间接通过配置Ribbon客户端的形式来自定义各个服务客户端调用的参数2:全局配置ribbon.ConnectTimeout=500 ribbon.ReadTimeOut=50003:指定服务配置userService.ribbon.ConnectTimeout=500 userService.ribbon.ReadTimeout=20004:重试机制userService.ribbon.ConnectTimeout=500userService.ribbon.ReadTimeout=2000userService.ribbon.OkToRetryOnAllOperations=trueuserService.ribbon.MaxAutoRetriesNextServer=2userService.ribbon.MaxAutoRetries=1Ribbon的超时与Hystrix的超时是两个概念。个别须要让hystrix的超时工夫大于Ribbon的超时工夫,否则Hystrix命令超时后,间接熔断,重试机制就没有任何意义了5:参数绑定罕用绑定参数的形式 @RequestParam 绑定单个申请参数值@PathVariable 绑定URI模板变量值;@RequestHeader 绑定申请头数据;@RequestBody 绑定申请的内容区数据并能进行主动类型转换等留神在定义各参数绑定的时候,@RequestParam和@RequestHeader等能够指定参数名称的注解,它们的value值千万不能少。在spring mvc程序中,这些注解会依据指定参数名来作为默认值,然而在fegin中绑定参数必须通过value属性来指明具体的参数名,不然会抛出IllegalStateException异样,value属性不能为空。6:Feign的默认配置概述Spring Cloud的Feign的一个核心概念就是客户端。 每个Feign客户端都是组合的组件的一部分,它们一起工作以按需调用近程服务器,并且该汇合具备将其作为应用@FeignClient正文的参数名称。 SpringCloud应用FeignClientsConfiguration创立一个新的汇合,作为每个命名客户端的ApplicationContext(利用上下文),这蕴含feign.Decoder,feign.Encoder和feign.Contract。 Spring Cloud Netflix默认为Feign提供以下bean:Decoder feignDecoder:ResponseEntityDecoder(其中蕴含SpringDecoder)Encoder feignEncoder:SpringEncoderLogger feignLogger:Slf4jLoggerContract feignContract:SpringMvcContractFeign.Builder feignBuilder:HystrixFeign.BuilderClient feignClient:如果Ribbon启用,则为LoadBalancerFeignClient,否则将应用默认的feign客户端。能够自定义FeignClientsConfiguration以齐全管制这一系列的配置。 7:自定义配置写一个自定义配置类,留神不要放到以后ComponentScan的范畴下,示例如: @Configurationpublic class MyConf {    @Bean    public Contract feignContract() {        return new feign.Contract.Default();    }}定义的是new feign.Contract.Default(),所有在UserService接口中只能应用Feign本人的注解url形式,应用Spring MVC的注解就会报错写好配置后,通过设置@FeignClient的configuration来应用,如下:@FeignClient(value = "userService",configuration=MyConf.class)能够为每个Feign客户端都配置本人的默认配置8: @FeignClient@FeignClient标签的罕用属性如下: name(value):指定FeignClient的名称,如果我的项目应用了Ribbon,name属性会作为微服务的名称,用于服务发现url: url个别用于调试,能够手动指定@FeignClient调用的地址configuration: Feign配置类,能够自定义Feign的Encoder、Decoder、LogLevel、Contractfallback: 定义容错的解决类,当调用近程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口,并应用@Component注解fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性咱们能够实现每个接口通用的容错逻辑,缩小反复的代码path: 定义以后FeignClient的对立前缀,增加到Feign拜访服务的拜访门路上decode404:当产生http 404谬误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException serviceId属性当初已被弃用,有利于name属性。以前,应用url属性,不须要name属性。当初须要应用name 9:Feign和@Primary9.1:概述当应用Feign与Hystrix回退时,在同一类型的ApplicationContext中有多个bean。这将导致@Autowired不起作用,因为没有一个bean标记为主。为了解决这个问题,Spring Cloud Netflix将所有Feign实例标记为@Primary,所以Spring Framework将晓得要注入哪个bean。在某些状况下,这可能是不可取的。要敞开此行为,将@FeignClient的primary属性设置为false,如: @FeignClient(name = "hello", primary = false)10:Feign的HTTP ClientFeign在默认状况下应用的是JDK原生的URLConnection发送HTTP申请,没有连接池,然而对每个地址会放弃一个长连贯,即利用HTTP的persistence connection 。能够用Apache的HTTP Client替换Feign原始的http client, 从而获取连接池、超时工夫等与性能非亲非故的控制能力。Spring Cloud从Brixtion.SR5版本开始反对这种替换,首先在我的项目中申明Apache HTTP Client和feign-httpclient依赖: <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId></dependency><dependency> <groupId>com.netflix.feign</groupId> <artifactId>feign-httpclient</artifactId> <version>8.18.0</version></dependency>而后在application.properties中增加:  ...

July 17, 2020 · 1 min · jiezi

SpringCloud-Docker-K8s微服务集群部署

装置 K8s v18.4筹备两台机器,一台做master,一台做node1.配置yum源(两台机器都做) cd /etc/yum.repos.d/ rm -f \* curl -o CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo curl -o docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repocat <<EOF > /etc/yum.repos.d/kubernetes.repo[kubernetes]name=Kubernetesbaseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64enabled=1gpgcheck=0repo_gpgcheck=0gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpgEOF2.装置docker并设置开启启动(两台机器都做)yum install -y docker-cesystemctl enable docker && systemctl start docker 3.装置kubeadm并设置开启启动,实际上是会主动装置kubelet、kubeadm、kubectl三个(两台机器都做)yum install -y kubeadmsystemctl enable kubelet && systemctl start kubelet 4.初始化kubeadm(只在master机器执行),留神apiserver-advertise-address的ip改成本人的master节点ip,最好ping一下看看有没有通,复制最初的kubeadm join 192.168.71.60:6443 --token...后续会用到kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.71.60 --image-repository mirrorgcrio --service-cidr=10.1.0.0/16 这里有个很诡异的BUG,笔者已经困住这一步好几天,就是这个问题https://github.com/kubernetes...新版本的移除了kubernetes-cni组件,然而新版本国内镜像较少,于是须要下老版本,然而老版本又说没有这个kubernetes-cni,导致很难堪。最初找到了个能用的镜像mirrorgcrio仓库终于下好了。 5.执行完下面命令后,依据输入提醒执行上面语句(只在master机器执行mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config 6.装置网络插件(master)下载文件https://github.com/WillLiaowh...执行文件kubectl apply -f kube-flannel.yml ...

July 10, 2020 · 1 min · jiezi

腾讯T9纯手写基于SpringCloudBootDocker开发源码笔记

这份笔记中的电商平台挪动商城开发+商家治理后盾与sso设计+平台治理后盾开发是基于Spring Cloud+Spring Boot+Docker开发的,同时每个我的项目的源代码也是在笔记当中(已上传GitHub)!这份笔记中的源码曾经全副上传,具体的获取链接在笔记当中。须要收费获取这份腾讯T8手写的源码笔记的敌人文末查看如何获取哦 9 电商平台挪动商城开发(源码已上传GitHub)挪动商城是电商平台一个十分重要的组成部分,它面向终端用户,为用户提供商品浏览、选购、订单查问和集体信息管理等服务,这些服务散布在不同的利用中,这些利用的设计也扩散在各个微服务工程的“wap" 模块中。本章介绍怎么将这些扩散的利用合并在一起应用,组成一个功能完善的挪动商城,体现出微服务架构设计中“合而用之”的概念。对于一个电商平台来说,挪动商城能够说是它的主体局部,它面向宽广的用户群体,所以必须具备极高的稳定性,并且可能适应大流量和高并发调用。上面将各个服务工程的挪动商城设计局部对立集中在-起进行介绍,以使读者对挪动商城的设计有一个全面的意识。 在笔记提供的电商平台实例中,挪动商城的次要性能包含商品展现、分类查问、购物车、订单查问、个人信息5项基本功能。各个性能的实现在以下几个模块中进行开发: 商品微服务工程“goods-microservice" 的“goods-wap" 模块。类目微服务工程“catalog microservice"的“catalog-wap" 模块。订单微服务工程“order-microservice" 的“order-wap" 模块。9.1挪动商城首页设计 9.2应用负载平衡的导航设计 9.3按分类查问设计 9.4商 品详情页设计 9.5购买下单实现 9.6用户登录与账户切换设计 9.6.1用户登录设计 9.6.2切换账号设计 9.7订单查问设计 9.8集成测试 10 商家治理后盾与SSO设计(源码已上传GitHub)在咱们所设计的电商平台实例中,商家是这个平台的配角,商家治理后盾就是专门为这个配角所提供的一个安全可靠的操作平台。在商家治理后盾中,商家能够进行商品治理、订单治理、物流治理、会员治理、评估治理等各个方面的管理工作。而这些治理及其服务性能的设计,别离由不同的微服务工程所实现,并通过不同利用进行部署。当初咱们要做的就是怎么将这些散布在不同利用之中的治理性能,组成一个具备 雷同的访问控制设计的治理后盾。通过应用单点登录设计就能够将这种扩散的利用通过统- -的权限治理,造成一个有机整体。 单点登录( Single Sign On,SSO )设计能够为分布式环境中的不同利用,提供一个对立的登录认证和受权治理。通过统-的受权认证, 商家管理员只有在任何一个利用之中登录一次,就能够失去应用其余利用的权限。所以,不论商家治理后盾的性能由多少个微服务利用组成,这对于一个商家管理员来说,它始终只是一个残缺的平台。商家治理后盾的设计和开发次要由商家治理开发和SsO开发两局部组成。其中,商家治理次要蕴含了商家及其权限体系的设计。 其中,商家及其权限体系的设计由“merchant object"、“merchant-domain”、“merchant-restapi"、“merchant-client"、“merchant-web” 等模块所组成。单点登录的开发由“merchant-sso”模块和“merchant-security" 模块组成。 10.1商家权限管理体系设计及开发 10.1.1商家权限体系建模10.1.2商家权限体系的长久化设计10.1.3商家权限体系的畛域服务开发10.2商家治理微服务开发 10.2.1商家领城服务层单元测10.2.2商家服务的接口开发10.3SSO设计 10.3.1SSO根本配置10.3.2 在SSO中应用商家的权限体系10.3.3用户登录设计10.3.4无关验证码的阐明10.3.5 SSO的主页设计10.3.6OAuth2服务端设计10.4SSO客户端设计 10.4.1客户端的项目管理配置10.4.2客户端的平安治理配置10.4.3权限验证实现原理10.4.4如何在利用中接入SSO10.4.5无关跨站申请伪造进攻的相干设置10.4.6依据用户权限 主动调配菜单 11 平台治理后盾开发(源码已上传GitHub)平台治理后盾是为电商平台的经营方提供服务的,它次要蕴含商家治理和一些公共配置管理的性能。在商家治理的设计中,包含商家的注册、审核和商家用户的权限治理,以及菜单配置管理等性能。除了一些公共治理性能的设计之外,平台自身的平安治理设计也是一项开发的内容。另外,无关商品类目标治理也应该纳入平台的治理领域之中,这样对整个平台类目设置能力有一个对立的标准。 平台治理后盾的开发次要蕴含两大部分的内容:-局部是治理后盾自身的权限治理设计;另一部分是商家及其权限的治理。 11.1平台治理后盾畛域设计 11.1.1畛域实体建模11.1.2实体的行为设计11.1.3畛域服务开发11.1.4畛域服务单元测试11.2平台治理后盾访问控制设计 11.2.1应用平台治理的用户体系11.2.2权限治理设计11.3 商家的注册设计 11.4商家菜单体系治理开发 11.4.1 分类菜单治理开发11.4.2 模块菜单治理开发11.4.3拜访资源管理开发11.5商家角色治理开发 当然上述的内容属于笔记当中的实际局部,上面我将会把笔记中的具体内容目录列举进去,这份笔记不仅教你怎么去搭建架构,教你如何如开发我的项目,还包含课前期的运维,属于很全面的内容!心愿大家通过这份笔记的学习,能够有一个不错的晋升! 第一章节 第二章节 第三章节 第四章节 第五章节+第六章节 ...

July 10, 2020 · 1 min · jiezi

SpringCloud-Alibaba微服务实战十七-JWT认证

概述在 OAuth2 体系中认证通过后返回的令牌信息分为两大类:不通明令牌(opaque tokens) 和 通明令牌(not opaque tokens)。 不通明令牌 就是一种无可读性的令牌,一般来说就是一段一般的 UUID 字符串。应用不通明令牌会升高零碎性能和可用性,并且减少提早,因为资源服务不晓得这个令牌是什么,代表谁,须要调用认证服务器获取用户信息接口,如下就是咱们在资源服务器中的配置,须要指明认证服务器的接口地址。 security: oauth2: resource: user-info-uri: http://localhost:5000/user/current/get id: account-service通明令牌的典型代表就是 JWT 了,用户信息保留在 JWT 字符串中,资源服务器本人能够解析令牌不再须要去认证服务器校验令牌。 之前的章节中咱们是应用了不通明令牌access_token,但思考到在微服务体系中这种中心化的受权服务会成为瓶颈,本章咱们就应用jwt来替换之前的access_token,专(zhuang)业(bi)点就叫去中心化。 jwt 是什么Json web token (JWT), 是为了在网络应用环境间传递申明而执行的一种基于JSON的凋谢规范(RFC 7519)。该token被设计为紧凑且平安的,特地实用于分布式站点的单点登录(SSO)场景。JWT的申明个别被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也能够减少一些额定的其它业务逻辑所必须的申明信息,该token也可间接被用于认证,也可被加密。简略点说就是一种固定格局的字符串,通常是加密的; 它由三局部组成,头部、载荷与签名,这三个局部都是json格局。 Header 头部:JSON形式形容JWT根本信息,如类型和签名算法。应用Base64编码为字符串Payload 载荷: JSON形式形容JWT信息,除了规范定义的,还能够增加自定义的信息。同样应用Base64编码为字符串。 iss: 签发者sub: 用户aud: 接管方exp(expires): unix工夫戳形容的过期工夫iat(issued at): unix工夫戳形容的签发工夫Signature 签名: 将前两个字符串用 . 连贯后,应用头部定义的加密算法,利用密钥进行签名,并将签名信息附在最初。JWT能够应用对称的加密密钥,但更平安的是应用非对称的密钥,本篇文章应用的是对称加密。 代码批改数据库原来应用access_token的时候咱们建设了7张oauth2相干的数据表 应用jwt的话只须要在数据库存储一下client信息即可,所以咱们只须要保留数据表oauth_client_details。 其余数据表已不再须要,大家能够删除。 认证服务 AuthorizationServerConfig批改 AuthorizationServerConfig 中TokenStore的相干配置@Beanpublic TokenStore tokenStore() { //return new JdbcTokenStore(dataSource); return new JwtTokenStore(jwtTokenEnhancer());}/** * JwtAccessTokenConverter * TokenEnhancer的子类,帮忙程序在JWT编码的令牌值和OAuth身份验证信息之间进行转换。 */@Beanpublic JwtAccessTokenConverter jwtTokenEnhancer(){ JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); // 设置对称签名 converter.setSigningKey("javadaily"); return converter;}之前咱们是将access_token存入数据库,应用jwt后不再须要存入数据库,所以咱们须要批改存储形式。 ...

July 10, 2020 · 2 min · jiezi

个人学习系列-SpringCloud项目搭建

一直想写springcloud的搭建教程,今天就来整理一下吧。搭建项目1. 创建一个空项目 2. 填写相关的信息 3. 新建项目后 4. 搭建服务中心4.1 添加模块 4.2 选择Spring Initializr方式创建 4.3 填写相关的组和工件 4.4 选择相关依赖 4.5 确认好相关内容点击完成 4.6 修改application.yml配置文件#eureka注册中心server: port: 8761 #端口号eureka: instance: hostname: localhost client: #表示十分将自己注册到Eureka Server,默认为true。由于当前应用就是Eureka Server,故而设为false。 register-with-eureka: false #表示是否从Eureka Server获取注册信息,默认为true。因为这是一个单点的Eureka Server,不需要同步其他 的Eureka Server节点的数据,故而设为false fetch-registry: false #置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址,默认是http://localhost:8761/eureka;多个地址可用,分隔 service-url: default-zone: http://${eureka.instance.hostname}:${server.port}/eureka/4.7 启动类添加注解@EnableEurekaServer是声明这是一个Eureka注册中心 @EnableEurekaServer@SpringBootApplicationpublic class ServerCenterApplication { public static void main(String[] args) { SpringApplication.run(ServerCenterApplication.class, args); }}4.8 访问127.0.0.1:8761如上图所示,看到没有任何的服务提供者。 5. 搭建服务提供者5.1 新建模块server-order构建方式和上面一样,就不再赘述了。 5.2 修改配置文件application.yml#eureka-client#端口号server: port: 8082eureka: instance: hostname: localhost #置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址,默认是http://localhost:8761/eureka;多个地址可用,分隔 client: service-url: default-zone: http://localhost:8761/eureka/spring: application: name: service-order5.3 启动类添加注解@EnableEurekaClient@SpringBootApplicationpublic class ServerOrderApplication { public static void main(String[] args) { SpringApplication.run(ServerOrderApplication.class, args); }}注册中心和服务提供者的主要区别就在于注解的不同。 ...

July 7, 2020 · 2 min · jiezi

Spring-Cloud-Alibaba系列五sentinel实现服务限流降级

一、sentinel是什么sentinel的官方名称叫分布式系统的流量防卫兵。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。在Spring Cloud项目中最开始我们使用的是Hystrix,目前已停止更新了。现在Spring Cloud官方推荐的是rensilience4j。当然还有我们今天学习的sentinel。 Sentinel 具有以下特征: 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运 行情况。广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。二、sentinel实现限流2.1 安装sentinel控制台下载地址:https://github.com/alibaba/Se...这里我们直接下载jar包即可,下载后通过命令行启动: java -jar sentinel-dashboard-1.7.2.jar默认端口:8080默认用户名:sentinel默认密码:sentinel启动成功后,我们浏览器访问http://localhost:8080,出现如下界面。 2.2 微服务继承sentinel引入sentinel依赖<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>添加sentinel的相关配置server: port: 7003spring: application: name: sentinel-provider cloud: nacos: discovery: server-addr: 127.0.0.1:8848 sentinel: transport: dashboard: 127.0.0.1:8080提供个接口用来测试限流@SpringBootApplicationpublic class SentinelApplication { public static void main(String[] args) { SpringApplication.run(SentinelApplication.class, args); }}@RestControllerclass TestController{ @GetMapping("/test") public String test(){ return "hello! sentinel!"; }}我们请求几次这个接口后,打开sentinel控制台,就可以实时监控到这个sentinel-provider服务接口调用情况了。 ...

June 28, 2020 · 2 min · jiezi

springcloud-系列了解一下-OpenFeign

写在前面思考的过程往往比直接得到结论更加重要 Feign对于 feign,无疑就是整合了 ribbon + hystrix,然后封装为对开发使用起来更加友好的 jar。因此本质上,feign 是 ribbon + hystrix. 因此,在学习 Feign 之前,建议先把 ribbon, hystrix 学习一下。 尽管,Feign 只做了封装加强,但是有几个问题还是值得思考的 1、feign 如何完成对注解 @FeignClient 的加载的@EnableFeignClient 注解导入了 FeignClientsRegistrar 类, FeignClientsRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,完成了对 @FeignClient 类的加载。 2、Fegin 一般是接口,它是如何完成动态代理的?2.1、未启用 Hystrix为每个 @FeignClient 注入的 Feign 配置类 FeignClientFactoryBean,实现了 FactoryBean。在 getObject()时,创建 ReflectiveFeign.FeignInvocationHandler。 FeignInvocationHandler 对应的就是被 @FeignClient 注解标注的类。方法则对应 SynchronousMethodHandler。 当在调用时 Feign 方法时,会被 FeignInvocationHandler 代理。 FeignInvocationHandler 创建流程如下 Feign 动态代理执行流程如下 2.2、启用 Hystrix当 feign.hystrix.enable=true 时,此时会被 @FeignClient 会被 HystrixInvocationHandler 代理,先走 Hystrix 的逻辑,然后再走 SynchronousMethodHandler 的逻辑。 ...

June 26, 2020 · 1 min · jiezi

SpringCloud-Gateway-通过-Nacos-配置动态路由-代码片段

package com.jarvisbim.jarvis.cloud.gateway.core.components;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.alibaba.nacos.api.NacosFactory;import com.alibaba.nacos.api.config.ConfigService;import com.alibaba.nacos.api.config.listener.Listener;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Value;import org.springframework.cloud.gateway.event.RefreshRoutesEvent;import org.springframework.cloud.gateway.route.RouteDefinition;import org.springframework.cloud.gateway.route.RouteDefinitionWriter;import org.springframework.context.ApplicationEventPublisher;import org.springframework.context.ApplicationEventPublisherAware;import org.springframework.stereotype.Component;import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;import javax.annotation.Resource;import javax.validation.constraints.NotNull;import java.util.ArrayList;import java.util.List;import java.util.Properties;import java.util.concurrent.Executor;/** * 动态路由组件 * <pre> * 监听Nacos配置文件的变化, 把配置文件的变更后的数据动态写入, 达到不重启Gateway, 也可以配置路由的要求 * - java 使用nacos config: @link: https://nacos.io/zh-cn/docs/sdk.html * </pre> * @author mao * @date 10/06/2020 14:52 */@Slf4j@Componentpublic class DynamicRouteComponent implements ApplicationEventPublisherAware { @Value("${spring.cloud.nacos.config.server-addr}") private String serverAddr; @Value("${jarvis.nacos.global.group}") private String group; @Value("${jarvis.gateway-router-data-id}") private String routeConfigDataId; @Value("${jarvis.nacos.global.namespace}") private String namespace; @Resource private RouteDefinitionWriter routeDefinitionWriter; private ApplicationEventPublisher applicationEventPublisher; private static final List<String> ROUTE_LIST = new ArrayList<>(); @Override public void setApplicationEventPublisher(@NotNull ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } @PostConstruct public void dynamicRouteListener() { try { Properties properties = new Properties(); properties.put("serverAddr", serverAddr); properties.put("namespace", namespace); ConfigService configService = NacosFactory.createConfigService(properties); // 程序首次启动, 并加载初始化路由配置 String initConfigInfo = configService.getConfig(routeConfigDataId, group, 5000); addAndPublishBatchRoute(initConfigInfo); configService.addListener(routeConfigDataId, group, new Listener() { @Override public void receiveConfigInfo(String configInfo) { addAndPublishBatchRoute(configInfo); } @Override public Executor getExecutor() { return null; } }); } catch (Exception e) { e.printStackTrace(); } } /** * 清空所有路由 */ private void clearRoute() { for(String id : ROUTE_LIST) { this.routeDefinitionWriter.delete(Mono.just(id)).subscribe(); } ROUTE_LIST.clear(); } /** * 添加单条路由信息 * @param definition RouteDefinition */ private void addRoute(RouteDefinition definition) { routeDefinitionWriter.save(Mono.just(definition)).subscribe(); ROUTE_LIST.add(definition.getId()); } /** * 批量 添加及发布 路由 * @param configInfo 配置文件字符串, 必须为json array格式 */ private void addAndPublishBatchRoute(String configInfo) { try { clearRoute(); List<RouteDefinition> gatewayRouteDefinitions = JSONObject.parseArray(configInfo, RouteDefinition.class); for (RouteDefinition routeDefinition : gatewayRouteDefinitions) { addRoute(routeDefinition); } publish(); log.info("Dynamic config gateway route finished. {}", JSON.toJSONString(gatewayRouteDefinitions)); } catch (Exception e) { e.printStackTrace(); } } private void publish() { this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter)); }}

June 10, 2020 · 2 min · jiezi

springcloud-系列-简单了解一下-hystrix

写在前面思考的过程往往比直接得到结论更加重要 1、为什么需要熔断器服务雪崩在分布式环境下,不可避免的就是服务之间的调用。A 调 B,B 可能会失败,如果此时 B 服务挂掉,那么会导致服务 A 因为服务 B 的失败而失败。从而导致 客户端认为 A 也是失败的。 简单说就是,牵一发而动全身 这也是,我们需要熔断器的原因。我们需要有保护服务调用的组件。当服务 B 挂掉时,服务 B 需要能够快速失败。 2、如果自己写一个断路器,你会怎么做呢?隔离策略思考一下,什么是隔离?我对他的理解,大概就是,服务 A 调用服务 B,服务 C。不能因为调用服务 B 出现问题,而导致调用服务 C 也出现问题。也就是,服务B、服务C 的调用应该放在不同的环境下。 常见的资源隔离,有线程池隔离,信号量隔离 线程池隔离信号量隔离线程请求线程和调用 provider 不是同一个线程请求线程和调用 provider 是同一个线程开销排队、调度、上下文开销等无线程切换,开销低异步支持不支持并发支持支持(线程池大小)支持(信号量上限)传递 Header无法传递 Http Header可以传递 Http Header快速失败当 provider 提供的服务不可用,或出现异常时,应该有可供回调的降级方法。 provider 调用失败抛出异常,可能针对某种异常,不想执行快速失败策略,而是需要直接抛出异常provider 调用失败,可能不想执行快速失败策略,也不想抛出任何异常。限流当 provider 被大量调用时,为了保护链路,需要做限流。那么其实核心的问题是,如何进行统计。 统计每个 provider 的调用情况需要统计。这样可以更好的监控到 provider 提供的服务的情况。统计的算法,应该是基于滑动窗口进行统计。 熔断因为有对每个 provider 调用情况统计,在调用之前,失败次数达到某个阈值时,可以认为该 provider 已经是有问题的,可以直接快速失败,以防止服务雪崩情况。 系统自适应保护熔断机制是针对每个 provider 的。但是,有可能服务系统已经要达到极限了,不能再接收任何请求了,那么此时,出于系统的保护,也应该快速失败。 扩展作为一个组件,支持扩展那是必须。常见的扩展方式:(其实就是面向接口编程,在某些执行流程中,暴露出部分接口。剩下的就看你怎么封装了) 观察者设计模式 + 策略设计模式。 例如public interface SayListener { String say();}public class App { List<SayListener> sayListener = new ArrayList<>(); public void doSomething() { // ... sayAction(); // 触发了 say 的动作 if (null != sayListener && sayListener.size() > 0) { sayListener.forEach(listener -> { listener.say(); }); } // ... } public void sayAction() {} public void registerSayListener(SayListener listener) { sayListener.add(listener); }}3、现有类似功能组件对比 sentinelhystrixresilience4j隔离策略信号量隔离(并发线程数限流)线程池隔离/信号量隔离信号量隔离熔断降级策略基于响应时间、异常比率、异常数基于异常比率基于异常比率、响应时间实时统计实现滑动窗口(LeapArray)滑动窗口(RxJava)Ring Bit Buffer动态规则配置支持多种数据源支持多种数据源有限支持扩展性多个扩展点插件形式接口形式基于注解的支持支持支持支持限流基于 QPS, 支持基于调用关系的限流基于线程池个数有限支持Rate Limiter系统自适应保护支持不支持不支持控制台丰富简单不提供控制台,可对接其他监控系统hystrix wiki 介绍实在太全了,这里就没必要在介绍了,主要是从个人的角度去思考如果让自己也实现一个断路器中间件,你会怎么做?(鉴于 hystrix 停止维护,就没看源码了,以及 sentinel 的活跃,重心会放在 sentinel 上) ...

June 7, 2020 · 1 min · jiezi

springcloud项目优雅重启二eurekaclient

启动eureka-client启动后,会向eureka-server注册,同时会定时续约 (renew);为了提升性能,eureka-client启用了本地缓存,缓存存在localRegionApps里,定时更新缓存。eureka-client的核心类是DiscoveryClient。 @InjectDiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args, Provider<BackupRegistry> backupRegistryProvider) { if (args != null) { this.healthCheckHandlerProvider = args.healthCheckHandlerProvider; this.healthCheckCallbackProvider = args.healthCheckCallbackProvider; this.eventListeners.addAll(args.getEventListeners()); this.preRegistrationHandler = args.preRegistrationHandler; } else { this.healthCheckCallbackProvider = null; this.healthCheckHandlerProvider = null; this.preRegistrationHandler = null; } this.applicationInfoManager = applicationInfoManager; InstanceInfo myInfo = applicationInfoManager.getInfo(); clientConfig = config; staticClientConfig = clientConfig; transportConfig = config.getTransportConfig(); instanceInfo = myInfo; if (myInfo != null) { appPathIdentifier = instanceInfo.getAppName() + "/" + instanceInfo.getId(); } else { logger.warn("Setting instanceInfo to a passed in null value"); } this.backupRegistryProvider = backupRegistryProvider; this.urlRandomizer = new EndpointUtils.InstanceInfoBasedUrlRandomizer(instanceInfo); localRegionApps.set(new Applications()); fetchRegistryGeneration = new AtomicLong(0); remoteRegionsToFetch = new AtomicReference<String>(clientConfig.fetchRegistryForRemoteRegions()); remoteRegionsRef = new AtomicReference<>(remoteRegionsToFetch.get() == null ? null : remoteRegionsToFetch.get().split(",")); if (config.shouldFetchRegistry()) { this.registryStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRY_PREFIX + "lastUpdateSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L}); } else { this.registryStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC; } if (config.shouldRegisterWithEureka()) { this.heartbeatStalenessMonitor = new ThresholdLevelsMetric(this, METRIC_REGISTRATION_PREFIX + "lastHeartbeatSec_", new long[]{15L, 30L, 60L, 120L, 240L, 480L}); } else { this.heartbeatStalenessMonitor = ThresholdLevelsMetric.NO_OP_METRIC; } logger.info("Initializing Eureka in region {}", clientConfig.getRegion()); if (!config.shouldRegisterWithEureka() && !config.shouldFetchRegistry()) { logger.info("Client configured to neither register nor query for data."); scheduler = null; heartbeatExecutor = null; cacheRefreshExecutor = null; eurekaTransport = null; instanceRegionChecker = new InstanceRegionChecker(new PropertyBasedAzToRegionMapper(config), clientConfig.getRegion()); // This is a bit of hack to allow for existing code using DiscoveryManager.getInstance() // to work with DI'd DiscoveryClient DiscoveryManager.getInstance().setDiscoveryClient(this); DiscoveryManager.getInstance().setEurekaClientConfig(config); initTimestampMs = System.currentTimeMillis(); logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}", initTimestampMs, this.getApplications().size()); return; // no need to setup up an network tasks and we are done } try { // default size of 2 - 1 each for heartbeat and cacheRefresh scheduler = Executors.newScheduledThreadPool(2, new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-%d") .setDaemon(true) .build()); heartbeatExecutor = new ThreadPoolExecutor( 1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-HeartbeatExecutor-%d") .setDaemon(true) .build() ); // use direct handoff cacheRefreshExecutor = new ThreadPoolExecutor( 1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactoryBuilder() .setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d") .setDaemon(true) .build() ); // use direct handoff eurekaTransport = new EurekaTransport(); scheduleServerEndpointTask(eurekaTransport, args); AzToRegionMapper azToRegionMapper; if (clientConfig.shouldUseDnsForFetchingServiceUrls()) { azToRegionMapper = new DNSBasedAzToRegionMapper(clientConfig); } else { azToRegionMapper = new PropertyBasedAzToRegionMapper(clientConfig); } if (null != remoteRegionsToFetch.get()) { azToRegionMapper.setRegionsToFetch(remoteRegionsToFetch.get().split(",")); } instanceRegionChecker = new InstanceRegionChecker(azToRegionMapper, clientConfig.getRegion()); } catch (Throwable e) { throw new RuntimeException("Failed to initialize DiscoveryClient!", e); } if (clientConfig.shouldFetchRegistry() && !fetchRegistry(false)) { fetchRegistryFromBackup(); } // call and execute the pre registration handler before all background tasks (inc registration) is started if (this.preRegistrationHandler != null) { this.preRegistrationHandler.beforeRegistration(); } // 这里clientConfig.shouldEnforceRegistrationAtInit()默认为false if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) { try { if (!register() ) { throw new IllegalStateException("Registration error at startup. Invalid server response."); } } catch (Throwable th) { logger.error("Registration error at startup: {}", th.getMessage()); throw new IllegalStateException(th); } } // finally, init the schedule tasks (e.g. cluster resolvers, heartbeat, instanceInfo replicator, fetch initScheduledTasks(); try { Monitors.registerObject(this); } catch (Throwable e) { logger.warn("Cannot register timers", e); } // This is a bit of hack to allow for existing code using DiscoveryManager.getInstance() // to work with DI'd DiscoveryClient DiscoveryManager.getInstance().setDiscoveryClient(this); DiscoveryManager.getInstance().setEurekaClientConfig(config); initTimestampMs = System.currentTimeMillis(); logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}", initTimestampMs, this.getApplications().size());}DiscoveryClient初始化时,在本地缓存放入了空列表,创建了定时任务启动器和线程池,启动定时任务;由于clientConfig.shouldEnforceRegistrationAtInit()默认为false,所以在初始化时并不会执行注册方法register()。 ...

June 5, 2020 · 12 min · jiezi

springcloud项目优雅重启一问题和gatewayribbon流程

问题当前项目用的是springcloud-gateway + eureka + springboot架构,请求会先经过网关,网关根据注册中心获取业务项目服务器地址,再转发到业务服务接口上;这种架构在项目重启时,存在几个问题 : 业务项目实例shutdown时,会停止当前未完成的REQUEST请求。某个业务项目实例已经停止了,但是网关仍会转发请求过去,导致请求失败。某个业务项目实例已经重新启动了,但是网关并不会马上向这个实例转发请求;假如项目只有两个实例,如果在第一个节点刚启动完就立刻重启另外一个实例,就会导致服务不可用。要解决以上问题,我们需要先了解gateway、eureka、ribbon、Tomcat的原理,明白为什么会出现以上问题。 主流程先从gateway入口处开始了解,以下是springcloud-gateway官网的一张图:有个关键类RoutePredicateHandlerMapping,继承了AbstractHandlerMapping,是webflux的handlermapping,作用相当于webmvc的handlermapping:将请求映射到对应的handler来处理。RoutePredicateHandlerMapping会遍历所有路由Route,获取符合规则的路由,并将获取到的route放入当前请求上下文的属性中。 public class RoutePredicateHandlerMapping extends AbstractHandlerMapping { @Override protected Mono<?> getHandlerInternal(ServerWebExchange exchange) { // don't handle requests on the management port if set if (managmentPort != null && exchange.getRequest().getURI().getPort() == managmentPort.intValue()) { return Mono.empty(); } exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName()); return lookupRoute(exchange) // .log("route-predicate-handler-mapping", Level.FINER) //name this .flatMap((Function<Route, Mono<?>>) r -> { exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR); if (logger.isDebugEnabled()) { logger.debug("Mapping [" + getExchangeDesc(exchange) + "] to " + r); } exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); return Mono.just(webHandler); }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> { exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR); if (logger.isTraceEnabled()) { logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); } }))); } protected Mono<Route> lookupRoute(ServerWebExchange exchange) { return this.routeLocator .getRoutes() //individually filter routes so that filterWhen error delaying is not a problem .concatMap(route -> Mono .just(route) .filterWhen(r -> { // add the current route we are testing exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId()); return r.getPredicate().apply(exchange); }) //instead of immediately stopping main flux due to error, log and swallow it .doOnError(e -> logger.error("Error applying predicate for route: "+route.getId(), e)) .onErrorResume(e -> Mono.empty()) ) // .defaultIfEmpty() put a static Route not found // or .switchIfEmpty() // .switchIfEmpty(Mono.<Route>empty().log("noroute")) .next() //TODO: error handling .map(route -> { if (logger.isDebugEnabled()) { logger.debug("Route matched: " + route.getId()); } validateRoute(route, exchange); return route; }); /* TODO: trace logging if (logger.isTraceEnabled()) { logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }*/ }}从routeLocator.getRoutes()看到是从routeLocator里获取路由列表,我们看下路由规则是怎么生成的。routeLocator有个实现类是RouteDefinitionRouteLocator。 ...

June 4, 2020 · 11 min · jiezi

springcloud-系列-三言两语带你认识-ribbon

前言ribbon 作为一个负载均衡组件,个人认为,其核心的功能就是提供多种负载均衡策略。 暂停思考一下,如果让你自己写负载均衡组件,要如何做? 获取有多少合适的服务可供负载服务有时候可能会不可用,那么需要更新维护服务,及时将不合理的服务剔除提供策略判断服务是否可用实现多种负载算法,供用户选择负载失败后的重试实际上, ribbon 的核心功能,也大概就是上面我说的这些。 理论1、获取有多少合适的服务可供负载当今的应用,大多数部署在云上,并向全国各地提供服务。假设服务 A 在福建、北京均有部署。当在北京的服务器请求了服务 A,最合理的情况,应该要由北京的服务器响应。 其实,这里引入了 ribbon 的一个核心概念。区域亲和性说人话就是,优先选择同一个区域的服务(除非同一区域的服务都挂了) (注:eureka 可以配置 region 和 zone ) 关于 eureka 分区配置,请参考文章 eureka分区的深入讲解 2、服务维护解决了第一个问题。接下来,要考虑如何维护服务列表?最简单的方式,其实就是直接写个定时器,每隔 30s。重新拉取服务列表,维护最新的可用服务列表。 ribbon 的实现就是这样。 ribbon 中,由 PollingServerListUpdater 每隔 30s 更新服务列表。 3、服务是否可用判断有了服务列表,还需要,判断服务可不可用,及时剔除不可用的服务。那么最简单的方式,就是直接 ping 该服务,看是否正常返回。但是,要考虑一个问题,如果你的服务非常多,每次检查的时候,都需要 ping 服务,那么这样会不会太损耗性能了? ribbon 中,有 ping 的抽象:IPing ,而且还有 ping 策略的抽象:IPingStrategy。 在 SerialPingStrategy(默认的 IPingStrategy 实现)实现中, ribbon 就考虑到了,我们上述说的问题。因此,实际上, ribbon 在判断服务是否可用,并非真正的 ping 服务,而是仅用服务的 up 的状态判断服务是否可用。 4、负载均衡算法服务列表维护好了,接下来就是实现负载均衡算法了。我们自己实现负载均衡算法时,算法肯定是会有非常多的。那么肯定要先抽象出一个 IRule 接口, 定义如何选择一个服务。 ribbon中,将负载均衡算法抽象为 IRule。 有以下算法 RoundRobinRule轮询策略。Ribbon 默认采用的策略。若经过一轮轮询没有找到可用的 provider,其最多 轮询 10 轮。若最终还没有找到,则返回 null。RandomRule随机策略,从所有可用的 provider 中随机选择一个。RetryRule重试策略。先按照 RoundRobinRule 策略获取 provider,若获取失败,则在指定的时限内 重试。默认的时限为 500 毫秒BestAvailableRule最可用策略。选择并发量最小的 provider,即连接的消费者数量最少的 provider。AvailabilityFilteringRule可用过滤算法。该算法规则是:过滤掉处于服务熔断状态的 provider,或已经超过连接 极限的 provider,对剩余 provider 采用轮询策略。ZoneAvoidanceRule区域回避策略。综合 provider 所在区域的性能及 provider 的可用性,对服务器进行选择。WeightedResponseTimeRule“权重响应时间”策略。根据每个 provider 的平均响应时间计算其权重,响应时间越快 权重越大,被选中的机率就越高(并非是权重最大的一定被选定)。在刚启动时采用轮询策 略。后面就会根据权重进行选择了。ribbon 默认使用的算法为 RoundRobinRule (实际上是多种 IRule 一起协调工作,过程较复杂) ...

May 31, 2020 · 2 min · jiezi

搭建SpringCloud微服务框架六数据库持久层SpringDataJPA

搭建微服务框架(数据库持久层-SpringDataJPA) 用惯了Mybatis,这次来换换口味,在SQuid中集成SpringDataJPA。本文源地址:搭建微服务框架(数据库持久层-SpringDataJPA) Github地址:SQuid 介绍以前都是听说过的是 HibernateJPA ,却从来没有使用过,一直在项目中使用的是 Mybatis。 SpringDataJPA是基于Hibernate的底层封装的一套ORM框架,使用起来的第一感觉是代码量真的很少,相较传统的Mybatis来说,感觉最起码少了60%,当然大部分都是体现在xml文件上。 介绍真的没有太多词汇可以展示出来,下面来进行使用。? 使用在squid项目中,我们新建一个 squid-example-jpa的项目(由于之前的example目录被删除,可以根据下面的层级目录来进行新建) 引入依赖:<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId></dependency><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId></dependency><dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId></dependency>生成Java实体如果使用的是IDEA,完全可以参考这篇博客 IDEA下生成SpringDataJPA的Java实体 来生成实体信息。 因为使用了lombok,所以在生成的实体中并没有 getter setter 方法呈现,关于lombok可以了解一下 Lombok DAO生成了实体信息后,DAO文件就需要我们自己来手工生成了: public interface EdocInvoiceRepository extends JpaRepository<EdocInvoice, Long> {}一般我们直接继承的是 JpaRepository ,这个是包含所有JPA处理的类,基本上拥有了所有持久层的交互方法。 JPARespository: public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { List<T> findAll(); List<T> findAll(Sort var1); List<T> findAllById(Iterable<ID> var1); <S extends T> List<S> saveAll(Iterable<S> var1); void flush(); <S extends T> S saveAndFlush(S var1); void deleteInBatch(Iterable<T> var1); void deleteAllInBatch(); T getOne(ID var1); <S extends T> List<S> findAll(Example<S> var1); <S extends T> List<S> findAll(Example<S> var1, Sort var2);}如果你还有其他需求,比如需要根据某两个字段进行查询等等,SpringDataJPA完全支持: ...

May 29, 2020 · 2 min · jiezi

搭建SpringCloud微服务框架一结构和各个组件

搭建微服务框架(结构和各个组件)简介 SQuid是基于Spring,SpringBoot,使用了SpringCloud下的组件进行构建,目的是想搭建一套可以快速开发部署,并且很好上手的一套微服务框架。本文源地址:搭建微服务框架(结构和各个组件) Github地址:SQuid 组件[Spring-Cloud-Feign]()[Spring-Security-OAuth]()Spring-Cloud-GatewaySpring-Cloud-Alibaba中间件[Redis]()NacosSentinel数据库持久层[SpringDataJPA]()Mybatis-Plus数据库Mysql5.7 +Oracle环境JDK1.8Maven3.2.5Idea如果你的电脑上已经有安装好上面的程序,那么你可以打开git,输入命令 git@github.com:yanzhenyidai/squid.git 将本项目克隆到本地运行。 不过也可以先看看后面各个组件的集成的说明,送上链接: SC服务注册与发现读取Nacos的配置信息服务接口鉴权服务网关处理数据库持久层-SpringDataJpa[TODO:数据库持久层-Mybatis-Plus]()[TODO:服务熔断和跟踪-Sentinel]()项目依赖本次项目是在 spring-boot: 2.0.9.RELEASE 下搭建,所需依赖文件如下: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.9.RELEASE</version> </parent> <properties> <spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version> <spring-cloud-openfeign.version>2.2.0.RELEASE</spring-cloud-openfeign.version> <spring-cloud.version>Finchley.SR2</spring-cloud.version> <druid-starter.version>1.1.21</druid-starter.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid-starter.version}</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-openfeign-dependencies</artifactId> <version>${spring-cloud-openfeign.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>parent以 springboot 开始,原因为 springcloud是基于 springboot 的一套脚手架工具,在搭建本项目时遇到了不少的版本冲突的问题,可以看一下springboot和springcloud版本整理。 希望能对你有到帮助。

May 29, 2020 · 1 min · jiezi

搭建SpringCloud微服务框架二SpringCloud服务注册与发现

搭建微服务框架(SC服务注册与发现)本文源地址:https://yanzhenyidai.com/#/squid/squid-2.1-sc-serverGithub地址:SQuid 服务注册中心-NacosNacos是阿里开源的一款注册中心中间件,详细介绍可以访问Nacos官网,本次框架是基于Nacos做的注册。 安装Nacos我们可以使用Docker,Docker可以很快的安装好Nacos并且启动。 而在本项目中,引入的Nacos两个依赖分别如下: <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>完成对Nacos的依赖引入后,可以进行下一步的SpringCloud服务发布的操作,?。 SpringCloud服务发布我们新建俩个Maven模块项目,用它来实现服务提供者的角色。 如上,分别以 squid-example-api 和 squid-example-provider 命名。 squid-example-apisquid-example-api 项目中主要是写一些接口文件,将这些接口对外注册并且暴露出去,引入依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>新建一个 HiService 的接口,并且注明 @FeignClient("squid-example-sc-provider"),注解内名称可以为项目名: @FeignClient("squid-example-sc-provider") public interface HiService { @RequestMapping(value = "/hi", method = RequestMethod.GET) public String hi(@RequestParam("msg") String msg); } PS:这里是为了明确各个模块,所以将 squid-example-api 和 squid-example-provider 进行分离,也可以将两个模块合并。 squid-example-provider然后我们依旧是在 squid-example-provider 引入依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.yanzhenyidai</groupId> <artifactId>squid-example-sc-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>引入 spring-cloud-start-openfeign 是将服务以 Http Restful 的形式进行对外发布(SC的服务基本上都是以Http Restful的形式, 可以了解一下 Dubbo或者其他RPC的服务注册,也可以看一下 [RPC和HTTP]()),而 spring-boot-starter-web 则是表明该项目需要以Web的形式进行启动, 不难理解,毕竟HTTP请求是有需要一个Web容器来进行。 ...

May 29, 2020 · 2 min · jiezi

搭建SpringCloud微服务框架五SpringCloudGateway-服务网关处理

搭建微服务框架(服务网关处理)本篇来进行介绍微服务网关集成的使用操作,基于SpringCloudGateway。本文源地址:搭建微服务框架(服务网关处理) Github地址:SQuid Spring-Cloud-Gateway由于SpringCloud-Netflix的Zuul组件不再维护,而Spring官方推出了Gateway的新组件,并且支持了SringCloud2.0的版本,所以在选型方面,直接就选择了Spring官方的Gateway。 介绍Gateway,不得不将它与Zuul进行比较。 的确,Zuul的网关处理流程很一目了然,基于一个 ZuulFilter,而后可以定义 preRoute() route() postRoute() error(),类似于Spring的前置通知,后置通知,环绕通知,算得上是不错的网关处理组件, 比较可惜的是,SpringCloud-Netfilx的停止更新,使得SpringCloud的网关处理选择为了 Spring-Cloud-Gateway。 众所周知,Zuul是基于Serverlet,而Gateway是基于Netty,两个谁更优秀,这个目前也是进行不了一个定义,广义上来说也是传统的 Http和TCP 的比较。 下面介绍Gateway的使用,? 使用Spring-Cloud-Gateway首先贴一下工程截图: 很简单的一个例子,先新建一个 squid-gateway 的工程,引入如下依赖: pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-gateway-core</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.isomorphism</groupId> <artifactId>token-bucket</artifactId> <version>1.7</version> </dependency>GatewayApplication@SpringBootApplication@EnableDiscoveryClientpublic class GateWayApplication { public static void main(String[] args) { SpringApplication.run(GateWayApplication.class, args); }}application.yaml最主要的就是application.yaml文件了,里面可以配置路由转发规则,当然也可以直接在 GatewayApplication.java 文件中写java代码来进行转发,不过我总认为这样不太直观,下面来看一下文件: ...

May 29, 2020 · 1 min · jiezi

SpringCloud-注册中心之Consul

【转载请注明出处】:https://segmentfault.com/a/1190000022778386 Consul 介绍Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其它分布式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其它工具(比如 ZooKeeper 等)。使用起来也较 为简单。Consul 使用 Go 语言编写,因此具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。 Consul 的优势:使用 Raft 算法来保证一致性, 比复杂的 Paxos 算法更直接. 相比较而言, zookeeper 采用的是 Paxos, 而 etcd 使用的则是 Raft。支持多数据中心,内外网的服务采用不同的端口进行监听。 多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等。 zookeeper 和 etcd 均不提供多数据中心功能的支持。支持健康检查。 etcd 不提供此功能。支持 http 和 dns 协议接口。 zookeeper 的集成较为复杂, etcd 只支持 http 协议。官方提供 web 管理界面, etcd 无此功能。综合比较, Consul 作为服务注册和配置管理的新星, 比较值得关注和研究。 特性:服务发现健康检查Key/Value 存储多数据中心Consul 角色client: 客户端, 无状态, 将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群。server: 服务端, 保存配置信息, 高可用集群, 在局域网内与本地客户端通讯, 通过广域网与其它数据中心通讯。 每个数据中心的 server 数量推荐为 3 个或是 5 个。Consul 客户端、服务端还支持夸中心的使用,更加提高了它的高可用性。 ...

May 29, 2020 · 3 min · jiezi

SpringCloudNetfilx入门

整体框架由于整个微服务使用springcloud进行管理,所以采用maven聚合工程 导包最好使用父项目进行版本控制 <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR4</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.2.5.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>注意点:maven中和Java类似没有多继承这个概念,间接实现多继承就可以使用import对包进行导入,这样子包就能继承版本控制 注册中心<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency></dependencies>客户端(服务提供者也是客户端)<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--实现负载均衡--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <!--显示info信息--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency></dependencies>application配置注册中心server: port: 8000eureka: client: register-with-eureka: false # 不讲自己注册进注册中心 fetch-registry: false # 不拉取服务在springboot应用中开启EurekaServer @SpringBootApplication@EnableEurekaServerpublic class RegistryApplication { public static void main(String[] args) { SpringApplication.run(RegistryApplication.class); }}服务提供者或消费者server: port: 8081eureka: client: service-url: defaultZone: http://localhost:8000/eureka # 服务中心的地址,','隔开可以写多个实现集群 instance: instance-id: consumer-port:8081 # status的名称spring: application: name: consumer # 服务的名称debug: true# 配置自己的信息info: app.name: roderick在springboot应用中开启EurekaServer ...

May 27, 2020 · 1 min · jiezi

Dubbo和SpringCloud微服务架构对比

一、为什么要使用微服务? 微服务提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合。今天我们来了解下业内主要的微服务框架:Dubbo 和 Spring Cloud 微服务主要的优势 降低复杂度将原来耦合在一起的复杂业务拆分为单个服务,规避了原本复杂度无止境的积累。每一个微服务专注于单一功能,并通过定义良好的接口清晰表述服务边界。 每个服务开发者只专注服务本身,通过使用缓存、DAL 等各种技术手段来提升系统的性能,而对于消费方来说完全透明。 可独立部署 由于微服务具备独立的运行进程,所以每个微服务可以独立部署。当业务迭代时只需要发布相关服务的迭代即可,降低了测试的工作量同时也降低了服务发布的风险。 容错 在微服务架构下,当某一组件发生故障时,故障会被隔离在单个服务中。比如通过限流、熔断等方式降低错误导致的危害,保障核心业务正常运行。 扩展 单块架构应用也可以实现横向扩展,就是将整个应用完整的复制到不同的节点。当应用的不同组件在扩展需求上存在差异时,微服务架构便体现出其灵活性, 因为每个服务可以根据实际需求独立进行扩展。 微服务的核心要素在于服务的发现、注册、路由、熔断、降级、分布式配置!! 二、Dubbo 和 SpringCloud 的比较 1、Dubbo 核心部件Provider:暴露服务的提供方,可以通过 jar 或者容器的方式启动服务。Consumer:调用远程服务的服务消费方。 Registry:服务注册中心和发现中心。 Monitor:统计服务和调用次数,调用时间监控中心,Dubbo 的控制台页面中可以显示。 Container:服务运行的容器。 Spring Cloud总体架构Service Provider: 暴露服务的提供方。Service Consumer:调用远程服务的服务消费方。 EureKa Server: 服务注册中心和服务发现中心。 从整体架构上来看,二者模式接近,都需要服务提供方,注册中心,服务消费方。2、微服务架构核心要素 Dubbo 只是实现了服务治理,而 Spring Cloud 子项目分别覆盖了微服务架构下的众多部件,服务治理只是其中的一个方面。Dubbo 提供了各种 Filter,对于上述中没有的要素,可以通过扩展 Filter 来完善: a. 分布式配置:可以使用淘宝的 diamond、百度的 disconf 来实现分布式配置管理。 b. 服务跟踪:可以使用京东开源的 Hydra,或者扩展 Filter 用 Zippin 来做服务跟踪。 c. 批量任务:可以使用当当开源的 Elastic-Job、tbschedule。 从核心要素来看,Spring Cloud 更胜一筹,在开发过程中只要整合 Spring Cloud 的子项目就可以顺利完成各种组件的融合,而 Dubbo 却需要通过实现各种 Filter 来做定制,开发成本以及技术难度略高。 ...

November 4, 2019 · 2 min · jiezi

分享SpringCloud通用架构图

分享一个SpringCloud通用架构 希望对你有帮助, 如有错误欢迎指正

November 4, 2019 · 1 min · jiezi

微服务架构案例03数据库选型简介业务数据规划设计

本文源码:GitHub·点这里 || GitEE·点这里 更新进度(共6节): 01:项目技术选型简介,架构图解说明02:业务架构设计,系统分层管理03:数据库选型,业务数据设计规划一、数据库选择1、数据库分类数据库类型常见数据库关系型MySQL、Oracle、DB2、SQLServer等。非关系型Hbase、Redis、MongodDB等。行式存储MySQL、Oracle、DB2、SQLServer等。列式存储Hbase、ClickHouse等。分布式存储Cassandra、Hbase、MongodDB等。键值存储Memcached、Redis、MemcacheDB等。图形存储Neo4J、TigerGraph等。文档存储MongoDB、CouchDB等。2、数据库选择基于特定的应用环境,选择最适合的数据库,建立数据存储模式,使之能够有效地存储数据,满足各种用户的应用需求。例如:普通的业务库,数据量不大情况下选择MySQL;有频繁的搜索操作,可以使用ElasticSearch;系统存在大量热点数据,可以使用常见的缓存数据库等。3、微服务数据库微服务架构的一个关键点是数据库设计规划,基本原则是每个服务都有自己单独的数据库,而且只有微服务本身可以访问这个数据库。其他的服务要是想访问,只能通过调用该服务对外提供的接口进行操作,这样可以压缩数据库操作的接口,在问题排查和性能优化上都可以提供支持,这样也使系统的框架更具有条理。该模式图解如下: 微服务C通过微服务A操作数据库A,或者通过微服务B操作数据库B。 二、规划业务数据库1、总体划分 主要使用三种数据存储:MySQL(划分三个业务库),ElasticSearch(单台),Redis(单台)。 2、用户库(user-data)存储用户相关的数据结构,比如User信息,Token,操作日志等。 CREATE TABLE `hc_user_base` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `user_name` varchar(50) DEFAULT NULL COMMENT '用户名', `pass_word` varchar(300) DEFAULT NULL COMMENT '加密密码', `phone` varchar(30) DEFAULT NULL COMMENT '手机号', `email` varchar(50) DEFAULT NULL COMMENT '邮箱', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', `state` int(1) DEFAULT '0' COMMENT '状态:0可用,1禁用', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';3、管理系统库(admin-data)存储后台微服务管理系统的支撑数据库,例如定时器,管理员权限,配置字典等。 ...

November 2, 2019 · 2 min · jiezi

Exception-in-monitor-thread-while-connecting-to-server-localhost

项目没有使用 MongoDB 却每次启动时会出现如下异常信息: 10:41:41.288 [main] INFO o.m.d.cluster - Cluster created with settings {hosts=[localhost:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}10:41:41.361 [cluster-ClusterId{value='5dae6c654d4299250bde1b44', description='null'}-localhost:27017] INFO o.m.d.cluster - Exception in monitor thread while connecting to server localhost:27017com.mongodb.MongoSocketOpenException: Exception opening socket at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:67) at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:126) at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:117) at java.lang.Thread.run(Thread.java:748)Caused by: java.net.ConnectException: 拒绝连接 (Connection refused) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at com.mongodb.internal.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:64) at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:62) ... 3 common frames omitted解决方法// 在 Application 主类上添加注解// 方式一:@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})// 方式二:@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})相关文档: ...

October 22, 2019 · 1 min · jiezi

Spring-Security-实战干货玩转自定义登录

1. 前言前面的关于 Spring Security 相关的文章只是一个预热。为了接下来更好的实战,如果你错过了请从 Spring Security 实战系列 开始。安全访问的第一步就是认证(Authentication),认证的第一步就是登录。今天我们要通过对 Spring Security 的自定义,来设计一个可扩展,可伸缩的 form 登录功能。 2. form 登录的流程下面是 form 登录的基本流程: 只要是 form 登录基本都能转化为上面的流程。接下来我们看看 Spring Security 是如何处理的。 3. Spring Security 中的登录昨天 Spring Security 实战干货:自定义配置类入口WebSecurityConfigurerAdapter 中已经讲到了我们通常的自定义访问控制主要是通过 HttpSecurity 来构建的。默认它提供了三种登录方式: formLogin() 普通表单登录oauth2Login() 基于 OAuth2.0 认证/授权协议openidLogin() 基于 OpenID 身份认证规范以上三种方式统统是 AbstractAuthenticationFilterConfigurer 实现的, 4. HttpSecurity 中的 form 表单登录启用表单登录通过两种方式一种是通过 HttpSecurity 的 apply(C configurer) 方法自己构造一个 AbstractAuthenticationFilterConfigurer 的实现,这种是比较高级的玩法。 另一种是我们常见的使用 HttpSecurity 的 formLogin() 方法来自定义 FormLoginConfigurer 。我们先搞一下比较常规的第二种。 ...

October 18, 2019 · 4 min · jiezi

Spring-Cloud-Alibaba-Nacos-Config-实战

Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置 一、安装 Nacos1、下载 Nacos最新稳定版下载:https://github.com/alibaba/nacos/releases 2、启动 Nacos启动 Nacos (单机模式) sh startup.sh -m standalone关闭 Nacos sh shutdown.sh二、配置 Nacos1、打开 Nacos默认地址:http://127.0.0.1:8848/nacos/#/login 默认账号:账号密码相同,都为nacos 2、添加配置配置数据: Data ID: nacos-dev.propertiesGroup : DEFAULT_GROUP配置格式: Properties配置内容: useLocalCache=true Data ID 的格式说明: ${prefix}-${spring.profile.active}.${file-extension}prefix: 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix 来配置 spring.profile.active: 即为当前环境对应的 profile, 注意:当 spring.profile.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension} file-exetension: 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型 ...

October 17, 2019 · 1 min · jiezi

Spring-Cloud-OpenFeign基于Ribbon和Hystrix的声明式服务调用

SpringBoot实战电商项目mall(20k+star)地址:https://github.com/macrozheng/mall摘要Spring Cloud OpenFeign 是声明式的服务调用工具,它整合了Ribbon和Hystrix,拥有负载均衡和服务容错功能,本文将对其用法进行详细介绍。 Feign简介Feign是声明式的服务调用工具,我们只需创建一个接口并用注解的方式来配置它,就可以实现对某个服务接口的调用,简化了直接使用RestTemplate来调用服务接口的开发量。Feign具备可插拔的注解支持,同时支持Feign注解、JAX-RS注解及SpringMvc注解。当使用Feign时,Spring Cloud集成了Ribbon和Eureka以提供负载均衡的服务调用及基于Hystrix的服务容错保护功能。 创建一个feign-service模块这里我们创建一个feign-service模块来演示feign的常用功能。在pom.xml中添加相关依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency>在application.yml中进行配置server: port: 8701spring: application: name: feign-serviceeureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8001/eureka/在启动类上添加@EnableFeignClients注解来启用Feign的客户端功能@EnableFeignClients@EnableDiscoveryClient@SpringBootApplicationpublic class FeignServiceApplication { public static void main(String[] args) { SpringApplication.run(FeignServiceApplication.class, args); }}添加UserService接口完成对user-service服务的接口绑定我们通过@FeignClient注解实现了一个Feign客户端,其中的value为user-service表示这是对user-service服务的接口调用客户端。我们可以回想下user-service中的UserController,只需将其改为接口,保留原来的SpringMvc注释即可。/** * Created by macro on 2019/9/5. */@FeignClient(value = "user-service")public interface UserService { @PostMapping("/user/create") CommonResult create(@RequestBody User user); @GetMapping("/user/{id}") CommonResult<User> getUser(@PathVariable Long id); @GetMapping("/user/getByUsername") CommonResult<User> getByUsername(@RequestParam String username); @PostMapping("/user/update") CommonResult update(@RequestBody User user); @PostMapping("/user/delete/{id}") CommonResult delete(@PathVariable Long id);}添加UserFeignController调用UserService实现服务调用/** * Created by macro on 2019/8/29. */@RestController@RequestMapping("/user")public class UserFeignController { @Autowired private UserService userService; @GetMapping("/{id}") public CommonResult getUser(@PathVariable Long id) { return userService.getUser(id); } @GetMapping("/getByUsername") public CommonResult getByUsername(@RequestParam String username) { return userService.getByUsername(username); } @PostMapping("/create") public CommonResult create(@RequestBody User user) { return userService.create(user); } @PostMapping("/update") public CommonResult update(@RequestBody User user) { return userService.update(user); } @PostMapping("/delete/{id}") public CommonResult delete(@PathVariable Long id) { return userService.delete(id); }}负载均衡功能演示启动eureka-service,两个user-service,feign-service服务,启动后注册中心显示如下: ...

October 14, 2019 · 2 min · jiezi

Java从单体到微服务打造房产销售平台

概述最近在学习某课的《Java从单体到微服务打造房产销售平台》,也算是我学习的第一门微服务课程,在此开贴记录一下知识点,如有不当请多指教! Spring Mail发送激活链接功能实现:在注册用户时通过spring mail发送激活链接到用户的邮箱,在有效期内用户点击链接后更新用户状态为激活状态。 引入spring-mail依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>配置appliacation.properties文件 #用来发送邮件domain.name=127.0.0.1:8090#spring-mailspring.mail.host=smtp.163.com #163邮箱spring.mail.username=chenwuguii@163.com spring.mail.password=czy123456 #163邮箱授权码spring.mail.properties.mail.smtp.auth=truehousespring.mail.properties.mail.smtp.starttls.enable=truespring.mail.properties.mail.smtp.starttls.required=trueMailService类 @Servicepublic class MailService { @Autowired private JavaMailSender mailSender; @Value("${spring.mail.username}") private String from; @Value("${domain.name}") private String domainName; @Autowired private UserMapper userMapper; //缓存key-email键值对,当超过15分钟有效期后,若用户还未激活则从数据库删除用户信息 private final Cache<String, String> registerCache = CacheBuilder.newBuilder().maximumSize(100).expireAfterAccess(15, TimeUnit.MINUTES) .removalListener(new RemovalListener<String, String>() { @Override public void onRemoval(RemovalNotification<String, String> notification) { String email = notification.getValue(); User user = new User(); user.setEmail(email); List<User> targetUser = userMapper.selectUsersByQuery(user); if (!targetUser.isEmpty() && Objects.equal(targetUser.get(0).getEnable(), 0)) { userMapper.delete(email);// 代码优化: 在删除前首先判断用户是否已经被激活,对于未激活的用户进行移除操作 } } }).build(); /** * 发送邮件 */ @Async public void sendMail(String title, String url, String email) { SimpleMailMessage message = new SimpleMailMessage(); message.setFrom(from);//发送方邮箱 message.setSubject(title);//标题 message.setTo(email);//接收方邮箱 message.setText(url);//内容 mailSender.send(message); } /** * 1.缓存key-email的关系 * 2.借助spring mail 发送邮件 * 3.借助异步框架进行异步操作 * * @param email */ @Async public void registerNotify(String email) { String randomKey = RandomStringUtils.randomAlphabetic(10); registerCache.put(randomKey, email); String url = "http://" + domainName + "/accounts/verify?key=" + randomKey; //发送邮件 sendMail("房产平台激活邮件", url, email); }}Nginx代理前提:当用户上传图片时,我们在数据库存放的是相对地址,然后保存图片到本地,在浏览器需要展示图片时我们取出相对路径后拼接上前缀路径,这里我们使用nginx代理我们图片的存放位置 ...

October 3, 2019 · 1 min · jiezi

全栈之路微服务课程12Hystrix之初遇见

简介Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。 断路器刨析实时监测应用,如果发现在一定时间内失败次数/失败率达到一定阈值,就“跳闸”,断路器打开——此时,请求直接返回,而不去调用原本调用的逻辑。跳闸一段时间后(例如15秒),断路器会进入半开状态,这是一个瞬间态,此时允许一次请求调用该调的逻辑,如果成功,则断路器关闭,应用正常调用;如果调用依然不成功,断路器继续回到打开状态,过段时间再进入半开状态尝试——通过”跳闸“,应用可以保护自己,而且避免浪费资源;而通过半开的设计,可实现应用的“自我修复“。 解决方案熔断模式 这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。隔离模式这种模式就像对系统请求按类型划分成一个个小岛的一样,当某个小岛被火烧光了,不会影响到其他的小岛。例如可以对不同类型的请求使用线程池来资源隔离,每种类型的请求互不影响,如果一种类型的请求线程资源耗尽,则对后续的该类型请求直接返回,不再调用后续资源。这种模式使用场景非常多,例如将一个服务拆开,对于重要的服务使用单独服务器来部署,再或者公司最近推广的多中心。 限流模式上述的熔断模式和隔离模式都属于出错后的容错处理机制,而限流模式则可以称为预防模式。限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。 降级降级与熔断紧密相关,熔断后业务如何表现,约定一个快速失败的 Fallback,即为服务降级代码实现加依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>启动类加注解@EnableCircuitBreaker 控制器加实现 测试http://localhost:8010/movies/usersByFeign/1 { "id": 1, "username": "默认用户", "name": "默认用户", "age": 0, "balance": 1}监控持续不断地访问http://localhost:8010/movies/users/1 多次(至少20次),再访问http://localhost:8010/actuator/health,返现断路器已被开启。 { "status": "UP", "details": { "diskSpace": { "status": "UP", "details": { "total": 107374178304, "free": 15773237248, "threshold": 10485760 } }, "db": { "status": "UP", "details": { "database": "MySQL", "hello": 1 } }, "refreshScope": { "status": "UP" }, "discoveryComposite": { "status": "UP", "details": { "discoveryClient": { "status": "UP", "details": { "services": [ "shop-discovery-eureka-ha", "shop-consumer-movie" ] } }, "eureka": { "description": "Remote status from Eureka server", "status": "UP", "details": { "applications": { "SHOP-DISCOVERY-EUREKA-HA": 1, "SHOP-CONSUMER-MOVIE": 1 } } } } }, "hystrix": { "status": "CIRCUIT_OPEN", "details": { "openCircuitBreakers": [ "MovieController::findByIdByFeign" ] } } }}

September 20, 2019 · 1 min · jiezi

全栈之路微服务课程13Feign之Hystrix

前言默认Feign是不启用Hystrix的,需要添加如下配置启用Hystrix,这样所有的Feign Client都会受到Hystrix保护! 新增配置feign: hystrix: enabled: true提供Fallback@FeignClient(name = "microservice-provider-user", fallback = UserFeignClientFallback.class)public interface UserFeignClient { @GetMapping("/users/{id}") User findById(@PathVariable("id") Long id);}@Componentclass UserFeignClientFallback implements UserFeignClient { @Override public User findById(Long id) { return new User(id, "默认用户", "默认用户", 0, new BigDecimal(1)); }}获取原因@FeignClient(name = "shop-provider-user", fallbackFactory = UserFeignClientFallbackFactory.class)public interface UserFeignClient { @GetMapping("/users/{id}") User findById(@PathVariable("id") Long id);}@Component@Slf4jclass UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient> { @Override public UserFeignClient create(Throwable throwable) { return new UserFeignClient() { @Override public User findById(Long id) { log.error("进入回退逻辑", throwable); return new User(id, "默认用户", "默认用户", 0, new BigDecimal(1)); } }; }}

September 20, 2019 · 1 min · jiezi

Dubbo-Spring-Cloud-之-HTTP-实战

上一篇文章《Spring Cloud Alibaba | Dubbo 与 Spring Cloud 完美结合》我们介绍了Dubbo Spring Cloud的基本使用,使用的服务中心为Spring Cloud Alibaba提供的Nacos,Dubbo内部提供了基于Dubbo的RPC调用,同时,Dubbo Spring Cloud在整合了Spring Cloud之后,可以直接提供HTTP接口,同Spring Cloud无缝衔接,直接支持Feign、RestTemplate等方式的远程调用,在提供HTTP服务的同时可以提供Dubbo服务。Dubbo Spring Cloud支持HTTP远程调用级大的方便了我们的对接外部系统,无需对Dubbo再做二次封装。 1. 案例实战接下来,我们通过一个简单的案例来介绍一下Dubbo Spring Cloud通过注解的方式是如何同时提供Dubbo服务和HTTP服务的。 1.1 创建父工程dubbo-spring-cloud-http工程依赖pom.xml如下: 代码清单:Alibaba/dubbo-spring-cloud-http/pom.xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Cloud Nacos Service Discovery --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>1.2 创建子工程dubbo_provider_web,服务提供方工程依赖pom.xml如下: 代码清单:Alibaba/dubbo-spring-cloud-http/dubbo_provider_web/pom.xml <dependencies> <!-- API --> <dependency> <groupId>com.springcloud</groupId> <artifactId>dubbo_api</artifactId> <version>${project.version}</version> </dependency> <!-- Dubbo Spring Cloud Starter --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> </dependency></dependencies>这里引入Dubbo Spring Cloud工具包和Dubbo API依赖包。 ...

September 20, 2019 · 2 min · jiezi

全栈之路微服务课程10Feign之初遇见

Feign是什么Feign是一个受到Retrofit,JAXRS-2.0和WebSocket启发的Java到HTTP客户端绑定器。Feign的第一个目标是降低将Denominator统一绑定到HTTP API 的复杂性。Feign 是一个声明web服务客户端,这使得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器。RestTemplate与Feign对比 如何使用引入依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId></dependency>创建feign Client@FeignClient(name = "shop-provider-user")public interface UserFeignClient { @GetMapping("/users/{id}") User findById(@PathVariable("id") Long id);}添加注解@EnableFeignClients@EnableFeignClients@SpringBootApplication//(scanBasePackages = {"com.dream.shop"})public class MovieApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(MovieApplication.class, args); }}控制器调用@RequestMapping("/movies")@RestControllerpublic class MovieController { @Autowired private RestTemplate restTemplate; @Autowired private UserFeignClient userFeignClient; @GetMapping("/usersByFeign/{id}") public User findByIdByFeign(@PathVariable Long id) { return this.userFeignClient.findById(id); } @GetMapping("/users/{id}") public User findById(@PathVariable Long id) { // 这里用到了RestTemplate的占位符能力// User user = this.restTemplate.getForObject("http://localhost:8000/users/{id}", User.class, id); User user = this.restTemplate.getForObject("http://shop-provider-user/users/{id}", User.class, id); // ...电影微服务的业务... return user; }}

September 19, 2019 · 1 min · jiezi

全栈之路微服务课程9Ribbon深入刨析

内置规则RoundRobinRule:系统默认规则,也是用的较多的一种规则。通过简单的轮询服务列表来选择服务器,其他的规则在很多情况下仍然使用RoundRobinRule。AvailabilityFilteringRule:顾名思义,有效性过滤规则。该规则会忽略一下服务器:无法连接的服务器:在默认情况下,如果 3 次连接失败,该服务器将会被置为 “短路”的状态,该状态将持续 30 秒,如果再次连接失败,“短路”状态的持 续 时 间 将 会 以 几 何 级 增 加 。 可 以 通 过 修 改 niws.loadbalancer<clientName>.connectionFailureCountThreshold 属性,来 配置连接失败的次数。高并发数过高的服务器:如果连接到该服务器的并发数过高,也会被这个规则忽略,可以通过修改<clientName>.ribbon.ActiveConnectionsLimit 属性来设定最高并发数。WeightedResponseTimeRule:为每个服务器赋予一个权重值,服务器的响应时间 越长,该权重值就是越少,这个规则会随机 选择服务器,这个权重值有可能会决定 服务器的选择。ZoneAvoidanceRule:该规则以区域、可用服务器为基础,进行服务器选择。使用 Zone 对服务器进行分类,可以理解为机架或者机房。BestAvailableRule:忽略“短路”的服务器,并选择并发数较低的服务器。RandomRule:顾名思义,随机选择可用的服务器。RetryRule:含有重试的选择逻辑,如果使用 RoundRobinRule 选择服务器无法连 接,那么将会重新选择服务器。代码配置/** * 该类为Ribbon的配置类 * 注意:该类不能放在主应用程序上下文@ComponentScan所扫描的包中,否则配置将会被所有Ribbon Client共享。 */@Configurationpublic class RibbonConfiguration { @Bean public IRule ribbonRule() { // 负载均衡规则,改为随机 return new RandomRule(); }}属性配置(推荐)属性配置的优先级高于代码配置。 shop-provider-user: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule饥饿加载默认情况下Ribbon是懒加载的——首次请求Ribbon相关类才会初始化,这会导致首次请求过慢的问题,你可以配置饥饿加载,让Ribbon在应用启动时就初始化。 ribbon: eager-load: enabled: true # 多个用,分隔 clients: shop-provider-user

September 19, 2019 · 1 min · jiezi

全栈之路微服务课程8Ribbon初识

简介nginx:服务器端负载均衡ribbon: 客户端负载均衡Ribbon是Netflix发布的负载均衡器,它可以帮我们控制HTTP和TCP客户端的行为。只需为Ribbon配置服务提供者地址列表,Ribbon就可基于负载均衡算法计算出要请求的目标服务地址。Ribbon默认为我们提供了很多的负载均衡算法,例如轮询、随机、响应时间加权等——当然,为Ribbon自定义负载均衡算法也非常容易,只需实现IRule 接口即可。图解Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,选择其中一个服务提供者实例。下图展示了Ribbon与Eureka配合使用时的大致架构。 客服端配置 以shop-consumer-movie服务为例修改MovieApplication.java 修改调用方式目标服务改成了http://shop-provider-user/users/{id} ,也就是http://{目标服务名称}/{目标服务端点} 的形式,Ribbon会自动在实际调用时,将目标服务名替换为该服务的IP和端口。 @RequestMapping("/movies")@RestControllerpublic class MovieController { @Autowired private RestTemplate restTemplate; @GetMapping("/users/{id}") public User findById(@PathVariable Long id) { // 这里用到了RestTemplate的占位符能力// User user = this.restTemplate.getForObject("http://localhost:8000/users/{id}", User.class, id); User user = this.restTemplate.getForObject("http://shop-provider-user/users/{id}", User.class, id); // ...电影微服务的业务... return user; }}服务端多端口启动 访问http://localhost:8010/movies/users/1 多次,会发现两个user服务实例都会打印日志。

September 19, 2019 · 1 min · jiezi

跟我学SpringCloud-第六篇Spring-Cloud-Config-Github配置中心

SpringCloud系列教程 | 第六篇:Spring Cloud Config Github配置中心Springboot: 2.1.6.RELEASESpringCloud: Greenwich.SR1 如无特殊说明,本系列教程全采用以上版本 随着分布式项目越来越大,勤劳的程序猿们会开始面临一个挑战,配置文件会越来越繁杂,虽然spring提供了一个鸡肋版的解决方案,spring.profiles.active,在大型的分布式项目体系中,聊胜于无吧,手动维护配置文件的痛苦,生产,UAT,测试,开发环境的隔离,额外的配置文件,如:logback.xml日志的配置文件,bootstrap.properties配置文件,当系统中有几十个服务,相应的会有上百个配置文件,简直就是史诗级的灾难大片,每次发布上线,都要手动去检查配置文件,相应的服务都需要重启,那么,有没有一种方案,可以自动更新配置,并且对版本做出相应的控制,恰好,springcloud为我们提供了这样一种工具,虽然很多方面都还不完善,配置能力比较弱,但是也给我们提供了一种思路。 市面上有很多配置中心,BAT每家都出过,360的QConf、淘宝的diamond、百度的disconf都是解决这类问题。国外也有很多开源的配置中心Apache Commons Configuration、owner、cfg4j等等。这些开源的软件以及解决方案都很优秀,也存在这样或者那样的缺陷。今天我们要了解的Spring Cloud Config,可以无缝的和spring体系相结合,够方便够简单颜值高。 1. Spring Cloud Config在介绍Spring Cloud Config之前,我们可以先凭空想一下一个配置中心需要提供的核心功能有哪些: 提供客户端和服务端的支持提供各个环境的配置配置文件修改后可以快速生效可以提供不同版本的管理可以支持不同的语言(java、.Net、Delphi、node等)支持一定数量的并发高可用(防止意外宕机导致配置不可用)Spring Cloud Config项目是一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。Spring cloud使用git或svn存放配置文件,默认情况下使用git,我们先以git为例做一套示例。 首先在github上面创建了一个文件夹springcloud-config用来存放配置文件,为了模拟生产环境,我们创建以下三个配置文件: // 开发环境springcloud-config-dev.properties// 测试环境springcloud-config-test.properties// 生产环境springcloud-config-pro.properties每个配置文件中都写一个属性springcloud.hello,属性值分别是 hello dev/test/pro。下面我们开始配置server端 2. Server端1. pom.xml<?xml version="1.0" encoding="UTF-8"?><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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.springcloud</groupId> <artifactId>config-server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>config-server</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>2. 配置文件server: port: 8080spring: application: name: spring-cloud-config-server cloud: config: server: git: uri: https://github.com/meteor1993/SpringCloudLearning # git仓库的地址 search-paths: chapter6/springcloud-config # git仓库地址下的相对地址,可以配置多个,用,分割。 username: #Git仓库用户名 password: #Git仓库密码Spring Cloud Config也提供本地存储配置的方式。我们只需要设置属性spring.profiles.active=native,Config Server会默认从应用的src/main/resource目录下检索配置文件。也可以通过spring.cloud.config.server.native.searchLocations=file:E:/properties/属性来指定配置文件的位置。虽然Spring Cloud Config提供了这样的功能,但是为了支持更好的管理内容和版本控制的功能,还是推荐使用git的方式。 ...

September 10, 2019 · 2 min · jiezi

跟我学SpringCloud-第五篇熔断监控Hystrix-Dashboard和Turbine

SpringCloud系列教程 | 第五篇:熔断监控Hystrix Dashboard和TurbineSpringboot: 2.1.6.RELEASESpringCloud: Greenwich.SR1 如无特殊说明,本系列教程全采用以上版本 Hystrix-dashboard是一款针对Hystrix进行实时监控的工具,通过Hystrix Dashboard我们可以在直观地看到各Hystrix Command的请求响应时间, 请求成功率等数据。但是只使用Hystrix Dashboard的话, 你只能看到单个应用内的服务信息, 这明显不够。我们需要一个工具能让我们汇总系统内多个服务的数据并显示到Hystrix Dashboard上, 这个工具就是Turbine。 1. Hystrix Dashboard创建一个新的项目hystrix-dashboard,延用上一篇文章提到的eureka和producer两个项目。 1. hystrix-dashboard pom.xml 依赖包管理<?xml version="1.0" encoding="UTF-8"?><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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.springcloud</groupId> <artifactId>hystrix-dashboard</artifactId> <version>0.0.1-SNAPSHOT</version> <name>hystrix-dashboard</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>前面介绍过的包我这里不再多说,讲几个前面没有见过的包: ...

September 10, 2019 · 2 min · jiezi

跟我学SpringCloud-第四篇熔断器Hystrix

Springboot: 2.1.6.RELEASESpringCloud: Greenwich.SR1 如无特殊说明,本系列教程全采用以上版本 1. 熔断器服务雪崩在正常的微服务架构体系下,一个业务很少有只需要调用一个服务就可以返回数据的情况,这种比较常见的是出现在demo中,一般都是存在调用链的,比如A->B->C->D,如果D在某一个瞬间出现问题,比如网络波动,io偏高,导致卡顿,随着时间的流逝,后续的流量继续请求,会造成D的压力上升,有可能引起宕机。 你以为这就是结束么,图样图森破,这才是噩梦的开始,在同一个调用链上的ABC三个服务都会随着D的宕机而引发宕机,这还不是结束,一个服务不可能只有一个接口,当它开始卡顿宕机时,会影响到其他调用链的正常调用,最终导致所有的服务瘫痪。 如下图所示: 熔断器相信大家都知道家用电闸,原来老式的电闸是使用保险丝的(现在很多都是空气开关了),当家里用电量过大的时候,保险丝经常烧断,这么做是保护家里的用电器,防止过载。 熔断器的作用和这个很像,它可以实现快速失败,如果在一段时间内服务调用失败或者异常,会强制要求当前调用失败,不在走远程调用,走服务降级操作(返回固定数据或者其他一些降级操作)。从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可以自动诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。 熔断器模式就像是那些容易导致错误的操作的一种代理。这种代理能够记录最近调用发生错误的次数,然后决定使用允许操作继续,或者立即返回错误。 Hystrix会有一个熔断时间窗口,具体转换逻辑如下: 熔断器就是保护服务高可用的最后一道防线。 2. Hystrix1. 断路器机制断路器很好理解, 当Hystrix Command请求后端服务失败数量超过一定比例(默认50%), 断路器会切换到开路状态(Open)。这时所有请求会直接失败而不会发送到后端服务。断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN)。这时会判断下一次请求的返回情况, 如果请求成功, 断路器切回闭路状态(CLOSED), 否则重新切换到开路状态(OPEN)。Hystrix的断路器就像我们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 并且断路器有自我检测并恢复的能力。 2. FallbackFallback相当于是降级操作。对于查询操作, 我们可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值。fallback方法的返回值一般是设置的默认值或者来自缓存。 3. 资源隔离在Hystrix中, 主要通过线程池来实现资源隔离。通常在使用的时候我们会根据调用的远程服务划分出多个线程池。例如调用产品服务的Command放入A线程池, 调用账户服务的Command放入B线程池。这样做的主要优点是运行环境被隔离开了。这样就算调用服务的代码存在bug或者由于其他原因导致自己所在线程池被耗尽时, 不会对系统的其他服务造成影响。但是带来的代价就是维护多个线程池会对系统带来额外的性能开销。如果是对性能有严格要求而且确信自己调用服务的客户端代码不会出问题的话, 可以使用Hystrix的信号模式(Semaphores)来隔离资源。 3. Feign Hystrix上一篇我们使用了producer和consumers,熔断器是只作用在服务调用端,因此上一篇使用到的consumers我们可以直接拿来使用。因为,Feign中已经依赖了Hystrix所以在maven配置上不用做任何改动。 1. 配置文件application.yml新增server: port: 8081spring: application: name: spring-cloud-consumerseureka: client: service-url: defaultZone: http://localhost:8761/eureka/feign: hystrix: enabled: true其中新增了feign.hystrix.enabled = true 2. 创建fallback类,继承与HelloRemote实现回调的方法package com.springcloud.consumers.fallback;import com.springcloud.consumers.remote.HelloRemote;import org.springframework.stereotype.Component;import org.springframework.web.bind.annotation.RequestParam;/** * Created with IntelliJ IDEA. * * @User: weishiyao * @Date: 2019/7/2 * @Time: 23:14 * @email: inwsy@hotmail.com * Description: */@Componentpublic class HelloRemoteFallBack implements HelloRemote { @Override public String hello(@RequestParam(value = "name") String name) { return "hello " + name + ", i am fallback massage"; }}3. 添加fallback属性在HelloRemote类添加指定fallback类,在服务熔断的时候返回fallback类中的内容。 ...

September 10, 2019 · 1 min · jiezi

跟我学SpringCloud-第三篇服务的提供与Feign调用

Springboot: 2.1.6.RELEASESpringCloud: Greenwich.SR1 如无特殊说明,本系列教程全采用以上版本 上一篇,我们介绍了注册中心的搭建,包括集群环境吓注册中心的搭建,这篇文章介绍一下如何使用注册中心,创建一个服务的提供者,使用一个简单的客户端去调用服务端提供的服务。 本篇文章中需要三个角色,分别是服务的提供者,服务的消费者,还有一个是上一篇文章的主角——注册中心Eureka(使用单机版本即可,本篇的示例也会使用单机版本的Eureka)。 整体流程为: 先启动注册中心Eureka启动服务的提供者将提供服务,并将服务注册到注册中心Eureka上启动服务的消费者,在注册中心中找到服务并完成消费1. 服务提供者1. pom.xml<?xml version="1.0" encoding="UTF-8"?><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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.springcloud</groupId> <artifactId>producer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>producer</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>2. 配置文件application.ymlserver: port: 8080spring: application: name: spring-cloud-producereureka: client: service-url: defaultZone: http://localhost:8761/eureka/3. 启动类ProducerApplication.java增加@EnableEurekaClient,如果是其他注册中心可以使用注解@EnableDiscoveryClient来进行服务的注册 ...

September 10, 2019 · 2 min · jiezi

跟我学SpringCloud-第二篇注册中心Eureka

SpringCloud系列教程 | 第二篇:注册中心EurekaSpringboot: 2.1.6.RELEASESpringCloud: Greenwich.SR1 如无特殊说明,本系列教程全采用以上版本 Eureka是Netflix开源的一款提供服务注册和发现的产品,它提供了完整的Service Registry和Service Discovery实现。也是springcloud体系中最重要最核心的组件之一。 注册中心的意义注册中心管理各种服务功能包括服务的注册、发现、熔断、负载、降级等,比如dubbo admin后台的各种功能。 有了注册中心,调用关系的变化,画几个简图来看一下。 服务A调用服务B 有了注册中心之后,任何一个服务都不在是直连的,都需要通过注册中心去调用。 如果是一个连续调用: 服务A调用服务B,服务B调用服务C 这里如果加上注册中心,整个调用流程就会分为两步,服务A先从注册中心请求服务B,服务B再从注册中心请求服务C 上面的示例只是描述了两三个服务之间的互相调用,可能加上注册中心还会稍显繁琐,如果一条调用链上面有几十个服务(这个丝毫不是开玩笑哦,正常的业务流程中很可能出现这种复杂的调用过程),在工作中我就遇到过超过20个服务的互相调用,这种复杂业务场景的互相调用,如果不使用注册中心,画出来的图会连成一个网状结构,单从图上面已经很难找出服务的上下游关系了。其中如果一个服务有改动,就会牵扯到上下游多台机器的重启,整个架构设计完全耦合在一起,每次改动所需要的工作量完全超出想象。通过注册中心去注册服务,完全不在需要关心上下游机器的ip地址,由几台服务器组成,是否重启才会生效,注册中心已经帮我们把服务的注册和发现做好了,我们只需要知道注册中心在哪里,对应的服务名是什么就ok啦~~ 由于各种服务都注册到了服务中心,就有了去做很多高级功能条件。比如几台服务提供相同服务来做均衡负载;监控服务器调用成功率来做熔断,移除服务列表中的故障点;监控服务调用时间来对不同的服务器设置不同的权重等等。 Netflix的前世今生在说Eureka之前我们先了解一下Netflix这家公司: 以下介绍来自于百度百科: Netflix(Nasdaq NFLX) 成立于1997年,是一家在线影片租赁提供商,主要提供Netflix超大数量的DVD并免费递送,总部位于美国加利福尼亚州洛斯盖图。Netflix已经连续五次被评为顾客最满意的网站。可以通过PC、TV及iPad、iPhone收看电影、电视节目,可通过Wii,Xbox360,PS3等设备连接TV。Netflix大奖赛从2006年10月份开始,Netflix公开了大约1亿个1-5的匿名影片评级,数据集仅包含了影片名称。评价星级和评级日期,没有任何文本评价的内容。比赛要求参赛者预测Netflix的客户分别喜欢什么影片,要把预测的效率提高10%以上。 总而言之,这是一家全球最大的(可能要排除国内的,具体不清楚)流媒体公司,最开始见这个单子是在各种美剧或者电影的开头,顺手百度了一下,Netflix拍摄的代表性的美剧有《纸牌屋》、《毒枭》、《怪奇物语》。springcloud的微服务就是基于Netflix这家公司的开源产品来做的。 Netflix的开源框架组件已经在Netflix的大规模分布式微服务环境中经过多年的生产实战验证,正逐步被社区接受为构造微服务框架的标准组件。Spring Cloud开源产品,主要是基于对Netflix开源组件的进一步封装,方便Spring开发人员构建微服务基础框架。对于一些打算构建微服务框架体系的公司来说,充分利用或参考借鉴Netflix的开源微服务组件(或Spring Cloud),在此基础上进行必要的企业定制,无疑是通向微服务架构的捷径。 Eureka按照官方介绍: Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud for locating services for the purpose of load balancing and failover of middle-tier servers.Eureka 是一个基于 REST 的服务,主要在 AWS 云中使用, 定位服务来进行中间层服务器的负载均衡和故障转移。 ...

September 7, 2019 · 2 min · jiezi

跟我学SpringCloud-第一篇介绍

SpringCloud系列教程 | 第一篇:介绍首先讲一下我为什么要写这一系列的文章,现在网上大量的springcloud相关的文章,使用的springboot和springcloud的版本都相对比较老,很多还是在使用springboot1.x的版本,如果尝鲜想使用springboot2.x的版本,很多配置都和之前的不一样,有了大量的修改,很多刚开始学习的朋友可能试一试搭不起来就放弃了,本系列教程就是帮助刚接触springcloud的朋友简单上手,快速起步。springboot进入2.x以后,历经一年多的修修改改,终于到了2.1.x的版本,相对较为稳定,本系列教程将使用目前最新的springboot(2.1.6.RELEASE)和springcloud(Greenwich.SR1)版本(如无特殊说明)。 1. 什么是springcloud?Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。 -- 以上内容摘自百度百科 百度百科的解释看起来文绉绉的,可能刚接触的朋友很多新名词都看不大懂。我的理解就是springcloud为项目微服务化提供了一系列的工具,常用的包括注册中心,断路器,配置中心,消息总线等等,简单理解就是springcloud提供了一系列的工具或者框架,当然,还包含很多设计思想。 2. 微服务架构选型为什么选择springcloud而不会dubbo?这里仅代表我的个人观点,欢迎交流:) 说到这个,就要先聊一下什么是微服务了。 微服务(Microservices): 是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。 Dubbo: Dubbo是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。简单的说,Dubbo 就是个服务框架,说白了就是个远程服务调用的分布式框架。 springcloud: springcloud是一整套的微服务解决方案,有一张很有名的对比图可以清晰看到dubbo和springcloud功能对比,如下: 如果微服务架构选型选择了dubbo,那么后续一些其他的组件,还需要我们自己去评估目前市面上一些开源的组件是否符合我们的需要,而如果架构选型选择了springcloud,那么就能省心很多,springcloud本身就提供了一整套的微服务的解决方案,虽然有很多组件目前看起来依然不是很成熟,不过这依然大大降低了我们在架构选型上的工作量。 3. springcloud一些常用组件以下排序不分先后 Spring Cloud Config 配置中心: 利用 Git 集中管理程序的配置。Spring Cloud Netflix Eureka: 服务中心(类似于管家的概念,需要什么直接从这里取,就可以了),一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移。Spring Cloud Netflix Hystrix 熔断器: 容错管理工具,旨在通过熔断机制控制服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Spring Cloud Netflix Zuul 网关: 是在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Web 网站后端所有请求的前门。Spring Cloud Netflix Archaius: 配置管理 API,包含一系列配置管理API,提供动态类型化属性、线程安全配置操作、轮询框架、回调机制等功能。Spring Cloud Netflix Ribbon: 负载均衡。Spring Cloud Netflix Fegin: REST客户端。Spring Cloud Bus: 消息总线,利用分布式消息将服务和服务实例连接在一起,用于在一个集群中传播状态的变化。Spring Cloud Security: 安全控制。Spring Cloud Sleuth: 分布式链路监控,SpringCloud 应用的分布式追踪系统,和 Zipkin,HTrace,ELK 兼容。Spring Cloud Stream: 消息组件,基于 Redis,Rabbit,Kafka 实现的消息微服务,简单声明模型用以在 Spring Cloud 应用中收发消息。下面一篇,开始springcloud的搭建。 ...

September 7, 2019 · 1 min · jiezi

SpringCloud微服务架构系列-服务的注册发现与调用

简介众所周知,SpringCloud是一个微服务框架,本质上是基于SpringBoot的一整套实现微服务的框架。包含了服务发现、负载均衡、断路器、服务网关、分布式配置等组件。其中服务注册、发现又有Netflix的Eureka,阿里的Dubbo,Apache的Consul等,本篇文章将以Eureka进行讲解。 EurekaEureka是Netflix开发的服务发现框架,本身是一个基于REST的服务。由两个组件组成: Eureka Server:也被称作是服务注册中心,用于提供服务的注册与发现。Eureka Client:包含服务消费者与服务生产者。图片来源于互联网,如侵权可联系博主 Eureka的作用就是将我们定义的API接口注册到Eureka服务器上,方便管理,调用的时候只需要知道服务名就可以,不再通过IP加端口号的方式调用,利于解耦。 服务的注册与发现一、新建主项目选择Maven,点击Next填写相关信息,点击Next确定信息无误后,点击Finish将src文件夹删除(如果有的话)打开pom.xml文件,添加如下代码。 <!--必须指定该父模块,不然后面子模块启动会报错,很麻烦--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <!--父模块类型必须为pom--> <packaging>pom</packaging> <!--包含子模块--> <modules> </modules> <!--在父模块添加web依赖,子模块可继承该依赖--> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>二、新建Eureka Server在项目上右键新建Module选择Spring Initializr,点击Next,填写相关信息,Next选择导入Eureka Server 依赖,Next,确认信息,点击Finish打开Server模块的pom.xml文件,修改 <parent>标签 <parent> <groupId>org.sakura</groupId> <artifactId>eureka</artifactId> <version>1.0-SNAPSHOT</version> </parent>打开主模块的pom.xml文件,在<modules>标签添加相应的子模块 <!--包含子模块--> <modules> <module>Server</module> </modules>将Server模块中的application.properties重命名为application.yml,并添加如下信息,也可直接使用properties文件类型(需修改如下代码) # Eureka 服务注册与发现的组件server: port: 8080spring: application: #服务名,很重要 name: servereureka: instance: hostname: localhost #将prefer-ip-address设为开启时,将默认显示服务的地址,而非主机名# prefer-ip-address: true #以IP地址注册到服务中心,相互注册使用IP地址# prefer-ip: 127.0.0.1 #显式设置服务的地址 client: # 下面两个 false 表明自己是 server,而非 client register-with-eureka: false # 不要使用 eureka 服务进行注册,即在管理界面不可见 fetch-registry: false # 不要在本地缓存注册表信息 service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/# defaultZone: http://127.0.0.1:${server.port}/eureka/ server: #开启自我保护模式 enable-self-preservation: false #清理无效节点,默认60*1000毫秒,即60秒 eviction-interval-timer-in-ms: 5000修改Server模块的启动类,添加@EnableEurekaServer注解即可 ...

August 28, 2019 · 2 min · jiezi

专访宜信梁鑫回归架构本质重新理解微服务

本期专访宜信开发平台(SIA)负责人梁鑫,与大家一起聊聊微服务架构及其在企业落地应用的策略。 第一部分:微服务的诞生、演变以及应用策略 记者:近几年来,微服务架构设计方式被提出并在越来越多的企业中得以实践和落地,但对于刚开始接触微服务的人来说,还是不知道要从哪些方面开始了解。您能否结合软件架构的发展历史,聊聊微服务的发展与特征。 梁鑫:微服务本质上是一种架构的风格,如果要了解微服务,我认为需要先了解整个架构的发展脉络。 软件架构,总是在不断的演进中。如果把时间退回到二十年前,当时企业级领域研发主要推崇的还是C/S模式,PB、Delphi这样的开发软件是企业应用开发的主流。 随着时间的推移,我们发现标准化的客户端存在一些弊病,比如我有一千个终端,升级版本需要每一台终端都升级,这是非常麻烦的。然后,企业应用研发开始向互联网学习,把浏览器作为客户端来使用,就可以避免这个问题。因此,基于浏览器的B/S架构开始渐渐流行起来。 刚开始的时候是ASP,之后又出现了JSP,因为Java的预编译模式,让性能有了非常大的提升,随后基于Java语言的J2EE架构就变得越来越流行。至此,架构经历了从传统的C/S模式到B/S模式的转变。 B/S架构初期基本都是单体架构,各个系统比较独立,他们之间往往不需要进行交互,即使存在一些交互,也大多是数据层面的。那个阶段ETL工具发展得很快,就是为了解决这样的数据孤岛问题。 随着企业应用越来越多,系统之间相互的关系也越来越密切,系统之间实时交互访问的需求也越来越多。这个时候工程师们发现,不管是什么语言开发的软件,基本都支持一种叫做XML的语言,于是提出一种实时交互的技术解决方案:通过XML语言来进行企业应用系统之间的远程调用。由此,SOA的概念被提了出来,WebService开始流行。 当第二波互联网浪潮来临后,很多公司为了适应更加灵活的业务发展,用基于HTTP协议和Restful的架构风格替代了原先笨重的WebService,简洁清晰的JSON替代了XML。同时SOA架构中常常采用服务总线技术,无疑是给系统架构增加了一个异常麻烦的瓶颈。如果使用注册和发现的机制,让服务进程之间直接进行调用,更适合企业应用的发展。这就是微服务架构从技术方面来说的历史脉络。 在《微服务设计》中界定微服务有两个基本原则:松耦合&高内聚。即“把因相同因素变化的事情聚集在一起,把因不同因素变化的事情区隔开来。”至于微服务大小的划分并没有统一的标准,通俗地说,就是你觉得它的大小差不多,同时符合“松耦合&高内聚”的原则就可以。 微服务有很多的好处,大致列举一些。 异构:微服务可以帮助我们轻松采用不同的技术,并且理解这些新技术的好处。尝试新技术通常伴随着风险,但如果把服务切得很小了,总会存在一些点让你可以选择一个风险最小的服务采用新技术,并降低风险。弹性:很明显,微服务可以很好地处理服务不可用和功能降级的问题,因为它可以形成很多个节点。隔离:微服务架构将系统分解为独立运行单元,给系统带来更好的隔离性,独立的微服务在发生异常时更容易定位和隔离问题,隔离性也是服务扩展性的基础。扩展:庞大的单体服务只能作为一个整体进行扩展,即使系统中只有一小部分模块存在性能问题,也需要对整个系统进行扩展。而微服务架构可以根据性能需要对不同的模块进行水平扩展。部署简单:在微服务架构中,各个服务的部署是独立的,这样就可以更快地对特定部分的代码进行部署。服务出现问题也更容易快速回滚,同时敏捷的交付和部署带来了更好的业务需求响应体验。灵活:在微服务架构中,系统会开放很多接口供外部使用,当情况发生改变时,可以使用不同的方式构建应用。把单体应用分解成多个微服务,可以达到可复用、可组合的目的。记者:据悉,您之前发表过一篇文章“公司为什么需要建立一套统一的开发框架?”,您认为公司建立统一开发框架是为了解决什么问题? 梁鑫:这是一个仁者见仁智者见智的问题,每个人的出发点都不一样,有的人可能主张需要统一,有的人则可能排斥统一,结合我的经历和实践来看,我认为公司是需要建立统一开发框架的。 近十年,互联网的发展颠覆了很多传统行业,很多新兴公司如雨后春笋般的冒了出来,它们的业务增长非常快,公司规模也越来越大。这得益于中国经济的高速增长和互联网的快速发展。但这种高速的发展过程中伴随而来的是不可忽视的弊端: 弊端一:自我繁衍在公司快速的发展过程中,往往会出现这样一个链条。新增一块业务 —> 招聘一位高级技术人员 —> 围绕这位同事组建一支技术团队 —> 该业务基本由这只团队负责,然后就形成了一个闭环。当需要跟其他业务进行交互时,经常是技术负责人之间自行决定。这就形成了自我繁衍的状态。 弊端二:管控壁垒随着业务规模的快速发展,这个团队很快形成了一个部门,团队决策者通常会从自身利益考量,希望尽量减少对外部门的依赖,无论是技术选型、规范建立、组件选取、运行环境都能够自行掌控。 弊端三:断崖效应当这样的技术氛围一旦形成,单个员工对单个项目的影响就会变的非常巨大。一个产品经常会因为一两个核心员工的离职难以为继,最后不得不重新开发新的产品。 弊端四:资源浪费当每个团队都在试图构建自己完整的研发流程时。中间的技术研究、产品研发、运维管理就会出现非常多的资源浪费。 弊端五:难以考核怎么衡量一个川菜厨师和一个鲁菜厨师谁更优秀?当每个团队都是一个闭环,采用不同技术栈、不同的技术组件、不同的维护方式和规范时,已经无法从产出效率来判断一个团队的绩效,KPI 指标也就非常难以设立。 建立一套公司级的统一的开发平台可以有效解决上述问题。从技术层面来讲,如果可以形成公司级别的统一开发平台,会在实际的生产过程中带来非常大的收益。 首先,避免了重复性技术研究,节约了人力成本。在项目组之下构建一个基础的开发架构平台,把技术共性问题提炼出来,交给一个专门团队负责处理,让项目组把精力投入到业务中。其次,标准化了技术规范,提升了产品项目质量。做工程要千人一面,而不要千人千面。采用统一的开发平台后,在技术栈、技术组件、技术实现方案,甚至在代码规范上,就能形成标准化的技术输出模式,标准化带来的效果不仅仅是开发效率的快速提升,还有产品质量的大幅提升。再次,可以进行技术沉淀,提升公司整体的技术能力,避免陷入一个人的能力决定一个项目。技术的进步来源于不断的技术积累和沉淀,建立公司级别的统一开发框架(平台),项目团队基于该平台进行自身项目的研发,不再需要关注于底层技术实现,只需要关注业务即可。而且,专注于平台的同事为了更好地满足项目组的技术需求,对平台进行不断的改进,从而达到技术积累和沉淀的目标。最后,可以对研发的投入和产出进行衡量,对研发团队进行有效管理和考核。当基于同一开发平台的标准化技术规范建立起来后,对业务功能的代码实现就可以进行相对有效的评估和考量,可以避免因为技术实现差异而出现的种种问题。这对KPI的制定和考核是一个巨大的帮助。我从前年提出这样的一个思想,通过一年多的努力,已经在公司有了一定的成果。我们的统一开发平台定位于技术层面,其主要目的是为统一公司内相关产品研发和项目实施使用的技术架构和开发工具,有效提高统一技术支持力度,形成持续的技术积累手段,提升技术人员的利用率并降低对人员的依赖性,最终提升软件的规模化、流水线式的生产能力。 记者:最近“Spring Boot”、“Spring Cloud”等词总被提及,这些新的框架集合方案与传统的微服务框架相比有哪些优势?结合您的经验来看,您认为微服务未来的发展走向可能是什么? 梁鑫:我是公司内部较早研究Spring Cloud 技术栈的人,也是Spring Cloud中国社区的成员。Spring Cloud是在2017年一跃成为最流行的微服务开发框架。但是,这里有一个需要辩证看待的问题。“不是说使用了Spring Cloud框架就实现了微服务架构,具备了微服务架构的优势”,正确的理解应该是“使用Spring Cloud框架开发微服务架构系统,使系统具备微服务架构的优势。”Spring Cloud之所以能从其他框架中脱颖而出成为最火的框架,得益于其本身体系的完整性。这一点通过下图Spring Cloud、Dubbo和ServiceComb的对比可以比较直观地了解到。 另外,Spring在中国有广泛的群众基础,我也比较推崇这种“约定大于配置”的研发思想,不需要完全依赖标准化的东西。 我不敢妄谈微服务架构的未来走向。立足当下,我认为目前Spring Cloud+Docker容器化的技术是用于微服务架构的一个比较好的选择。我比较认可一个很有趣的说法是“基因架构”,意思是:架构从诞生之初就是为了改变的,所以你的架构越容易改变就越好。我觉得架构的未来会向这条路发展。 我们的统一开发平台的建设就是基于Spring Cloud技术栈。 记者:今年在软件研发行业比较热门的话题是“中台”,在架构层面也有人提出来要做微服务中台,对此您怎么看? 梁鑫:去年一个综艺节目带火了一句话,“盘它”。节目里有一句 “干干巴巴的,麻麻赖赖的,一点都不圆润,盘他!”。 后来说到什么就盘什么,也不管是什么东西,能不能握在手中,反正盘就是了。听起来是不是特别有魔性,然后就有了“万物皆可盘”这个段子。这本身其实只是一种调侃的讲法,也并不会真的有人看到什么就盘什么。有意思的是任何事情都可以再认真往深处想一想,你会不会也犯一些看似荒唐的错误呢?今年技术圈最火的一个名词就是“中台”,套用到这儿就变成了“万物皆可中台”,一个名词到处套,我认为很多公司应该避免盲目跟风,让“中台”成为名词陷阱。 面对一个新的技术或趋势,我们要先了解其来源和根本。中台的来源需要回溯到阿里。2015年阿里巴巴集团启动了中台战略,目标是要构建符合互联网大数据时代的,具有创新性、灵活性的‘大中台、小前台’的机制,即作为前台的一线业务会更敏捷、更快速地适用瞬息万变的市场,而中台将集合整个集团的运营数据能力、产品技术能力,对各前台业务形成强有力的支撑. 那阿里集团为什么要建立一个‘大中台、小前台’的架构呢?《企业IT架构转型之道——阿里巴巴中台战略思考与架构实战》一书对此有详细介绍。从阿里共享业务事业部的发展史说起,起初,阿里只有一个淘宝事业部,后来成立了天猫事业部,此时淘宝的技术团队同时支撑着这两个事业部。当时的淘宝和天猫的电商系统像我们很多大型企业的一样是分为两套独立的烟囱式体系,两套体系中都包含的有商品、交易、支付、评价、物流等功能。因为上述原因,阿里集团又成立了共享业务事业部,其成员主要来自之前的淘宝技术团队,同时将两套电商业务做了梳理和沉淀,将两个平台中公共的、通用的业务功能沉淀到共享事业部,避免重复建设和维护。 作为一个拥有10多年编程经验的老兵,我经常思考的一个问题就是系统发展的规律,透过其形领会其意,回顾架构的发展,我认为可以总结出一点:“快”。当然这个快是有前提的,比如正确率、资源限制,要在稳定、尽量减少资源消耗的情况下求快。 “快”可以再次分解,从开发的角度来看,编写代码要快、开发要快、功能测试要快、环境部署要快、服务启停要快;从生产的角度来看,程序运行的速度要快、高并发之下还是要快等。 微服务架构之所以流行,因为把服务拆小了,可以高度复用,不用经常编写和修改代码,节省了非常多的时间;容器化技术之所以流行,因为容器化技术可以使得生产环境和测试环境一致,节省了大量的环境部署时间、减少了出错的可能性,还可以随意增加容器节点,增强业务处理能力,保证高并发下的快速响应。分布式架构也是如此,微服务架构其实就是分布式架构的一种演化。万变不离其宗,都是追求“快”。 回到“中台”这个话题,建设中台的目标是避免重复建设和维护,快速响应需求。后台和平台的系统比较稳定,一般不轻易发生变化,而且从稳定性考虑,应该尽量减少后台和平台系统更新的次数,前端系统因为要适用用户的需求而不断变化,这样前台和后台在对接时就产生了一个求变一个求不变的矛盾,这时我们希望在两者之间建立一个中间平台,把前端后台可重复利用的东西集中到这个中间平台来,重新封装组合对外提供服务,这是符合“快”的思想的。 这是中台的来源和根本,企业在建设中台之前,一定要先了解这些,看所要建设的中台是否符合“避免重复建设和维护”的思想,是否符合“快”的原则。 第二部分:微服务在业务中的应用需要解决的关键问题 记者:宜信在今年开源了微服务任务调度平台SIA-TASK,这个平台在宜信技术团队内部有广泛的应用,开源后也得到了很多开发者的支持。您能否介绍一下这个平台的设计思路以及核心功能?(设计开发这个平台想要解决什么问题) 梁鑫:前面谈到中台,其实我认为“中台”只是一个名称而已,只要符合“避免重复建设和维护”和“快”两个原则,叫什么都可以,比如我们的微服务调度平台SIA-TASK,就是一个很像中台的系统。 介绍SIA-TASK的设计思想之前,我先介绍一下它的背景。无论是互联网应用或者企业级应用,都充斥着大量的批处理任务。常常需要一些任务调度系统帮助开发者解决问题。随着微服务化架构的逐步演进,单体架构逐渐演变为分布式、微服务架构。很多原先的任务调度平台已经不能满足业务系统的需求,于是出现了一些基于分布式的任务调度平台。这些平台各有其特点,也各有不足之处,比如不支持任务编排、与业务高耦合、不支持跨平台等问题,不符合新一代微服务架构的需求,因此我们开发了微服务任务调度平台(SIA-TASK)。 SIA-TASK 使用 SpringBoot 体系作为架构选型,基于Quartz及Zookeeper进行二次开发,支持相应的特性功能,SIA-TASK 的逻辑架构图如下图所示: ...

August 20, 2019 · 1 min · jiezi

Spring-cloud-一步步实现广告系统-21-系统错误汇总

广告系统学习过程中问题答疑博客园Eureka集群启动报错Answer 因为Eureka在集群启动过程中,会连接集群中其他的机器进行数据同步,在这个过程中,如果别的服务还没有启动完成,就会出现Connection refused: connecterror,当其他节点启动完成之后,报错就会消失。 AdSearch 服务启动报错2019-08-16 10:27:57.038 ERROR 73180 --- [ main] o.s.boot.SpringApplication : Application run failedjava.lang.IllegalStateException: Failed to introspect Class [org.springframework.boot.autoconfigure.kafka.KafkaAnnotationDrivenConfiguration] from ClassLoader [sun.misc.Launcher$AppClassLoader@18b4aac2] at org.springframework.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:760) ~[spring-core-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:725) ~[spring-core-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:710) ~[spring-core-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.boot.test.mock.mockito.DefinitionsParser.parse(DefinitionsParser.java:62) ~[spring-boot-test-2.1.5.RELEASE.jar:2.1.5.RELEASE] at org.springframework.boot.test.mock.mockito.MockitoPostProcessor.postProcessBeanFactory(MockitoPostProcessor.java:141) ~[spring-boot-test-2.1.5.RELEASE.jar:2.1.5.RELEASE] at org.springframework.boot.test.mock.mockito.MockitoPostProcessor.postProcessBeanFactory(MockitoPostProcessor.java:133) ~[spring-boot-test-2.1.5.RELEASE.jar:2.1.5.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:286) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:174) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:705) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:531) ~[spring-context-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) ~[spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) ~[spring-boot-2.1.5.RELEASE.jar:2.1.5.RELEASE] at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:127) [spring-boot-test-2.1.5.RELEASE.jar:2.1.5.RELEASE] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44) [spring-boot-test-autoconfigure-2.1.5.RELEASE.jar:2.1.5.RELEASE] at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12] at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12] at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190) [spring-test-5.1.7.RELEASE.jar:5.1.7.RELEASE] at org.junit.runner.JUnitCore.run(JUnitCore.java:137) [junit-4.12.jar:4.12] at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) [junit-rt.jar:na] at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) [junit-rt.jar:na] at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) [junit-rt.jar:na] at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) [junit-rt.jar:na]Caused by: java.lang.NoClassDefFoundError: Lorg/springframework/kafka/listener/AfterRollbackProcessor; at java.lang.Class.getDeclaredFields0(Native Method) ~[na:1.8.0_171] at java.lang.Class.privateGetDeclaredFields(Class.java:2583) ~[na:1.8.0_171] at java.lang.Class.getDeclaredFields(Class.java:1916) ~[na:1.8.0_171] at org.springframework.util.ReflectionUtils.getDeclaredFields(ReflectionUtils.java:755) ~[spring-core-5.1.7.RELEASE.jar:5.1.7.RELEASE] ... 40 common frames omittedCaused by: java.lang.ClassNotFoundException: org.springframework.kafka.listener.AfterRollbackProcessor at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_171] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_171] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) ~[na:1.8.0_171] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_171] ... 44 common frames omitted2019-08-16 10:27:57.119 INFO 73180 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$2c3f141a] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)查看这个错误,是在加载org.springframework.kafka.listener.AfterRollbackProcessor的时候,没有找到对应的class,可是我们明明添加了依赖呀? ...

August 19, 2019 · 2 min · jiezi

Spring-cloud-一步步实现广告系统-20-系统运行测试

系统运行经过长时间的编码实现,我们的主体模块已经大致完成,因为之前我们都是零散的对各个微服务自行测试,接下来,我们需要将所有的服务模块进行联调测试,Let's do it. 清除测试数据&测试文件我们在实现各个服务的过程中,添加了不少的测试文件和测试数据,为了不影响我们最终的展示效果,我们先将之前的历史数据清理掉。 drop database advertisement;依然使用flyway 添加我们的测试数据: INSERT INTO `ad_user` VALUES (10,'Isaac','B2E56F2420D73FEC125D2D51641C5713',1,'2019-08-14 20:29:01','2019-08-14 20:29:01');INSERT INTO `ad_creative` VALUES (10,'第一个创意',1,1,720,1080,1024,0,1,10,'https://www.life-runner.com','2019-08-14 21:31:31','2019-08-14 21:31:31');INSERT INTO `ad_plan` VALUES (10,10,'推广计划名称',1,'2019-11-28 00:00:00','2019-11-20 00:00:00','2019-11-19 20:42:27','2019-08-14 20:57:12');INSERT INTO `ad_unit` VALUES (10,10,'第一个推广单元',1,1,10000000,'2019-11-20 11:43:26','2019-11-20 11:43:26'),(12,10,'第二个推广单元',1,1,15000000,'2019-01-01 00:00:00','2019-01-01 00:00:00');INSERT INTO `ad_unit_district` VALUES (10,10,'陕西省','西安市'),(11,10,'陕西省','西安市'),(12,10,'陕西省','西安市'),(14,10,'山西省','阳泉市');INSERT INTO `ad_unit_hobby` VALUES (10,10,'爬山'),(11,10,'读书'),(12,10,'写代码');INSERT INTO `ad_unit_keyword` VALUES (10,10,'汽车'),(11,10,'火车'),(12,10,'飞机');INSERT INTO `relationship_creative_unit` VALUES (10,10,10);导出测试索引文件可参考 全量索引传送门 ,或者下载源码github传送门 / gitee传送门 ,运行mscx-ad-db项目,然后执行 http://localhost:7002/ad-db/export/plan。 开发自测 Unit Test一个合格的开发人员是绝对不能容忍自己的代码存在傻~ bug 存在的,但是个人总会有犯错的时候,那么我们要怎么避免此类非业务发展导致的基础问题呢,这时候,开发的UT就显得非常Important了。 广告投放系统测试我们来编写投放系统的单元测试,如下图:单元测试模块的目录结构与我们的正式项目结构保持一致,如果你需要给单元测试编写特例化配置,把我们的application.yml配置文件copy到UT中就可以了,这里就不做赘述。 ...

August 19, 2019 · 2 min · jiezi

SpringCloud微服务05Zuul组件实现路由网关控制

一、Zuul组件简介1、基础概念Zuul 网关主要提供动态路由,监控,弹性,安全管控等功能。在分布式的微服务系统中,系统被拆为了多个微服务模块,通过zuul网关对用户的请求进行路由,转发到具体的后微服务模块中。2、Zuul的作用1)按照不同策略,将请求转发到不同的服务上去;2)聚合API接口,统一对外暴露,提高系统的安全性; 3)实现请求统一的过滤,以及服务的熔断降级; 3、案例结构 启动顺序如下: # 注册中心node05-eureka-7001# 两个服务提供者node05-provider-6001node05-provider-6002# 网关控制node05-zuul-7002启动成功后,注册中心展示如下: 二、Zuul使用详解1、核心依赖<!-- 路由网关 --><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId></dependency>2、核心配置文件server: port: 7002spring: application: name: cloud-node05-parenteureka: instance: prefer-ip-address: true client: service-url: defaultZone: http://registry01.com:7001/eureka/zuul: # 前缀,可以用来做版本控制 prefix: /v1 # 禁用默认路由,执行配置的路由 ignored-services: "*" routes: # 配置6001接口微服务 pro6001: serviceId: node05-provider-6001 path: /api-6001/** # 配置6002接口微服务 pro6002: serviceId: node05-provider-6002 path: /api-6002/**启动类注解:@EnableZuulProxy3、统一服务降级实现FallbackProvider接口,自定义响应提示。 @Componentpublic class FallBackConfig implements FallbackProvider { private static final Logger LOGGER = LoggerFactory.getLogger(FallBackConfig.class) ; @Override public ClientHttpResponse fallbackResponse(Throwable cause) { // 捕获超时异常,返回自定义信息 if (cause instanceof HystrixTimeoutException) { return response(HttpStatus.GATEWAY_TIMEOUT); } else { return fallbackResponse(); } } private ClientHttpResponse response(final HttpStatus status) { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() { return status; } @Override public int getRawStatusCode() { return status.value(); } @Override public String getStatusText() { return status.getReasonPhrase(); } @Override public void close() { LOGGER.info("close"); } @Override public InputStream getBody() { String message = "{\n" + "\"code\": 200,\n" + "\"message\": \"微服务飞出了地球\"\n" + "}"; return new ByteArrayInputStream(message.getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } @Override public String getRoute() { return "*"; } @Override public ClientHttpResponse fallbackResponse() { return response(HttpStatus.INTERNAL_SERVER_ERROR); }}4、统一过滤器继承ZuulFilter类,自定义过滤动作。 ...

August 18, 2019 · 2 min · jiezi

SpringCloud微服务06Config组件实现配置统一管理

一、Config简介在微服务系统中,服务较多,相同的配置:如数据库信息、缓存、参数等,会出现在不同的服务上,如果一个配置发生变化,需要修改很多的服务配置。spring cloud提供配置中心,来解决这个场景问题。 系统中的通用配置存储在相同的地址:GitHub,Gitee,本地配置服务等,然后配置中心读取配置以restful发布出来,其它服务可以调用接口获取配置信息。二、配置服务端1、项目结构 核心注解:@EnableConfigServer2、核心依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId></dependency>3、核心配置文件这里注意读取文件的配置 active :native,读取本地配置;active :git,读网络仓库配置;server: port: 9001spring: application: name: config-server-9001 profiles: # 读取本地 # active: native # 读取Git active: git cloud: config: server: native: search-locations: classpath:/config git: # 读取的仓库地址 uri: https://gitee.com/cicadasmile/spring-cloud-config.git # 读取仓库指定文件夹下 search-paths: /cloudbaseconfig # 非公开需要的登录账号 username: password: label: master4、读取配置内容不同的环境读取的结果不同。 info: date: 20190814 author: cicada sign: develop version: V1.0三、配置客户端1、核心依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId></dependency>2、核心配置文件在上面的配置中心,配置读取Git资源,所以这里的配置也就是读取Git资源。 server: port: 8001spring: application: name: config-client-8001 profiles: active: dev cloud: config: # 读取本地配置 --------------------------- #uri: http://localhost:9001 ## 读取策略:快速失败 #fail-fast: true ## 读取的文件名:无后缀 #name: client-8001 ## 读取的配置环境 #profile: dev # client-8001-dev.yml # ---------------------------------------- # github上的资源名称 ----------------------- name: client-8001 # 读取的配置环境 profile: dev label: master # 本微服务启动后,通过配置中心6001服务,获取GitHub的配置文件 uri: http://localhost:9001 # ----------------------------------------3、测试接口@RestControllerpublic class ClientController { @Value("${info.date}") private String date ; @Value("${info.author}") private String author ; @Value("${info.sign}") private String sign ; @Value("${info.version}") private String version ; /** * 获取配置信息 */ @RequestMapping("/getConfigInfo") public String getConfigInfo (){ return date+"-"+author+"-"+sign+"-"+version ; }}四、基于Eureka配置上面的模式,通过服务中心,直接获取配置。下面把注册中心Eureka加进来。 ...

August 18, 2019 · 1 min · jiezi

分布式SpringBootSpringCloudEureka

环境Java version 1.8SpringBoot version 2.1.7搭建注册中心 Eureka-serverpom.xml 依赖如下所示:<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifactId> <version>1.1.1</version> </dependency></dependencies>配置 Eureka application.properties# 应用启动端口server.port=8090# 注册中心管理中的 应用名称spring.application.name=eureka-server# 登陆注册管理中的的账号密码spring.security.user.roles=SUPERUSERspring.security.user.name=eurekaspring.security.user.password=123456# 是否把自己注册到注册中心eureka.client.register-with-eureka=true# 是否从eureka上来获取服务的注册信息eureka.client.fetch-registry=falseeureka.instance.hostname=localhosteureka.client.serviceUrl.defaultZone=http://eureka:123456@localhost:8090/eureka启动注册中心 启动后访问(http://127.0.0.1:8090) 登陆界面 2. 输入设置的账号密码(user:eureka pwd:123456)3. 进入注册中心页面 需要注意的是 需要处理下CSRF不然服务提供者注册不进来 启动入口文件如下EurekaServiceApplication.java@EnableEurekaServer@SpringBootApplicationpublic class EurekaServiceApplication { public static void main(String[] args) { SpringApplication.run(EurekaServiceApplication.class, args); } /** * 忽略 uri /eureka/** 的CSRF检测 */ @EnableWebSecurity static class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().ignoringAntMatchers("/eureka/**"); super.configure(http); } }}简单的注册中心已经搭建完成搭建服务提供者 Provider-service首先还是配置文件 application.properties服务端口server.port=8081# 服务应用名称spring.application.name=provider-ticket# 是否允许使用ip连接eureka.instance.ip-address=true# 注意 http://用户名:密码@主机:端口/eureka 需要与服务中心里配置的一样eureka.client.serviceUrl.defaultZone=http://eureka:123456@localhost:8090/eureka启动 项目后会自动把服务注册到配置的服务中心以下是我做的测试代码 ...

August 17, 2019 · 2 min · jiezi

Spring-Boot-Cloud-CLI-快速上手

导读在日常开发与测试中有一些Spring Cloud 的相关的组件如 eureka、configserver、zipkin、hystrixdashboard等相对来说不容易发生变动,这里就介绍一种Spring 官方为我们提供的开箱即用的 Spring Boot Cloud CLI 只需要一条命令就可以启动这些相关的组件服务。 Spring Boot Cloud CLI 是什么?Spring Boot Cloud CLI 官方是这样描述的: Spring Boot CLI provides Spring Boot command line features for Spring Cloud. You can write Groovy scripts to run Spring Cloud component applications (e.g. @EnableEurekaServer). You can also easily do things like encryption and decryption to support Spring Cloud Config clients with secret configuration values. With the Launcher CLI you can launch services like Eureka, Zipkin, Config Server conveniently all at once from the command line (very useful at development time).翻译之后: ...

August 17, 2019 · 2 min · jiezi

SpringCloud中利用FeignClient发送请求时参数的传递和返回值

1.SpringCloud中微服务之间的调用,传递参数时需要加相应的注解。用到的主要是三个注解@RequestBody,@RequestParam(),@PathVariable()2.get和post请求中对于传递单个引用类型的参数,比如String,Integer....用@RequestParam(),括号中一定要有值(参数的别名)。调用方需要加注解,被调用方不需要加。当然加上也不会出错。被调用方的参数名和调用方的别名保持一致即可。3.post请求中对于javaBean,map,list类型的参数的传递,用@RequestBody,调用方不需要加注解,被调用方加注解即可。注:get请求中使用@RequestBody会出错,同时也不能传递javaBean,map,list类型的参数4.参数位于路径中用@PathVariable(),调用方需要指定别名。别调用方加注解即可。5.引用类型的参数传递时可以自动转化。比如调用方传递String类型的“11”,被调用方可以直接用Integer变量接收6.返回值为javaBean,可以用String接收JSON字符串,然后自行转化。也可以用javaBean或者Map接收。调用方的属性名和类型要和被调用方的保持一致ps:亲自写代码实验理解更深

July 16, 2019 · 1 min · jiezi

SpringCloud使用Fegin进行HTTP接口调用

Fegin简介Fegin是声明式、模块化的Http客户端,可以帮助我们快捷优雅的调用HTTP接口。在SpringCloud中可以很方便的创建一个Feign客户端,只需声明一个接口,并加上对应的注解就能完成对HTTP接口的调用。 本文不集成注册中心也就不使用Fegin的负载均衡,所以可以理解为一个更简便,高可复用的Http客户端。以示例讲解SpringBoot版本:2.1.1.RELEASESpringCloud版本:Finchley.SR2必要POM引入<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.1.RELEASE</version> </parent> <dependencyManagement> <dependencies> <!--spring-cloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>Fegin客户端定义1、@FeignClient 定义接口为Http客户端,调用指定方法,并将接口注入Spring上下文中参数url:所请求http服务的url、参数config:指定fegin的配置类2、@PostMapping 为@RequestMapping的组合注解,默认为Post请求调用,注解不多介绍,主要表示所需要调用的http接口的具体路径,可在url中拼接参数,也可以指定入参的ContentType3、http接口的返回值格式如果和返回对象属性一致,会反序列化为对应对象。package com.external.feign;import java.util.List;import java.util.Map;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.PostMapping;import com.external.config.FormFeignConfig;import com.external.dto.response.BaseBispDto;import com.external.dto.response.NiftyRes;import com.external.dto.response.ReportAnalyzesRes;import com.external.dto.response.ReportSummaryRes;import com.external.feign.rpc.BISPResponse;@FeignClient(name="fegin-name", url="${http-url}" , configuration = FormFeignConfig.class)public interface BispClient { /** * @Description * @author zengzp */ @PostMapping(value="/intf?method=XXXX", consumes = {"application/x-www-form-urlencoded"}) public XXXXResponse<BaseBispDto> saveSampleInfo(Map<String, ?> params); /** * @Description * @author zengzp */ @PostMapping(value="/intf?method=XXXX", consumes = {"application/x-www-form-urlencoded"}) public XXXXResponse<NiftyRes> getNiftyDetectionResultReplenish(Map<String, ?> params); Fegin配置代码配置日志输出策略与指定对应ContentType的消息的编码与解码package com.external.config;import org.springframework.beans.factory.ObjectFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.http.HttpMessageConverters;import org.springframework.cloud.openfeign.support.SpringDecoder;import org.springframework.cloud.openfeign.support.SpringEncoder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Scope;import feign.Logger;import feign.codec.Decoder;import feign.codec.Encoder;import feign.form.FormEncoder;@Configurationpublic class FormFeignConfig { @Autowired private ObjectFactory<HttpMessageConverters> messageConverters; @Bean Logger.Level feignLoggerLevel() { return Logger.Level.BASIC; } @Bean @Scope("prototype") Decoder decoder() { return new AllinpayDecoder(new SpringDecoder(messageConverters)); } @Bean @Scope("prototype") Encoder encoder(){ return new FormEncoder(new SpringEncoder(this.messageConverters)); }}统一响应DTOpackage com.external.feign.rpc;import org.springframework.http.HttpStatus;import com.external.common.dto.BaseDto;public class XXXXResponse<T> extends BaseDto { /** * */ private static final long serialVersionUID = 1L; private String code; private String msg; private Long total; private T rows;}启动服务时务必在配置类上增加@EnableFeignClients

July 15, 2019 · 1 min · jiezi

手撕面试官系列三-微服务架构面试题DubboSpring-BootSpring-Cloud

直接进入主题Dubbo(面试题+答案领取方式见个人主页) Dubbo 中 中 zookeeper 做注册中心,如果注册中心集群都挂掉,发布者和订阅者之间还能通信么?dubbo 服务负载均衡策略?Dubbo 在安全机制方面是如何解决的dubbo 连接注册中心和直连的区别dubbo 服务集群配置(集群容错模式)dubbo 通信协议 dubbo 协议为什么要消费者比提供者个数多dubbo 通信协议 dubbo 协议为什么不能传大包dubbo 通信协议 dubbo 协议为什么采用异步单一长连接dubbo 通信协议 dubbo 协议适用范围和适用场景RMI 协议Hessian 协议httpWebserviceThrifSpring Boot 什么是 Spring Boot?Spring Boot 有哪些优点?什么是 JavaConfig?如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?Spring Boot 中的监视器是什么?如何在 Spring Boot 中禁用 Actuator 端点安全性?如何在自定义端口上运行 Spring Boot 应用程序?什么是 YAML?如何实现 Spring Boot 应用程序的安全性?如何集成 Spring Boot 和 ActiveMQ?如何使用 Spring Boot 实现分页和排序?什么是 Swagger?你用 Spring Boot 实现了它吗?什么是 Spring Profiles?什么是 Spring Batch?什么是 FreeMarker 模板?如何使用 Spring Boot 实现异常处理?您使用了哪些 starter maven 依赖项?什么是 CSRF 攻击?什么是 WebSockets?什么是 AOP?什么是 Apache Kafka?我们如何监视所有 Spring Boot 微服务?Spring Cloud ...

July 12, 2019 · 1 min · jiezi

Spring-Cloud-Alibaba-Nacos心跳与选举

通过阅读NACOS的源码,了解其心跳与选举机制。开始阅读此篇文章之前,建议先阅读如下两篇文章: Spring Cloud Alibaba Nacos(功能篇) Spring Cloud Alibaba Nacos(源码篇) 一、心跳机制只有NACOS服务与所注册的Instance之间才会有直接的心跳维持机制,换言之,这是一种典型的集中式管理机制。 在client这一侧是心跳的发起源,进入NacosNamingService,可以发现,只有注册服务实例的时候才会构造心跳包: @Override public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException { if (instance.isEphemeral()) { BeatInfo beatInfo = new BeatInfo(); beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName)); beatInfo.setIp(instance.getIp()); beatInfo.setPort(instance.getPort()); beatInfo.setCluster(instance.getClusterName()); beatInfo.setWeight(instance.getWeight()); beatInfo.setMetadata(instance.getMetadata()); beatInfo.setScheduled(false); beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo); } serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance); }没有特殊情况,目前ephemeral都是true。BeatReactor维护了一个Map对象,记录了需要发送心跳的BeatInfo,构造了一个心跳包后,BeatReactor.addBeatInfo方法将BeatInfo放入Map中。然后,内部有一个定时器,每隔5秒发送一次心跳。 class BeatProcessor implements Runnable { @Override public void run() { try { for (Map.Entry<String, BeatInfo> entry : dom2Beat.entrySet()) { BeatInfo beatInfo = entry.getValue(); if (beatInfo.isScheduled()) { continue; } beatInfo.setScheduled(true); executorService.schedule(new BeatTask(beatInfo), 0, TimeUnit.MILLISECONDS); } } catch (Exception e) { NAMING_LOGGER.error("[CLIENT-BEAT] Exception while scheduling beat.", e); } finally { executorService.schedule(this, clientBeatInterval, TimeUnit.MILLISECONDS); } } }通过设置scheduled的值来控制是否已经下发了心跳任务,具体的心跳任务逻辑放在了BeatTask。 ...

July 8, 2019 · 4 min · jiezi

Spring-Cloud-Alibaba-Nacos源码篇

在看这篇文章之前,最好对NACOS相关功能有所了解,推荐看完Spring Cloud Alibaba Nacos(功能篇)。 针对功能,有目的的去找相对应的源代码,进一步了解功能是如何被实现出来的。 本文针对有一定源代码阅读经验的人群,不会深入太多的细节,还需要读者打开源码跟踪,自行领会。 一、引子进入GitHub对应的页面,将NACOS工程clone下来。目录和文件看起来很冗长,但是对于看源代码真正有帮助的部分并不多。 有了这三张图,就能顺利找到突破口了,核心内容就集中在nacos-console,nacos-naming,nacos-config,顺藤摸瓜,就能看到不少内容了。 如果还是感觉无从下手的话,那就移步nacos-example,里面有主要业务的调用入口,一看便知。 二、配置服务首先从一个工厂类说起:com.alibaba.nacos.api.NacosFactory。 里面的静态方法用于创建ConfigService和NamingService,代码类似,以创建ConfigService为例: public static ConfigService createConfigService(Properties properties) throws NacosException { try { Class<?> driverImplClass = Class.forName("com.alibaba.nacos.client.config.NacosConfigService"); Constructor constructor = driverImplClass.getConstructor(Properties.class); ConfigService vendorImpl = (ConfigService) constructor.newInstance(properties); return vendorImpl; } catch (Throwable e) { throw new NacosException(-400, e.getMessage()); }}没有什么复杂的逻辑,使用的是基本的反射原理。构造参数传入了properties,这些属性可以通过bootstrap.yml中指定,对应的是NacosConfigProperties。 需要细看的是构造函数中对于namespace初始化的那部分内容。 private void initNamespace(Properties properties) { String namespaceTmp = null; String isUseCloudNamespaceParsing = properties.getProperty(PropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING, System.getProperty(SystemPropertyKeyConst.IS_USE_CLOUD_NAMESPACE_PARSING, String.valueOf(Constants.DEFAULT_USE_CLOUD_NAMESPACE_PARSING))); if (Boolean.valueOf(isUseCloudNamespaceParsing)) { namespaceTmp = TemplateUtils.stringBlankAndThenExecute(namespaceTmp, new Callable<String>() { @Override public String call() { return TenantUtil.getUserTenantForAcm(); } }); namespaceTmp = TemplateUtils.stringBlankAndThenExecute(namespaceTmp, new Callable<String>() { @Override public String call() { String namespace = System.getenv(PropertyKeyConst.SystemEnv.ALIBABA_ALIWARE_NAMESPACE); return StringUtils.isNotBlank(namespace) ? namespace : EMPTY; } }); } if (StringUtils.isBlank(namespaceTmp)) { namespaceTmp = properties.getProperty(PropertyKeyConst.NAMESPACE); } namespace = StringUtils.isNotBlank(namespaceTmp) ? namespaceTmp.trim() : EMPTY; properties.put(PropertyKeyConst.NAMESPACE, namespace);}传入的properties会指定是否解析云环境中的namespace参数,如果是的,就是去读取阿里云环境的系统变量;如果不是,那么就读取properties中指定的namespace,没有指定的话,最终解析出来的是空字符串。从代码上看出来,获取云环境的namespace做成了异步化的形式,但是目前版本还是使用的同步调用。 ...

July 3, 2019 · 4 min · jiezi

工作记录给-Spring-boot-Jar-瘦瘦身

写在前面在如今程序员的世界中,spring boot 越来越流行,不管是开发web应用还是构建spring cloud 微服务架构都离不开它, 不同于传统的web应用 需要单独部署容器来发布war包, spring boot 应用可以把整个项目打包成我们熟悉的jar来运行,大大方便了我们的开发部署。 问题凸显上述提到Spring boot将整个应用打成一个Jar来执行,大大提高了我们的效率。 但是同时也给我们带来了烦恼,随着我们项目的不但迭代,也导致Jar不断的肥胖,对于高速迭代的项目上传一个如此肥胖的Jar简直痛不欲生。 那怎么办? 程序员是一个懒人职业,总会想到办法来一次搞定这些问题的。 下面就让我们来看看吧! 解决方案解决上述问题,只需要如下几步就可以搞定了。 通常我们是用spring-boot-maven-plugin 进行打包、通过阅读文档发现可以通过配置使得该插件在打包时忽略特定的依赖,文档:spring-boot-maven-plugin首先备份原先的依赖: 可以用使用 mvn dependency:copy-dependencies 首先将依赖导出。将一些变化不大的 jar copy 到外部文件 lib 文件夹中(和 pom 文件中配置对应 )修改 pom 文件<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <layout>ZIP</layout> <!--去除在生产环境中不变的依赖--> <excludeGroupIds> org.springframework.boot, org.springframework, org.springframework.data, org.apache.tomcat.embed </excludeGroupIds> </configuration> </plugin> </plugins></build> 注:layout 必须是 ZIP 、 excludeGroupIds 中时忽略也是就需要打在外部的 jar 、根据自己项目的情况进行配置,exclude的更多用法 请参考文档spring-boot-maven-plugin项目启动 将 项目的 jar 和 刚创建的 lib 放在同级目录下(不是必须的)。启动项目: java -Dloader.path="lib/" -jar xx.jarok! 就这么简单的帮spring boot jar 减肥成功了。 ...

June 30, 2019 · 1 min · jiezi

SpringCloud微服务架构升级总结

一、背景1.1 应用系统的架构历史 1.2 什么是微服务?起源:微服务的概念源于 2014 年 3 月 Martin Fowler 所写的一篇文章“Microservices”。文中内容提到:微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。 通信方式:每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于 HTTP 的 RESTful API)。 微服务的常规定义:微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务。把原来的一个完整的进程服务,拆分成两个或两个以上的进程服务,且互相之间存在调用关系,与原先单一的进程服务相比,就是“微服务”。(微服务是一个比较级的概念,而不是单一的概念) 1.3 微服务架构的优势可扩展性:在增加业务功能时,单一应用架构需要在原先架构的代码基础上做比较大的调整,而微服务架构只需要增加新的微服务节点,并调整与之有关联的微服务节点即可。在增加业务响应能力时,单一架构需要进行整体扩容,而微服务架构仅需要扩容响应能力不足的微服务节点。容错性:在系统发生故障时,单一应用架构需要进行整个系统的修复,涉及到代码的变更和应用的启停,而微服务架构仅仅需要针对有问题的服务进行代码的变更和服务的启停。其他服务可通过重试、熔断等机制实现应用层面的容错。技术选型灵活:微服务架构下,每个微服务节点可以根据完成需求功能的不同,自由选择最适合的技术栈,即使对单一的微服务节点进行重构,成本也非常低。开发运维效率更高:每个微服务节点都是一个单一进程,都专注于单一功能,并通过定义良好的接口清晰表述服务边界。由于体积小、复杂度低,每个微服务可由一个小规模团队或者个人完全掌控,易于保持高可维护性和开发效率。Spring Cloud作为目前最流行的微服务开发框架,不是采用了Spring Cloud框架就实现了微服务架构,具备了微服务架构的优势。正确的理解是使用Spring Cloud框架开发微服务架构的系统,使系统具备微服务架构的优势(Spring Cloud就像工具,还需要“做”的过程)。 1.4 什么是Spring Boot?什么是Spring Cloud?Spring Boot框架是由Pivotal团队提供的全新框架,其设计目的是用来简化基于Spring应用的初始搭建以及开发过程。SpringBoot框架使用了特定的方式来进行应用系统的配置,从而使开发人员不再需要耗费大量精力去定义模板化的配置文件。 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理、服务注册,服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操作提供了一种简单的开发方式。 1.5 微服务、Spring Boot、Spring Cloud三者之间的关系思想:微服务是一种架构的理念,提出了微服务的设计原则,从理论为具体的技术落地提供了指导思想。脚手架:Spring Boot是一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务。多个组件的集合:Spring Cloud是一个基于Spring Boot实现的服务治理工具包;Spring Boot专注于快速、方便集成的单个微服务个体;Spring Cloud关注全局的服务治理框架。二、技术解析2.1 Everything is jar, Everything is httpSpring Boot通过@SpringBootApplication注解标识为Spring Boot应用程序。所有的应用都通过jar包方式编译,部署和运行。 @SpringBootApplication public class Application { private static final Logger LOGGER = LoggerFactory.getLogger(Application.class); public static void main(String[] args) { SpringApplication.run(Application.class, args); LOGGER.info(”启动成功!"); } }每个Spring Boot的应用都可以通过内嵌web容器的方式提供http服务,仅仅需要在pom文件中依赖spring-boot-start-web即可,原则上微服务架构希望每个独立节点都提供http服务。 ...

June 26, 2019 · 3 min · jiezi

点评CAT在Spring-Cloud中的实践

作者在基于Spring Cloud微服务的架构时,一直苦于寻找一个可靠的性能监控平台,后在大神的推荐下,详细研究了点评CAT,其满足对应用性能监控的需求(包含SQL性能,URL响应性能等),将踩过的坑进行分享一下。 下载cat 3.0并启动由于微服务集群并不是很庞大,且服务器资源有限,所以暂时只采用了单点部署的CAT,集群部署和使用请参考CAT的github,这里暂不做分享 配置系统的JDK,以及下载对应的tomcat,本人使用的是JDK8和tomcat8.5.x版本(JDK的配置和tomcat的下载不做详细说明)CAT下载地址http://unidal.org/nexus/servi...修改tomcat的server.xml使其支持中文的URL <Connector port="8080" protocol="HTTP/1.1" URIEncoding="utf-8" connectionTimeout="20000" redirectPort="8443" /><!-- 增加 URIEncoding="utf-8" -->创建CAT使用的文件夹,并修改其配置 mkdir /datachmod -R 777 /data/ 修改CAT配置文件,创建/data/appdatas/cat/client.xml并修改如下 <?xml version="1.0" encoding="utf-8"?><config mode="client"> <servers> <server ip="127.0.0.1" port="2280" http-port="8080"/> </servers></config>修改cat的数据库配置文件/data/appdatas/cat/datasource.xml <?xml version="1.0" encoding="utf-8"?><data-sources> <data-source id="cat"> <maximum-pool-size>3</maximum-pool-size> <connection-timeout>1s</connection-timeout> <idle-timeout>10m</idle-timeout> <statement-cache-size>1000</statement-cache-size> <properties> <driver>com.mysql.jdbc.Driver</driver> <url><![CDATA[jdbc:mysql://127.0.0.1:3306/cat]]></url> <!-- 请替换为真实数据库URL及Port --> <user>root</user> <!-- 请替换为真实数据库用户名 --> <password>root</password> <!-- 请替换为真实数据库密码 --> <connectionProperties><![CDATA[useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&socketTimeout=120000]]></connectionProperties> </properties> </data-source></data-sources>运行CAT的SQL脚本初始化数据库 将CAT的war重命名为cat.war放到tomcat的webapps下,并启动tomcat(默认用户名密码admin:admin),即可通过服务器IP:8080/cat进行访问springboot集成cat clientmaven引入cat client <dependency> <groupId>com.dianping.cat</groupId> <artifactId>cat-client</artifactId> <version>3.0.0</version></dependency>使用SPI方式配置cat client 其中com.dianping.cat.configuration.ClientConfigProvider文件中填写完成实现类名称,实现类代码如下: public class CatClientConfigProvider implements ClientConfigProvider { @Override public ClientConfig getClientConfig() { List<Server> servers = Lists.newArrayList(); //cat 服务器地址,多个则需要使用,分割 String catServersStr = SpringUtils.getProperties("cat.servers"); if (catServersStr != null) { String[] catServers = catServersStr.split(","); for (String catServer : catServers) { servers.add(new Server(catServer)); } //domain直接去springboot的application name String domain = SpringUtils.getProperties("spring.application.name"); ClientConfig config = new ClientConfig(); config.setServers(servers); config.setDomain(domain); return config; } return null; }}app.properties文件中填写app.name=应用名称 ...

June 25, 2019 · 1 min · jiezi

Spring-Cloud-Alibaba-Nacos

越来越多的读者在和我交流关于Spring Cloud Alibaba的种种事宜,甚至于在一次面试中,一半时间都在聊这个话题。所以,本着对技术钻研的热情,对Spring Cloud Alibaba进行了一番研究。 在这里,并不想高谈阔论,也不想预言未来,只是挑选了几个从阿里巴巴中间件团队内脱胎出来的开源组件,对于解决实际业务问题有所裨益。 一、背景先来说说大背景。 现在,很明显的一个趋势就是:微服务。 这个趋势的底层驱动力就来源于分布式系统的普及,而微服务的各个特性是如今大大小小的企业无法拒绝的诱惑。 然后,用上了微服务的架构风格,用Spring Cloud,或者Dubbo搭了一套脚手架,就开始干起来了。 接下来,一众小公司画完了大饼之后,发现自己根本吃不下。这就是典型的落后劳动力与先进生产力的尖锐矛盾。这个时候,返璞归真的想法是不能有了,重构代价太大。 当然,哪里有问题,哪里就有商机。各大XX云厂商经过一系列包装之后,用“云原生(Cloud Native)”的新概念粉墨登场。 Spring Cloud Alibaba就是其中之一。 这个概念的一个核心价值就是:平滑上云,赋能运维。最明显的业务表象就是,会提供一套Open API,甚至是贴心的提供一个可视化控制台,傻瓜式的那种。 二、从NACOS说起这是一颗耀眼的掌上明珠,迅速引起了我的注意。 按照套路,分为两讲。其一讲述NACOS的功能特性,及其使用,再者就是更深入一步,看看大厂的攻城狮们写的代码。 本文所使用的版本是NACOS 1.0.0,由于此版本还是第一个NACOS正式版,NACOS正处在飞速发展阶段,本文的一些内容可能会不适用于以后的版本,请读者自行辨别。 NACOS解决两个核心问题:动态配置管理,服务注册发现。 兼容性方面,除了支持自家的Dubbo,还对Spring Cloud,Kubernetes,Istio有所兼容。 对照以上的全景图,现在的NACOS还有一段距离,但是并不遥远。 至此,不说道说道Eureka,都有点过意不去了。 我用下来的体验是:NACOS完全可以替代Eureka了。 江山代有才人出,这是必然的结果。 在“云原生”的大背景之下,NACOS顺利成章的推出了Console,将触角进一步延伸至服务的精细化管理。 当然,不排除Eureka也在憋大招。 再说说动态配置的特性。 当然,NACOS略胜一筹,可替代Spring Cloud Config了。 原先在Git/SVN上托管的配置项,都可以在Console上统一管理了。 如果想先睹为快,可以接下着往下读。如果想再多了解一些,可以直接跳过这部分,阅读下一个小节。 可以把NACOS理解成是一个中心化的服务,这在阿里系的架构中屡见不鲜。所以,必须得先启动这个服务。 有两个办法:其一是直接clone源码,使用maven打包。第二个办法是直接下载GitHub release出来的压缩包。 推荐后者。 方法1:主要运行以下命令: git clone https://github.com/alibaba/nacos.git cd nacos/ mvn -Prelease-nacos clean install -U经过一段时间的构建过程,在./distribution/target目录下有我们想要的压缩包。 方法2:进入https://github.com/alibaba/nacos/releases,找到压缩包,下载。 为了演示,我们先用单机模式启动。 Windows环境下: startup.cmd -m standalone一切就绪的话,访问http://127.0.0.1:8848/nacos/index.html,使用nacos/nacos登录。 接下来,随便逛逛。 三、重要的概念为了避免在Console中迷失自我,有必要先阐述几个重要的概念。 这张图很重要。表述了namespace、group和service/dataId的包含关系。 NACOS给的最佳实践表明,最外层的namespace是可以用于区分部署环境的,比如test,uat,product等。同时,也有一个商业利用价值:多租户。以namespace为单位,给用户开辟使用空间。 其它两个领域模型不用多解释了,见名知意。其目的也非常明显,就是为了能够逻辑上区分两个目标对象。 默认情况下,namespace=public,group=DEFAULT_GROUP。 明白了这个数据模型后,可以稍微玩转一下Console了,比如新建若干个namespace: ...

June 23, 2019 · 2 min · jiezi

springCloud学习5SpringCloudStream事件驱动

springcloud 总集:https://www.tapme.top/blog/detail/2019-02-28-11-33 代码见文章结尾 想想平常生活中做饭的场景,在用电饭锅做饭的同时,我们可以洗菜、切菜,等待电饭锅发出饭做好的提示我们回去拔下电饭锅电源(或者什么也不知让它处于保温状态),反正这个时候我们知道饭做好了,接下来可以炒菜了。从这里可以看出我们在日常生活中与世界的互动并不是同步的、线性的,不是简单的请求--响应模型。它是事件驱动的,我们不断的发送消息、接受消息、处理消息。 同样在软件世界中也不全是请求--响应模型,也会需要进行异步的消息通信。使用消息实现事件通信的概念被称为消息驱动架构(Event Driven Architecture,EDA),也被称为消息驱动架构(Message Driven Architecture,MDA)。使用这类架构可以构建高度解耦的系统,该系统能够对变化做出响应,且不需要与特定的库或者服务紧密耦合。 在 Spring Cloud 项目中可以使用Spirng Cloud Stream轻而易举的构建基于消息传递的解决方案。 为什么使用消息传递 要解答这个问题,让我们从一个例子开始,之前一直使用的两个服务:许可证服务和组织服务。每次对许可证服务进行请求,许可证服务都要通过 http 请求到组织服务上查询组织信息。显而易见这次额外的 http 请求会花费较长的时间。如果能够将缓存组织数据的读操作,将会大幅提高许可证服务的响应时间。但是缓存数据有如下 2 个要求: 缓存的数据需要在许可证服务的所有实例之间保存一致——这意味着不能将数据缓存到服务实例的内存中。在更新或者删除一个组织数据时,许可证服务缓存的数据需要失效——避免读取到过期数据,需要尽早让过时数据失效并删除。 要实现上面的要求,现在有两种办法。 使用同步请求--响应模型来实现。组织服务在组织数据变化时调用许可证服务的接口通知组织服务已经变化,或者直接操作许可证服务的缓存。使用事件驱动。组织服务发出一个异步消息。许可证服务收到该消息后清除对应的缓存。同步请求-响应方式 许可证服务在 redis 中缓存从组织服务中查询到的服务信息,当组织数据更新时,组织服务同步 http 请求通知许可证服务数据过期。这种方式有以下几个问题: 组织服务和许可证服务紧密耦合这种方式不够灵活,如果要为组织服务添加新的消费者,必须修改组织服务代码,以让其通知新的服务数据变动。使用消息传递方式 同样的许可证服务在 redis 中缓存从组织服务中查询到的服务信息,当组织数据更新时,组织服务将更新信息写入到队列中。许可证服务监听消息队列。使用消息传递有一下 4 个好处: 松耦合性:将服务间的依赖,变成了服务对队列的依赖,依赖关系变弱了。耐久性:即使服务消费者已经关闭了,也可以继续往里发送消息,等消费者开启后处理可伸缩性: 消息发送者不用等待消息消费者的响应,它们可以继续做各自的工作灵活性:消息发送者不用知道谁会消费这个消息,因此在有新的消息消费者时无需修改消息发送代码spring cloud 中使用消息传递 spring cloud 项目中可以通过 spring cloud stream 框架来轻松集成消息传递。该框架最大的特点是抽象了消息传递平台的细节,因此可以在支持的消息队列中随意切换(包括 Apache Kafka 和 RabbitMQ)。 <!-- more --> spring cloud stream 架构 spring cloud stream 中有 4 个组件涉及到消息发布和消息消费,分别为: ...

June 21, 2019 · 3 min · jiezi

springCloud学习4Zuul服务路由

springcloud 总集:https://www.tapme.top/blog/detail/2019-02-28-11-33 本篇中 Zuul 版本为 1.x,目前最新的是 2.x,二者在过滤器的使用上有较大区别 超长警告 项目代码见文章结尾 一、背景 微服务架构将一个应用拆分为很多个微小应用,这样会导致之前不是问题的问题出现,比如: 安全问题如何实现?日志记录如何实现?用户跟踪如何实现?上面的问题在传统的单机应用很容易解决,只需要当作一个功能实现即可。但是在微服务中就行不通了,让每个服务都实现一份上述功能,那是相当不现实的,费时,费力还容易出问题。 为了解决这个问题,需要将这些横切关注点(分布式系统级别的横切关注点和 spring 中的基本一个意思)抽象成一个独立的且作为应用程序中所有微服务调用的过滤器和路由器的服务。这样的服务被称为——服务网管(service gateway),服务客户端不再直接调用服务。取而代之的是,服务网关作为单个策略执行点(Policy Enforcement Point,PEP) , 所有调用都通过服务网管进行路由,然后送到目的地。 二、服务网关1、什么是服务网关 之前的几节中我们是通过 http 请求直接调用各个服务,通常在实际系统中不会直接调用。而是通过服务网关来进行服务调用。服务网关充当了服务客户端和被调用服务间的中介。服务客户端仅与服务网关管理的单个 url 进行对话。下图说了服务网关在一个系统中的作用: 服务网关位于服务客户端和相应的服务实例之间。所有的服务调用(内部和外部)都应流经服务网关。 <!-- more --> 2、功能 由于服务网关代理了所有的服务调用,因此它还能充当服务调用的中央策略执行点(PEP),通俗的说就能能够在此实现横切关注点,不用在各个微服务中实现。主要有以下几个: 静态路由——服务网关将所有的服务调用放置在单个 URL 和 API 路由后,每个服务对应一个固定的服务端点,方便开发人员的服务调用。动态路由——服务网关可以检测传入的请求,根据请求数据和请求者执行职能路由。比如将一部分的调用路由到特定的服务实例上,比如测试版本。验证和授权——所有服务调用都经过服务网关,显然可以在此进行权限验证,确保系统安全。日志记录——当服务调用经过服务网关时,可以使用服务网关来收集数据和日志信息(比如服务调用次数,服务响应时间等)。还能确保在用户请求上提供关键信息以确保日志统计(比如给每个用户请求加一个 url 参数,每个服务中可通过该参数将关键信息对应到某个用户请求)。看到这儿可能会有这样的疑问:所有调用都通过服务网关,难道服务网关不是单点故障和潜在瓶颈吗? 1. 在单独的服务器前,负载均衡器是很有用的。将负载均衡器放到多个服务网关前面是比较好的设计,确保服务网关可以实现伸缩。但是如果将负载均衡器置于所有服务前便不是一个好主意,会造成瓶颈。 2. 服务网关的代码应该是无状态的。有状态的应用实现伸缩性较为麻烦 3. 服务网关的代码应该轻量的。服务网关是服务调用的“阻塞点”,不易在服务网关处耽误较长的时间,比如进行同步数据库操作 三、实战 使用 Netflix Zuul 来构建服务网关,配合之前的代码,让服务网关来管理服务调用。 在生产环境中不建议使用 zuul,该组件性能较弱,且已经停止更新 1、创建 zuulsvr 项目 详细过程不赘述,和之前一样(注意 spring cloud 版本要和之前一致),主要 pom 依赖如下: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId></dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId></dependency>2、配置 zuul 首先在启动加入注解开启 zuul 并注册到 eureka 中 ...

June 20, 2019 · 3 min · jiezi

从0手写springCloud项目组件搭建

写在前面一直在写springCloud项目,每次都是新建项目然后从零开始写配置,现在写一个尽量通用的项目,方便后续搭建框架的时候直接拿过去使用。 需要搭建的组件(模块)有: eureka(认证),zuul(网关),auth(认证),config(配置中心),user(用户),order(订单),pay(支付),feign...这边主要想涉及到的框架技术有:springcloud,springboot2,oauth2,springSecurity,liquibase,lcn(5.0.2),mybatisplus,logback,redis,mysql,swagger2,poi需要搭建、支持的技术 github,jenkins(自动发布),maven私服,nginx,redis,mysql5.7,jdk1.8,swagger2,rabbitmq一 需要搭建的组件需要搭建的组件主要有7个模块(feign会集成到具体模块),这边我回详细记录eureka,zuul,auth,config,user.因为前四者是springCloud的配置。需要详细介绍,而具体的业务逻辑代码会在具体模块,这里我将以user模块为例子详细介绍. eureka我们知道,在为服务里面,所有模块需要被注册到一个注册中心,持续的向注册中心发送心跳以保证连接的存活。而springcloud的注册中心有consul和eureka,这里我选用的是eureka.eureka的代码很简单,只需要在配置文件里面配置好注册地址与密码(可不设置,生产上强烈建议设置),并标识好自己不向自己注册,不被自己发现即可。 maven坐标: <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--我是用的springboot2.1.3如果是springboot1.5.x请不用这个--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>主类,不用做任何配置 @SpringBootApplication@EnableEurekaServerpublic class CrawlerEurekaApplication { public static void main(String[] args) { SpringApplication.run(CrawlerEurekaApplication.class, args); }}yml配置文件: spring: application: name: crawler-eurekaserver: host: http://localhost port: 9990eureka: client: fetch-registry: false register-with-eureka: false service-url: defaultZone: ${server.host}:${server.port}/eureka/ instance: prefer-ip-address: truezuul上面我们把注册中心搭建好了,访问localhost:9990就可以看到eureka的控制台。但是我们看不到一个服务注册上去了。现在我们搭建一个网关,因为在实际项目中,我们会有很多个微服务模块,而服务器只会向外暴露一个端口,其他的通过相对路径转发。这样也是为了安全和方便管理,有点nginx的感觉。网关的配置也不复杂:pom坐标: <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>主类除了标识为eureka-client,还标识是网关 ...

June 18, 2019 · 1 min · jiezi

SpringBoot系列教程之基础篇一白话我的学习经历

有人说,Spring Boot的出现,让Java迎来了又一春,它是Java应用开发的颠覆者,彻底改变了Java应用开发的模式。2017年,SpringBoot闯入我的生活, 也让我迎来了又一春我开始接触SpringBoot的时候,是在2017年,是公司同事在开始学。我也网上查找了些资料,发现SpringBoot相比传统SpringMVC在xml配置上有很大的一部分优势:无繁琐的xml配置,各个组件依赖配置都自动加入等。我便也跟着疯狂地学起来。不得不发表一下心得体会:用起来很爽,很舒服。 学习过程,痛并快乐着我是一个天生爱折腾的主儿。喜欢学习新的技术和实现方案,挑战难点。然后把学习到的知识转化为自己的,并记录下来,整理输出。有很多也跟我一样吧。 学习springboot的时间虽过了很久,但我仍旧感觉得到当初学习SpringBoot的那股劲。 现在学习技术的途径有很多,可以看视屏教程,看博客,看码云和Github都可以呢。 学习过程中,我也总是会遇到各种问题,或者不明白的知识点,也就是知识盲区,我会怎么做呢?根据这个知识点,提炼出“关键字”去百度或者谷歌搜索,对知识点先有一个大体的了解。但是要从浩瀚的资料中,筛选出有用的资料,那还真得有一双敏感的慧眼吧。我在搜索资料的时候,心里面就会去评估这份资料: 第一层:看到不符合的,直接pass掉。第二层:比较符合的。收集下来,再寻找相似的,方便后面做对比。第三层:直接符合的。那就是实践。看是否能正确解决。并做好记录。不断试错是一种态度。也正是这样的思考方式,解决了我遇到的很多问题。 在学习SpringBoot的过程中,除了基础知识点的积累,我少不了去找许多开源项目案例研究学习,折腾各种环境部署,并从中找到我需要的那部分,然后运用到自己的项目中。我很感谢有前辈们的探索和分享。 我当时的目标很简单,就一个----学好SpringBoot,然后能成功整合各个项目,并简单的用起来。 只是学会用的话,如果有SpringMVC的使用经验的话,上手是分分钟的。 当时,我的目的也很单纯,就是学会用,其他也没多想。我开始简单地搭建了三层架构,然后慢慢开始整合相关组件,实现功能需求。 就这么简单的目的,我什么都不想去实现它就可以了。然而会有很多人,还没开始去做,就开始打退堂鼓。从心里面就已经告知自己:“我不会,我不行,没有大佬带。”,就这样,每天活在痛苦和焦虑中。 有些路必须得自己去走,才能知道沿途的风景是多么的迷人。我曾经也很想会有大佬带,学什么会什么。但对于我们这样的无名小卒,菜鸟小白,谁又会去关心呢。只能啃书,啃视频。有问题也不知道该如何解决。 痛苦在所难免,但如果有我陪着,你是否不会感觉到孤单。我是一天不写代码就剁手的程序猿。遇到的问题,也尽可能的去一起解决,减轻学习上的痛苦。 我当时大概学习了一两周,就开始上手,整合项目,直接开干。在项目中去夯实基础。 学习完了,就得实战。不说了,直接干它一个商城!其过程可谓是艰辛痛苦,那可谓是网上搜罗各种资料博客,github上找Demo项目学习,也算是很艰辛的一段学习历程。 我在的公司是个小公司,但我当时主要负责聚合支付类项目的开发,一想到互联网的项目,应该使用的是比较新的技术开发,终于可以涨姿势了。当时就我一个人接手,我还很高兴,终于能挺起腰杆,撸起袖子,大干一场。但当我真正去接手的时候,我不敢相信自己的眼睛,项目是用servlet+jsp实现,还是几个研究生实习开发的。现在都二十一世纪了好吧,还是互联网项目。咋就没看出一点互联网项目的气息。 收了,吐槽结束。 也许正因为是在这样的环境下,让我有机会去把所学的给施展开来。当时,我一边用原来的技术开发着原有的功能,一边在谋划用SpringBoot新框架的搭建和实现。 我很喜欢当时带我项目的老师说的一句话:用你最熟悉的语言开发。 我深信不疑。 后来,整个的搭建思路,前后端的整合过程,百分之90是我独立完成的。我也很成功的将原有的旧项目V1.0,迁移到我新搭建的SpringBoot项目中,并按照规范开发,就基本上完成SpringBoot单体应用V2.0整合。后面,由于有其他需求,又进行了SpringBoot+Dubbo的微服务搭建V3.0。 正因为有了这样的经历,我知道这样的经验很宝贵,也很来之不易。当然也有我很多没有考虑到的,还需继续学习。 遗憾的是,当初没有做好笔记,光顾着自己爽了。现在也只能靠着自己残缺的记忆。 不遗憾的是,我依然还有心去做一件我值得去做的事----那就是将零散的知识点,躺过的坑,能总结分享,有机地形成一个个系列。 这也是我现在准备去做的事情。 曾经的我也开始过,但后来没有写下去,因为自己的口才和知识面不够,没有多少的落地经验,自然也写不出,即使写得出,也写不好,写不清楚。 相比之前的我,现在的我,年岁长了,经验长了,学到的和看到的多了。也写了几万的文字。也更有底气去做这件事情,相信可以写得更好。 于你,可以跟我一起,学习SpringBoot,并能真正的从基础入门到独自搭建属于自己的框架,为自己增添技术实力, 而且掌握大小公司里的开发技巧,工作习惯。 于我,可以在写教程中,反思自我,争取做得更好。也可能会有更好,更有趣的想法在其中产生。

June 18, 2019 · 1 min · jiezi

注册中心配置了spring-security后客户端启动报错

注册中心配置了security后, 报了 registration failed Cannot execute request on any known server 的错误, 原因是 2.1版本的security默认加上了 csrf 拦截, 所以需要通过重写方法, 把csrf拦截禁用 在启动类上加上以下代码(禁用csrf)即解决问题 @EnableWebSecuritystatic class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .anyRequest() .authenticated() .and() .httpBasic(); }}完整代码如下: /** * @author 毛宇鹏 */@EnableEurekaServer@SpringBootApplication(exclude={ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})public class RegisterApplication { public static void main(String[] args) { SpringApplication.run(RegisterApplication.class, args); } /** * 2.1版本的security默认加上了 csrf 拦截, 所以需要通过重写方法, 把csrf拦截禁用 * 参考: https://github.com/spring-cloud/spring-cloud-netflix/issues/2754 * <pre> * This is because @EnableWebSecurity is now added by default when Spring Security is on the classpath. * This enable CSRF protection by default. You will have the same problem in 1.5.10 if you add @EnableWebSecurity. * One work around, which is not the most secure workaround if you have browsers using the Eureka dashboard, is to disable CSRF protection. * This can be done by adding the following configuration to your app. * </pre> */ @EnableWebSecurity static class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .anyRequest() .authenticated() .and() .httpBasic(); } }}

June 17, 2019 · 1 min · jiezi

springCloud学习3Netflix-Hystrix弹性客户端

springcloud 总集:https://www.tapme.top/blog/detail/2019-02-28-11-33 本次用到全部代码见文章最下方。 一、为什么要有客户端弹性模式 所有的系统都会遇到故障,分布式系统单点故障概率更高。如何构建应用程序来应对故障,是每个软件开发人员工作的关键部分。但是通常在构建系统时,大多数工程师只考虑到基础设施或关键服务彻底发生故障,使用诸如集群关键服务器、服务间的负载均衡以及异地部署等技术。尽管这些方法考虑到组件系统的彻底故障,但他们之解决了构建弹性系统的一小部分问题。当服务崩溃时,很容易检测到该服务以及失效,因此应用程序可以饶过它。然而,当服务运行缓慢时,检测到这个服务性能越发低下并绕过它是非常困难的,因为以下几个原因: 服务的降级可以是以间歇性的故障开始,并形成不可逆转的势头————可能开始只是一小部分服务调用变慢,直到突然间应用程序容器耗尽了线程(所有线程都在等待调用完成)并彻底崩溃。应用程序通常的设计是处理远程资源的彻底故障,而不是部分降级————通常,只要服务没有完全死掉,应用程序将继续调用这个服务,直到资源耗尽崩溃。 性能较差的远程服务会导致很大的潜在问题,它们不仅难以检测,还会触发连锁反应,从而影响整个应用程序生态系统。如果没有适当的保护措施,一个性能不佳的服务可以迅速拖垮整个应用程序。基于云、基于微服务的应用程序特别容易受到这些类型的终端影响,因为这些应用由大量细粒度的分布式服务组成,这些服务在完成用户的事务时涉及不同的基础设施。 二、什么是客户端弹性模式 客户端弹性模式是在远程服务发生错误或表现不佳时保护远程资源(另一个微服务调用或者数据库查询)免于崩溃。这些模式的目标是为了能让客户端“快速失败”,不消耗诸如数据库连接、线程池之类的资源,还可以避免远程服务的问题向客户端的消费者进行传播,引发“雪崩”效应。spring cloud 主要使用的有四种客户端弹性模式: 客户端负载均衡(client load balance)模式 上一篇已经说过,这里不再赘述。 断路器(circuit breaker)模式 本模式模仿的是电路中的断路器。有了软件断路器,当远程服务被调用时,断路器将监视这个调用,如果调用时间太长,断路器将介入并中断调用。此外,如果对某个远程资源的调用失败次数达到某个阈值,将会采取快速失败策略,阻止将来调用失败的远程资源。 <!-- more --> 后备(fallback)模式 当远程调用失败时,将执行替代代码路径,并尝试通过其他方式来处理操作,而不是产生一个异常。也就是为远程操作提供一个应急措施,而不是简单的抛出异常。 舱壁(bulkhead)模式 舱壁模式是建立在造船的基础概念上。我们都知道一艘船会被划分为多个水密舱(舱壁),因而即使少数几个部位被击穿漏水,整艘船并不会被淹没。将这个概念带入到远程调用中,如果所有调用都使用的是同一个线程池来处理,那么很有可能一个缓慢的远程调用会拖垮整个应用程序。在舱壁模式中可以隔离每个远程资源,并分配各自的线程池,使之互不影响。 下图展示了这些模式是如何运用到微服务中的: 三、spring cloud 中使用 使用 Netflix 的 Hystrix 库来实现上述弹性模式。继续使用上一节的项目,给 licensingservice 服务实现弹性模式。 1、代码修改1、依赖引入 首先修改 POM 文件,添加下面两个依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId></dependency><!--本依赖不是必须的,spring-cloud-starter-hystrix已经带了,但是在Camden.SR5发行版本中使用了1.5.6,这个版本有一个不一致的地方,在没有后备的情况下会抛出java.lang.reflect.UndeclaredThrowableException而不是com.netflix.hystrix.exception.HystrixRuntimeException, 在后续版本中修复了这个问题--><dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-javanica</artifactId> <version>1.5.9</version></dependency> 然后在启动类上加入@EnableCircuitBreaker启用 Hystrix。 2、实现断路器 首先修改 organizationservice 项目中的 OrganizationController,模拟延迟,每隔两次让线程 sleep 2 秒 @RestControllerpublic class OrganizationController { private static int count=1; @GetMapping(value = "/organization/{orgId}") public Object getOrganizationInfo(@PathVariable("orgId") String orgId) throws Exception{ if(count%2==0){ TimeUnit.SECONDS.sleep(2); } count++; Map<String, String> data = new HashMap<>(2); data.put("id", orgId); data.put("name", orgId + "公司"); return data; }} 只需在方法上添加@HystrixCommand,即可实现超时短路。如果 Spring 扫描到该注解注释的类,它将动态生成一个代理,来包装这个方法,并通过专门用于处理远程调用的线程池来管理对该方法的所有调用。 ...

June 14, 2019 · 2 min · jiezi

SpringCloudEureka入门与原理

为了开发效率高效和业务逻辑清晰,越来越多的项目采用分布式系统。分布式最重要的就是注册中心了。Eureka是SpringCloud原生提供的注册中心,来look一波吧。超光速入门服务端引入依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>Greenwich.SR1</version></dependency>给启动类加上注解@EnableEurekaServer @EnableEurekaServer@SpringBootApplicationpublic class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); }}配置一下yml文件: #端口号server: port: 8331#Eureka实例名,集群中根据这里相互识别eureka: instance: hostname: eureka #客户端 client: #是否开启注册服务,作为注册中心,就不注册了 register-with-eureka: false #是否拉取服务列表,这里我只提供服务给别的服务。 fetch-registry: false #注册中心地址 service-url: defaultZone: http://localhost:8331/eureka/启动项目EurekaApplication ,浏览器访问http://localhost:8331/,Euerka 服务器搭建成功了。 现在还没有东西注册进来。 客户端引入依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>Greenwich.SR1</version></dependency>这回启动类注解变了,@EnableDiscoveryClient @EnableDiscoveryClient@SpringBootApplicationpublic class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); }}接下来是配置文件: #端口号server: port: 8332#Eureka实例名,集群中根据这里相互识别spring: application: name: first-serviceeureka: #客户端 client: #注册中心地址 service-url: defaultZone: http://localhost:8331/eureka/然后启动项目,过一会儿,刷新页面: ...

June 13, 2019 · 2 min · jiezi

Eureka-源码分析之-Eureka-Server

文章首发于公众号《程序员果果》地址 : https://mp.weixin.qq.com/s/Ff...简介上一篇文章《Eureka 源码分析之 Eureka Client》 通过源码知道 ,eureka Client 是通过 http rest来 与 eureka server 交互,实现 注册服务,续约服务,服务下线 等。本篇探究下eureka server。 源码分析从 @EnableEurekaServer 注解为入口分析,通过源码可以看出他是一个标记注解: /** * Annotation to activate Eureka Server related configuration {@link */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(EurekaServerMarkerConfiguration.class)public @interface EnableEurekaServer {}从注释可以知道,用来激活 eureka server 的 配置类 EurekaServerAutoConfiguration 中相关配置,EurekaServerAutoConfiguration 的关键代码如下: @Configuration@Import(EurekaServerInitializerConfiguration.class)@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class })@PropertySource("classpath:/eureka/server.properties")public class EurekaServerAutoConfiguration extends WebMvcConfigurerAdapter { /** * List of packages containing Jersey resources required by the Eureka server */ private static final String[] EUREKA_PACKAGES = new String[] { "com.netflix.discovery", "com.netflix.eureka" }; @Autowired private ApplicationInfoManager applicationInfoManager; @Autowired private EurekaServerConfig eurekaServerConfig; @Autowired private EurekaClientConfig eurekaClientConfig; @Autowired private EurekaClient eurekaClient; @Autowired private InstanceRegistryProperties instanceRegistryProperties; public static final CloudJacksonJson JACKSON_JSON = new CloudJacksonJson(); @Bean public HasFeatures eurekaServerFeature() { return HasFeatures.namedFeature("Eureka Server", EurekaServerAutoConfiguration.class); } @Configuration protected static class EurekaServerConfigBeanConfiguration { // 创建并加载EurekaServerConfig的实现类,主要是Eureka-server的配置信息 @Bean @ConditionalOnMissingBean public EurekaServerConfig eurekaServerConfig(EurekaClientConfig clientConfig) { EurekaServerConfigBean server = new EurekaServerConfigBean(); if (clientConfig.shouldRegisterWithEureka()) { // Set a sensible default if we are supposed to replicate server.setRegistrySyncRetries(5); } return server; } } //加载EurekaController,SpringCloud 提供了一些额外的接口,用来获取eurekaServer的信息 @Bean @ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true) public EurekaController eurekaController() { return new EurekaController(this.applicationInfoManager); } //省略 ... // 接收客户端的注册等请求就是通过InstanceRegistry来处理的,是真正处理业务的类,接下来会详细分析 @Bean public PeerAwareInstanceRegistry peerAwareInstanceRegistry( ServerCodecs serverCodecs) { this.eurekaClient.getApplications(); // force initialization return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.eurekaClient, this.instanceRegistryProperties.getExpectedNumberOfRenewsPerMin(), this.instanceRegistryProperties.getDefaultOpenForTrafficCount()); } //配置服务节点信息,这里的作用主要是为了配置Eureka的peer节点,也就是说当有收到有节点注册上来的时候,需要通知给哪些节点 @Bean @ConditionalOnMissingBean public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry, ServerCodecs serverCodecs) { return new RefreshablePeerEurekaNodes(registry, this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.applicationInfoManager); } //省略 ... //EurekaServer的上下文 @Bean public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs, PeerAwareInstanceRegistry registry, PeerEurekaNodes peerEurekaNodes) { return new DefaultEurekaServerContext(this.eurekaServerConfig, serverCodecs, registry, peerEurekaNodes, this.applicationInfoManager); } // 初始化Eureka-server,会同步其他注册中心的数据到当前注册中心 @Bean public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) { return new EurekaServerBootstrap(this.applicationInfoManager, this.eurekaClientConfig, this.eurekaServerConfig, registry, serverContext); } // 配置拦截器,ServletContainer里面实现了jersey框架,通过他来实现eurekaServer对外的restFull接口 @Bean public FilterRegistrationBean jerseyFilterRegistration( javax.ws.rs.core.Application eurekaJerseyApp) { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new ServletContainer(eurekaJerseyApp)); bean.setOrder(Ordered.LOWEST_PRECEDENCE); bean.setUrlPatterns( Collections.singletonList(EurekaConstants.DEFAULT_PREFIX + "/*")); return bean; } //省略 ... }从EurekaServerAutoConfiguration 类上的注解@Import(EurekaServerInitializerConfiguration.class) 可以到,实例化类EurekaServerAutoConfiguration之前,已经实例化了EurekaServerInitializerConfiguration类,代码如下: ...

June 13, 2019 · 4 min · jiezi

springCloud学习2服务发现

本篇代码存放于:github 一、服务发现架构 服务发现架构通常具有下面 4 个概念: 服务注册:服务如何使用服务发现代理进行注册?服务地址的客户端查找:服务客户端查找服务信息的方法是什么?信息共享:如何跨节点共享服务信息?健康监测:服务如何将它的健康信息传回给服务发现代理?下图展示了这 4 个概念的流程,以及在服务发现模式实现中通常发生的情况: 通常服务实例都只向一个服务发现实例注册,服务发现实例之间再通过数据传输,让每个服务实例注册到所有的服务发现实例中。 服务在向服务发现实例注册后,这个服务就能被服务消费者调用了。服务消费者可以使用多种模型来"发现"服务。 每次调用服务时,通过服务发现层来获取目标服务地址并进行调用。这种用的比较少,弊端较多。首先是每次服务调用都通过服务发现层来完成,耗时会比直接调用高。最主要的是这种方法很脆弱,消费端完全依赖于服务发现层来查找和调用服务。更健壮的方法是使用所谓的客户端负载均衡。 如下图所示: 在这个模型中,当服务消费者需要调用一个服务时: (1)联系服务发现层,获取所请求服务的所有服务实例,然后放到本地缓存中。 (2)每次调用该服务时,服务消费者从缓存中取出一个服务实例的位置,通常这个'取出'使用简单的复制均衡算法,如“轮询”,“随机",以确保服务调用分布在所有实例之间。 (3)客户端将定期与服务发现层进行通信,并刷新服务实例的缓存。 (4)如果在调用服务的过程中,服务调用失败,那么本地缓存将从服务发现层中刷新数据,再次尝试。 <!-- more --> 二、spring cloud 实战 使用 spring cloud 和 Netflix Eureka 搭建服务发现实例。 1、构建 Spring Eureka 服务 eurekasvr POM 主要配置如下: <!-- 其他依赖省略 --><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId></dependency> applicaiton.yml 配置如下: server: port: 8761eureka: client: #不注册自己 register-with-eureka: false #不在本地缓存注册表信息 fetch-registry: false server: #接受请求前的等待实际,开发模式下不要开启 #wait-time-in-ms-when-sync-empty: 5 最后在启动类上加入注释@SpringBootApplication即可启动服务中心。服务中心管理页面:http://localhost:8761 ...

June 13, 2019 · 3 min · jiezi

小强开饭店从单体应用到微服务

本篇博客通过小强开饭店的通俗易懂的故事,带你了解后端服务是如果从单体应用演变到微服务的。如果有说的不对的地方,欢迎各位大佬强势怼。 小强开饭店有一天,小强为了早日奔赴小康生活,打算开一个饭店来帮他快速的实现这个目标。 饭店开业了于是他盘下了一个店面,一顿装修之后,雇了一个厨师,便开业了。 饭店生意变好了刚刚开业那段时间还好,店里的人虽然多,但是都还能应付的过来。 小强请的厨师手艺很好,再加上小强经营得当,宣传的也不错,慢慢的店里的生意越来越好。 慢慢的,顾客越来越多。很多时候厨师都忙不过来,大家只有排队在外面等着。渐渐的有些顾客变得十分不耐烦,等不下去了就走了,然后给了这家店差评。这种情况愈演愈烈,小强看到这不是个办法啊,得做点什么。 招聘厨师小强下了血本,又另外聘请了几位厨艺很好的厨师。 有了这些厨师的加盟,虽然客人很多,饭店的经营也还是能够勉强的应付的来。口碑也慢慢的由差变好。随着口碑的变好,慕名而来的也随之越来越多。 生意火爆随着顾客越来越多,即使厨房的厨师已经招聘满了,都还是应付不过来。 于是厨师也变成了暴躁的厨师。有的时候因为太忙了还罢工不干了。还得小强去苦口婆心的劝。小强心想这也不是个办法,再这么下去口碑又得下去。于是小强摇身一变,变成了强老板。 强老板开了分店强老板拿着开饭店赚的钱,在城里的很多地方开了分店,十分的膨胀。这样一来,客人不用大老远的跑到那一家店去了,可以选择离自己近的店。很快,原来的那家生意也渐渐的恢复正常,各个分店的业绩也有所提高。 但是随着强老板的强势宣传,以及顾客之间的自传播,这个参考被越来越多的人知道了。但是由于顾客分散,每家店的火爆程度都不同。有的店甚至陷入了跟最开始的店一样的境地,大量的顾客排队。但是有的店的生意却又十分冷清。 强老板心想,这肯定不行啊,这样下去早晚得血亏。于是强老板摇身一变,变成了强总。 强总开了个顾客中心 所有想去餐馆用餐的顾客都来这里,由强老板统一安排的大巴再送至各个分店。每辆车轮流的送至每一家分店。这样一来,就不存在某一家分店生意十分火爆而另外的店生意惨淡的情况了。 强总已达成奔赴小康的目标 读后感其实这个想法是很久以前不知道在哪儿看博客的时候,看到一位大佬的类比,确实是忘了。而最近刚好在准备分享,所以就打算详细的以图文和故事的方式来让没有了解过这方面的人快速的了解一下。 其实我也纠结过要不要将里面类比概念的解释穿插到故事里,但是后面想了一下,这样应该会干扰到大家对故事本身的理解,从而达不到通俗易懂的效果。所以我将解释单独放在了最后面。 单个饭店最开始的单个饭店其实就是一个App或者一个网站,来给用户提供服务。可以理解为前端,或者客户端。 单个饭店的厨师而单个饭店中的厨师,其实就是后端,提供数据,提供服务。一个厨师就对应着一个后端服务的实例。 随着App的访问量越来越大,最初的单体应用已经无法扛住这么大的压力了。导致其他的用户进入系统时,系统无法正常的服务。就跟我们现在打开一个网站一样,凡是超过2-3秒没有反应就直接宣告它的死刑了,直接退出-卸载二连。 单个饭店的多个厨师多个厨师则是相应的后端服务启动了多个实例,每个实例都是完全一样的,只不过是运行在不同的机器上或者不同的端口上。 每次的请求由这些实例来均摊,这样也的确能够暂时解决访问量大的问题。但是维护起来十分的麻烦,部署的流程也很繁琐。每次部署你得更新所有的实例,万一数量多,又在不同的机器上,很有可能因为操作失误引发线上的事故。而且有可能让老版本的服务兼容新版的前端或者客户端,造成不必要的BUG。 再退一万步,就算所有的实例都在同一个服务器上,万一真的访问量到了一定的量级,你得维护多少个实例啊。人工成本巨大。而且一不小心,一觉起来,本身没有问题的服务,因为一晚上发生了事件引发了热点,导致你的应用访问量剧增,增到超过你的所有实例能够承受的极限,服务挂了。 再退一万万步,就算你自己维护没有烦死,前端的兄弟可能早就收拾你了。你没有做请求分发的话,所有的服务器地址得由前端去维护。 分店这里的分店指微服务中的一个服务的多个实例。与之前人工维护的多个实例不同,这个是由工具帮我们维护。 这里我拿Docker Swarm举个例子。在Portainer中,你新建了一个服务之后可以选择设置Replicas,也就是实例的数量,当然默认是一个。你可以起10个,20个,但是这里得考虑到你的服务是否支持这样做。如果你的服务不是无状态应用,就很难做到可以自动的做横向扩展。 分店的生意火爆其实也是一样的,即使有很多个实例,你如果不能控制请求打到哪个服务上的话,某些实例承受的压力大了一样的会挂。 强总的顾客中心顾客中心大家可以理解为网关。更具体点可以理解为Zuul。 你的服务有了网关之后,所有的请求都从网关走。根据以及配置的路由,网关可以判断到你想具体到哪个服务去。 然后就会从自己的服务集群中找到对应的服务,获取到所有的服务实例的服务器IP以及端口。前面说到有可能请求会集中到某几个实例上。而我们可以使用工具来解决这个问题。例如,使用Spring Cloud的核心组件Ribbon。 这个组件的作用是做负载均衡,它可以使所有到某个服务的请求,平均的分发到该服务的每个实例上去。从而避免某几个服务的请求超过其能承受的阙值。当然,Ribbon需要和Spring Cloud的其他核心组件相互协作的。 另外一个版本的故事小强搞了个新闻App,用Spring Boot搭了一个后端,找人用React Native写了个App,就这样上线了。因为其内容和推广都还不错,所以受到了用户的喜爱。 但是随着访问量越来越大,服务器渐渐扛不住压力。有的用户进App之后甚至要5-6秒才有反应,而且慢的出奇。于是小强开始给服务尽量的无状态化,然后在一个服务器上启动了几个实例。 一段时间之后,访问量又增大了。小强只好硬着头皮,继续加实例数量,你强任你强,加实例我在行。 有一天,小强一觉起来,发现服务炸了...啊不是,是挂了。因为发生了一些事情引发了巨大的社会舆论,App的访问量剧增。导致新加的实例也没能扛住。 就这样,小强老实的开始了重构。使用Spring Cloud搭建了一个微服务集群,把服务拆分之后,给每个服务启动了几个实例。同时使用Eureka和Feign来进行服务之间的通信,使用Ribbon来做负载均衡。 就这样,这个App暂时稳定了下来。不过还有很多事情可以继续去做。 参考: 拜托!面试请不要再问我Spring Cloud底层原理往期文章: 什么?你竟然还没有用这几个chrome插件?手把手教你从零开始搭建SpringBoot后端项目框架用go-module作为包管理器搭建go的web服务器WebAssembly完全入门——了解wasm的前世今身相关: 个人网站: Lunhao Hu微信公众号: SH的全栈笔记(或直接在添加公众号界面搜索微信号LunhaoHu)

June 12, 2019 · 1 min · jiezi

springCloud学习1集中式配置管理

springcloud 总集:https://www.tapme.top/blog/detail/2019-02-28-11-33 一、前言 在开发普通的 web 应用中,我们通常是将配置项写在单独的配置文件中,比如application.yml,application.properties,但是在微服务架构中,可能会出现数百个微服务,如果每个微服务将配置文件写在自身的配置文件中,会导致配置文件的管理非常复杂。因此集中式的配置管理是非常有必要的,每个服务启动时从集中式的存储库中读取需要的配置信息。其模型如下: 简单来说就是如下几点: 启动一个微服务实例时向配置管理服务请求获取其所在环境的特定配置文件实际的配置信息驻留在存储库中。可以选择不同的实现来保存配置数据,包含:源代码控制下的文件、关系数据库或键值数据存储应用程序配置数据的实际管理和应用程序无关。配置的更改通常通过构建和部署管道来处理进行配置管理更改时,必须通知使用该配置的服务实例 由于本系列为 spring cloud,所以使用Spring Cloud Config来构建配置管理,当然还有很多其他优秀的解决方案(Etcd,Eureka,Consul...)。 二、构建配置服务 spring cloud 是建立在 spring boot 的基础上的,因此需要有 spring boot 的构建基础。 1、pom 编写 pom 主要依赖如下(篇幅原因列出主要内容,完整代码请到 github 上查看),spring boot 版本和 spring cloud 版本如下,之后不在赘述: <!-- more --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.4.RELEASE</version></parent><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement><properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Camden.SR5</spring-cloud.version></properties><dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>2、注解引导类 只需在 spring boot 启动类上加入一个@EnableConfigServer注解即可。 ...

June 10, 2019 · 2 min · jiezi

编码-技术图谱-一份属于Java开发者的思维导图

一份Java开发者的技术图谱 , 近期主要侧重点在 Java | Docker | 并发与分布式.

June 6, 2019 · 1 min · jiezi

Eureka-源码分析之-Eureka-Client

文章首发于微信公众号《程序员果果》地址:https://mp.weixin.qq.com/s/47...简介Eureka是一种基于REST(Representational State Transfer)的服务,主要用于AWS云,用于定位服务,以实现中间层服务器的负载平衡和故障转移。我们将此服务称为Eureka Server。Eureka还附带了一个基于Java的客户端组件Eureka Client,它使与服务的交互变得更加容易。客户端还有一个内置的负载均衡器,可以进行基本的循环负载均衡。在Netflix,一个更复杂的负载均衡器包含Eureka基于流量,资源使用,错误条件等多种因素提供加权负载平衡,以提供卓越的弹性。先看一张 github 上 Netflix Eureka 的一架构图,如下: 从图可以看出在这个体系中,有2个角色,即Eureka Server和Eureka Client。而Eureka Client又分为Applicaton Service和Application Client,即服务提供者何服务消费者。 每个区域有一个Eureka集群,并且每个区域至少有一个eureka服务器可以处理区域故障,以防服务器瘫痪。 Eureka Client 在 Eureka Server 注册,然后Eureka Client 每30秒向 Eureka Server 发送一次心跳来更新一次租约。如果 Eureka Client 无法续订租约几次,则会在大约90秒内 Eureka Server 将其从服务器注册表中删除。注册信息和续订将复制到群集中的所有 Eureka Server 节点。来自任何区域的客户端都可以查找注册表信息(每30秒发生一次)根据这些注册表信息,Application Client 可以远程调用 Applicaton Service 来消费服务。 源码分析基于Spring Cloud的 eureka 的 client 端在启动类上加上 @EnableDiscoveryClient 注解,就可以 用 NetFlix 提供的 Eureka client。下面就以 @EnableDiscoveryClient 为入口,进行Eureka Client的源码分析。 @EnableDiscoveryClient,通过源码可以发现这是一个标记注解: /** * Annotation to enable a DiscoveryClient implementation. * @author Spencer Gibb */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(EnableDiscoveryClientImportSelector.class)public @interface EnableDiscoveryClient { boolean autoRegister() default true;}通过注释可以知道 @EnableDiscoveryClient 注解是用来 启用 DiscoveryClient 的实现,DiscoveryClient接口代码如下: ...

June 6, 2019 · 4 min · jiezi

初学者关于Docker的一些问题记录

项目背景搭建一个基于springcloud的分布式博客系统,已经实现了基于eureka的配置中心和注册中心,为了减少本地的内存压力,使用docker将配置中心注册中心放到服务器上 初学者初探dockerfile中的WORKDIR的用处docker build -t imageName path, 这里path指的是上下文路径,如ADD COPY等命令都需要一个源路径和目标路径,那么源路径和目标路径的定位是相对于那个路径呢? 源路径就是相对于path,它只能访问path下的目录,在path外的目标是不能被访问到,目标路径相对的就是这个WORKDIR,表示当前容器在运行是访问的根路径,比如RUN java -jar target.jar的时候,这个target在容器中的某个目录下,通过WORKDIR定位到这个目录,就能能通过RUN 来执行到这个target.jar,而不需要在RUN中指定额外的相对或者绝对路径定位这个jar文件制作一个含有jdk环境的Dockefile制作这么一个Dockerfile也不难,指定FROM centos, 通过add将jar解压到容器目录里面,最后通过ENTRYPOINT 指定java -jar && tail -f > /etc/null执行springboot的jar包并保证进程不退出。但jdk的环境变量配置需要注意,有三种写法,一种通过RUN SED -i "$a" /etc/profile 将jdk的环境变量写进profile,第二种通过RUN echo "JAVA_HOME" >> /etc/profile,第三种直接通过dockerfile提供的ENV JAVA_HOME 来设置jdk的环境变量。前面两种都是通过在/etc/profile中写环境变量来完成,但是指定RUN source /etc/profile是行不通的,你需要进入容器中source /etc/profile才能让/etc/profile的环境变量生效。第三种是最简单的设置方法,设置了在容器容器时直接生效。RUN命令中的&&命令连接RUN command 一个RUN会产生一个中间的容器,那么一套相关的命令可以通过RUM command && command来进行连接,换行可以指定 ,如果不指定直接换行连接command会出现一些语法错误,这样有什么好处呢?更加直观?命令功能分块集中?你觉得好就对了何必教科书般的说出个之所以然来,RUM cd /usr/local && npm install这条命令如果分开写成两个RUN会如何? 导致install访问不到/usr/local的文件,它因为是重新开始一个容器,访问的路径时WORKDIR指定的根目录CMD的ENTRYPOINT的区别dockerfile中的一些指令都是可以通过docker run来覆盖的,比如 -v 挂载可以覆盖VOLUME -p 可以覆盖EXPOSE指定的端口, -w可以覆盖WORKDIR,-v 可以覆盖ENV环境变量,这里的docker run imageId command 中的command可以覆盖CMD,所以容器的启动后执行的命令还是写在ENTRYPOINT比较好,避免被覆盖掉。docker run中的-it是什么意思,-d是什么意思, 后面跟个command为/bin/bash又是什么意思i表示交互,t表示伪终端,-d是后台运行,/bin/bash是容器启动时执行/bin/bash命令在容器中打开一个进程进入/bin/bash。解释了但是没有实践又怎么知道是怎么个回事。那么如果不指定-d,会使容器在前台执行进程,将控制台打印这些执行信息,如果指定了-d那么容器进程在后台执行,不会打印执行信息,也不用想办法退出当前容器执行的进程。一般运行docker run以后直接在控制台打印这个容器的id信息,但是我又想进入容器怎么办?docker exec吗,我执行进去看看不想写这个命令,这时候可以通过docker run -it /bin/bash 执行完就能进入到这个容器里面查看一些信息,这应该就是所谓的交互dockerfile通过docker build通过docker images可以找到这个镜像,删除dockerfile上下文会生效吗之前试了一下,也不知道是不是服务器内存不够,执行docker run 没生效,还需要待实践挂载目录的理解挂载目录可以在dockerfile中通过volume指定,这只能指定容器的挂载目录,宿主机的挂载目录自动生成,可以通过docker inspect imageId查看,也可以通过docker run -v path:path 指定,那么我在宿主机的挂载目录中更改一些信息,它会立马响应到容器对应挂载的目录里面dockerfile制作启动springboot项目的镜像,如何更新jar包最初认为只要挂载好宿主机的存放jar的目录到指定的容器目录中,通过docker restart重新执行dockerfile中的ENTRYPOINT java -jar target.jar命令来执行这个容器的挂载目录更新的target.jar,这样就能完成jar的更新,发现行不通每次发布新的jar都需要通过docker build重新构建镜像,具体还需要实际操作总结

June 5, 2019 · 1 min · jiezi

Spring-Cloud-Config2x-版本使用webhooks无法刷新client配置的解决方案

前言:本次开发环境为SpringBoot 2.1.4.RELEASE、SpringCloud Greenwich.SR1、SpringCloudConfig 2.1.1.RELEASE发现问题使用config手动通过访问/actuator/bus-refresh可以正常刷新,但是通过配置webhooks访问/monitor无法刷新配置。 解决问题官方文档排查https://cloud.spring.io/sprin... bus的文档中对spring.cloud.bus.id有如下描述:应用有一个ServiceID,默认的值是app:index:id的组装。规则是: app :如果vcap.application.name存在,使用vcap.application.name,否则使用spring.application.name(默认值为application) index :配置值的情况下优先使用vcap.application.instance_index,否则依次使用spring.application.index、local.server.port、server.port(默认值0) id: 如果vcap.application.instance_id存在,使用vcap.application.instance_id,否则给一个随机值##### 代码排查设置客户端的打印日志级别 logging: level: org.springframework.cloud.bus: debug控制台会打印出org.springframework.cloud.bus.DefaultBusPathMatcher中匹配规则的日志(如果客户端不刷新,一般这里的日志打印出的匹配规则和待匹配字符串是不一致的),webhooks端的过来匹配规则由三部分数据组成,使用“:”拼接,得到的结果如下: spring.application.name:spring.cloud.config.profile:**如果我们serviceID不进行设置,当前服务那么会使用默认配置(默认配置代码体现在:org.springframework.cloud.bus.BusEnvironmentPostProcessor#getDefaultServiceId),如下: private String getDefaultServiceId(ConfigurableEnvironment environment) { return "${vcap.application.name:${spring.application.name:application}}:${vcap.application.instance_index:${spring.application.index:${local.server.port:${server.port:0}}}}:${vcap.application.instance_id:${random.value}}"; }对应官方文档,以及我们的配置文件,我们可以依据serviceID的匹配规则来设置对应的参数去匹配webhooks。 如果发现app:index:id中的index不一致, 举例yml配置: vcap: application: instance_index: ${spring.cloud.config.profile}或者直接修改bus.id的配置,如下: spring: application: name: client cloud: config: discovery: service-id: CONFIG enabled: true profile: dev bus: id: ${spring.application.name}:${spring.cloud.config.profile}:${random.value}

June 3, 2019 · 1 min · jiezi

springcloud-基于feign的服务接口的统一hystrix降级处理

springcloud开发微服务时,基于feign来做声明式服务接口,当启用hystrix服务熔断降级时,项目服务众多,每个Feign服务接口都得写一些重复问的服务降级处理代码,势必显得枯燥无味: Feign服务接口: @FeignClient(name="springcloud-nacos-producer", qualifier="productApiService", contextId="productApiService", fallback=ProductFallbackApiService.class)public interface ProductApiService { /** * 创建商品 * @param product */ @PostMapping(value="/api/product/add", produces=APPLICATION_JSON, consumes=APPLICATION_JSON) public Result<Long> createProduct(@RequestBody Product product); /** * 修改商品 * @param product */ @PutMapping(value="/api/product/update", produces=APPLICATION_JSON, consumes=APPLICATION_JSON) public Result<Object> updateProduct(@RequestBody Product product); /** * 删除商品 * @param productId */ @DeleteMapping(value="/api/product/delete/{productId}", produces=APPLICATION_JSON) public Result<Object> deleteProductById(@PathVariable("productId") Long productId); /** * 根据productId获取商品信息 * @param productId * @return */ @GetMapping(value="/api/product/{productId}", produces=APPLICATION_JSON) public Result<Product> getProductById(@PathVariable("productId") Long productId); /** * 根据条件查询商品列表(分页、排序) * @param condition * @param page * @param sort * @return */ @GetMapping(value="/api/product/list1", produces=APPLICATION_JSON) public PageResult<List<Product>> getProductListByPage(@RequestParam Product condition, @RequestParam Page page, @RequestParam Sort sort);}对应的熔断降级处理类: ...

June 3, 2019 · 1 min · jiezi

让springcloud-feignclient-完全支持springmvc的RequestParam注解的特性

1、要解决的问题在springcloud微服务中,使用feign来做声明式微服务调用的client时,经常会遇到springmvc的原生注解@RequestParam不支持自定义POJO对象的问题,例如: 服务的API接口: @FeignClient(name="springcloud-nacos-producer", qualifier="productApiService")public interface ProductApiService { @GetMapping(value="/api/product/list", produces=APPLICATION_JSON) public PageResult<List<Product>> getProductListByPage(@RequestParam Product condition, @RequestParam Page page, @RequestParam Sort sort);}public class Page implements DtoModel { private static final long serialVersionUID = 1L; private Integer currentPage = 1; private Integer pageSize = 10; private Integer totalRowCount = 0; //get/set...}public class Sort implements DtoModel { private static final long serialVersionUID = 1L; private List<Order> orders; Sort() { super(); } Sort(List<Order> orders) { super(); this.orders = orders; } public static Sort by(Order... orders) { return new Sort(Arrays.asList(orders)); } public List<Order> getOrders() { return orders; } public void setOrders(List<Order> orders) { this.orders = orders; } public Order first() { if(orders != null && orders.size() > 0) { return orders.get(0); } return null; } public static class Order { public static final String DIRECTION_ASC = "asc"; public static final String DIRECTION_DESC = "desc"; private String property; private String direction; Order() { super(); } Order(String property, String direction) { super(); if(direction != null) { direction = direction.toLowerCase(); direction = DIRECTION_DESC.equals(direction) ? DIRECTION_DESC : DIRECTION_ASC; } else { direction = DIRECTION_ASC; } this.property = property; this.direction = direction; } public static Order by(String property, String direction) { return new Order(property, direction); } public static Order asc(String property) { return new Order(property, DIRECTION_ASC); } public static Order desc(String property) { return new Order(property, DIRECTION_DESC); } public String getProperty() { return property; } public void setProperty(String property) { this.property = property; } public String getDirection() { return direction; } public void setDirection(String direction) { this.direction = direction; } /** * Used by SpringMVC @RequestParam and JAX-RS @QueryParam * @param order * @return */ public static Order valueOf(String order) { if(order != null) { String[] orders = order.trim().split(":"); String prop = null, dir = null; if(orders.length == 1) { prop = orders[0] == null ? null : orders[0].trim(); if(prop != null && prop.length() > 0) { return Order.asc(prop); } } else if (orders.length == 2) { prop = orders[0] == null ? null : orders[0].trim(); dir = orders[1] == null ? null : orders[1].trim(); if(prop != null && prop.length() > 0) { return Order.by(prop, dir); } } } return null; } @Override public String toString() { return property + ":" + direction; } } @Override public String toString() { return "Sort " + orders + ""; }}服务的提供者(Provider): ...

May 31, 2019 · 6 min · jiezi

Spring-Cloud-Netflix-中文文档

1、服务发现: Eureka Clients1.1. 怎么样成为Eureka客户端1.2. 注册为Eureka1.3. Authenticating with the Eureka Server1.4. Status Page and Health Indicator1.5. Registering a Secure Application1.6. Eureka’s Health Checks1.7. Eureka Metadata for Instances and Clients1.7.1. Using Eureka on Cloud Foundry1.7.2. Using Eureka on AWS1.7.3. Changing the Eureka Instance ID1.8. Using the EurekaClient1.8.1. EurekaClient without Jersey1.9. Alternatives to the Native Netflix EurekaClient1.10. Why Is It so Slow to Register a Service?1.11. Zones2. Service Discovery: Eureka Server2.1. How to Include Eureka Server2.2. How to Run a Eureka Server2.3. High Availability, Zones and Regions2.4. Standalone Mode2.5. Peer Awareness2.6. When to Prefer IP Address2.7. Securing The Eureka Server2.8. JDK 11 Support3. Circuit Breaker: Hystrix Clients3.1. How to Include Hystrix3.2. Propagating the Security Context or Using Spring Scopes3.3. Health Indicator3.4. Hystrix Metrics Stream4. Circuit Breaker: Hystrix Dashboard5. Hystrix Timeouts And Ribbon Clients5.1. How to Include the Hystrix Dashboard5.2. Turbine5.2.1. Clusters Endpoint5.3. Turbine Stream6. Client Side Load Balancer: Ribbon6.1. How to Include Ribbon6.2. Customizing the Ribbon Client6.3. Customizing the Default for All Ribbon Clients6.4. Customizing the Ribbon Client by Setting Properties6.5. Using Ribbon with Eureka6.6. Example: How to Use Ribbon Without Eureka6.7. Example: Disable Eureka Use in Ribbon6.8. Using the Ribbon API Directly6.9. Caching of Ribbon Configuration6.10. How to Configure Hystrix Thread Pools6.11. How to Provide a Key to Ribbon’s IRule7. External Configuration: Archaius8. Router and Filter: Zuul8.1. How to Include Zuul8.2. Embedded Zuul Reverse Proxy8.3. Zuul Http Client8.4. Cookies and Sensitive Headers8.5. Ignored Headers8.6. Management Endpoints8.6.1. Routes Endpoint8.6.2. Filters Endpoint8.7. Strangulation Patterns and Local Forwards8.8. Uploading Files through Zuul8.9. Query String Encoding8.10. Request URI Encoding8.11. Plain Embedded Zuul8.12. Disable Zuul Filters8.13. Providing Hystrix Fallbacks For Routes8.14. Zuul Timeouts8.15. Rewriting the Location header8.16. Enabling Cross Origin Requests8.17. Metrics8.18. Zuul Developer Guide8.18.1. The Zuul Servlet8.18.2. Zuul RequestContext8.18.3. @EnableZuulProxy vs. @EnableZuulServer8.18.4. @EnableZuulServer Filters8.18.5. @EnableZuulProxy Filters8.18.6. Custom Zuul Filter ExamplesHow to Write a Pre FilterHow to Write a Route FilterHow to Write a Post Filter8.18.7. How Zuul Errors Work8.18.8. Zuul Eager Application Context Loading9. Polyglot support with Sidecar10. Retrying Failed Requests10.1. BackOff Policies10.2. Configuration10.2.1. Zuul11. HTTP Clients12. Modules In Maintenance Mode

May 29, 2019 · 2 min · jiezi

Spring-Cloud-Eureka-自我保护机制实战分析

前些天栈长在Java技术栈微信公众号分享过 Spring Cloud Eureka 的系列文章: [Spring Cloud Eureka 自我保护机制](https://mp.weixin.qq.com/s/vw... Spring Cloud Eureka 常用配置详解其中,可能大家关于自我机制的具体保护逻辑还不是特别清楚,今天栈长就具体分析和实战一下,自我保护机制到底是怎么工作的。 现在我们把保护机制开启: 关注右上角的两个重要参数: 参数说明Renews thresholdEureka Server 期望每分钟收到客户端实例的总心跳数Renews (last min)Eureka Server 最后一分钟收到的总心跳数我这里显示的数值如下: Renews threshold 6Renews (last min) 8这个 6 和 8 分别是怎么算出来的? 先来看这两个参数的默认设置,摘自《Spring Cloud Eureka 常用配置详解》一文: eureka.server.renewal-percent-threshold:表示 Eureka Server 开启自我保护的系数,默认:0.85。eureka.instance.lease-renewal-interval-in-seconds:表示 Eureka Client 向 Eureka Server 发送心跳的频率(默认 30 秒),如果在 lease-expiration-duration-in-seconds 指定的时间内未收到心跳,则移除该实例。 这里有 4 个注册实例,保护系数:0.85,心跳频率:30秒(每分钟两次),计算公式如下: Renews threshold = 4 * 2 * 0.85 = 6.8(取整为:6)Renews (last min) = 4 * 2 = 8现在删除一个配置中心实例测试一下: ...

May 27, 2019 · 1 min · jiezi

客户端负载均衡Ribbon之源码解析

什么是负载均衡器?假设有一个分布式系统,该系统由在不同计算机上运行的许多服务组成。但是,当用户数量很大时,通常会为服务创建多个副本。每个副本都在另一台计算机上运行。此时,出现 “Load Balancer(负载均衡器)”。它有助于在服务器之间平均分配传入流量。 服务器端负载均衡器传统上,Load Balancers(例如Nginx、F5)是放置在服务器端的组件。当请求来自 客户端 时,它们将转到负载均衡器,负载均衡器将为请求指定 服务器。负载均衡器使用的最简单的算法是随机指定。在这种情况下,大多数负载平衡器是用于控制负载平衡的硬件集成软件。 重点: 对客户端不透明,客户端不知道服务器端的服务列表,甚至不知道自己发送请求的目标地址存在负载均衡器。服务器端维护负载均衡服务器,控制负载均衡策略和算法。客户端负载均衡器当负载均衡器位于 客户端 时,客户端得到可用的服务器列表然后按照特定的负载均衡策略,分发请求到不同的 服务器 。 重点: 对客户端透明,客户端需要知道服务器端的服务列表,需要自行决定请求要发送的目标地址。客户端维护负载均衡服务器,控制负载均衡策略和算法。目前单独提供的客户端实现比较少( 我用过的只有Ribbon),大部分都是在框架内部自行实现。Ribbon简介Ribbon是Netflix公司开源的一个客户单负载均衡的项目,可以自动与 Eureka 进行交互。它提供下列特性: 负载均衡容错以异步和反应式模型执行多协议 (HTTP, TCP, UDP)缓存和批量Ribbon中的关键组件 ServerList:可以响应客户端的特定服务的服务器列表。ServerListFilter:可以动态获得的具有所需特征的候选服务器列表的过滤器。ServerListUpdater:用于执行动态服务器列表更新。Rule:负载均衡策略,用于确定从服务器列表返回哪个服务器。Ping:客户端用于快速检查服务器当时是否处于活动状态。LoadBalancer:负载均衡器,负责负载均衡调度的管理。源码分析LoadBalancerClient实际应用中,通常将 RestTemplate 和 Ribbon 结合使用,例如: @Configurationpublic class RibbonConfig { @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); }}消费者调用服务接口: @Servicepublic class RibbonService { @Autowired private RestTemplate restTemplate; public String hi(String name) { return restTemplate.getForObject("http://service-hi/hi?name="+name,String.class); }}@LoadBalanced,通过源码可以发现这是一个标记注解: /** * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient * @author Spencer Gibb */@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Qualifierpublic @interface LoadBalanced {}通过注释可以知道@LoadBalanced注解是用来给RestTemplate做标记,方便我们对RestTemplate添加一个LoadBalancerClient,以实现客户端负载均衡。 ...

May 25, 2019 · 4 min · jiezi

HystrixFeign的详细构建过程及自定义扩展功能

spring-cloud-openfeign-core-2.1.1.RELEASE.jar 中 HystrixFeign 的详细构建过程:@EnableFeignClients -> FeignClientsRegistrar 扫描 @Feign注解的类 -> FeignClientFactoryBean通过Targeter生产FeignClient -> Targeter通过Feign.Builder构建Feign -> Feign.Builder 1. 准备工作(配置)FeignAutoConfiguration自动配置类 @Configuration @ConditionalOnClass(name = "feign.hystrix.HystrixFeign") protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new HystrixTargeter(); } } @Configuration @ConditionalOnMissingClass("feign.hystrix.HystrixFeign") protected static class DefaultFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new DefaultTargeter(); } }feign.hystrix.HystrixFeign类存在时,将 HystrixTargeter 注册为 Targeter 类型的 beanfeign.hystrix.HystrixFeign类不存在时,使用 DefaultTargeter 。看起来似乎可以使用自定义的Targeter代替Hystrix或默认的,这样就可以自定义各种功能了。实际上不行,因为 Targeter 是 package 访问级别的。FeignClientsConfiguration@Configurationpublic class FeignClientsConfiguration { @Bean @ConditionalOnMissingBean public Retryer feignRetryer() { return Retryer.NEVER_RETRY; } @Bean @Scope("prototype") @ConditionalOnMissingBean public Feign.Builder feignBuilder(Retryer retryer) { return Feign.builder().retryer(retryer); } @Configuration @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class }) protected static class HystrixFeignConfiguration { @Bean @Scope("prototype") @ConditionalOnMissingBean @ConditionalOnProperty(name = "feign.hystrix.enabled") public Feign.Builder feignHystrixBuilder() { return HystrixFeign.builder(); } }}重要:Feign 以及内部类 Feign.Builder 都是 public 访问级别,可以注入自定义的bean。 ...

May 24, 2019 · 5 min · jiezi

微服务网关实战Spring-Cloud-Gateway

作为Netflix Zuul的替代者,Spring Cloud Gateway是一款非常实用的微服务网关,在Spring Cloud微服务架构体系中发挥非常大的作用。本文对Spring Cloud Gateway常见使用场景进行了梳理,希望对微服务开发人员提供一些帮助。 微服务网关SpringCloudGateway 1.概述 Spring cloud gateway是spring官方基于Spring 5.0、Spring Boot2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效和统一的API路由管理方式,Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filer链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。 2.核心概念 网关提供API全托管服务,丰富的API管理功能,辅助企业管理大规模的API,以降低管理成本和安全风险,包括协议适配、协议转发、安全策略、防刷、流量、监控日志等贡呢。一般来说网关对外暴露的URL或者接口信息,我们统称为路由信息。如果研发过网关中间件或者使用过Zuul的人,会知道网关的核心是Filter以及Filter Chain(Filter责任链)。Sprig Cloud Gateway也具有路由和Filter的概念。下面介绍一下Spring Cloud Gateway中几个重要的概念。 路由。路由是网关最基础的部分,路由信息有一个ID、一个目的URL、一组断言和一组Filter组成。如果断言路由为真,则说明请求的URL和配置匹配断言。Java8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于http request中的任何信息,比如请求头和参数等。过滤器。一个标准的Spring webFilter。Spring cloud gateway中的filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理 如上图所示,Spring cloudGateway发出请求。然后再由Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway web handler。Handler再通过指定的过滤器链将请求发送到我们实际的服务执行业务逻辑,然后返回。 快速入门 以Spring Boot框架开发为例,启动一个Gateway服务模块(以Consul作为注册中心),一个后端服务模块。client端请求经gateway服务把请求路由到后端服务。 前提条件: Consul:版本1.5.0。Spring bot:版本2.1.5。Spring cloud:版本Greenwich.SR1。Redis:版本5.0.5。1.微服务开发 这里以使用Spring Boot框架开发微服务为例,启动一个服务并注册到Consul。 引入依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency>注册服务到Consul,配置文件配置如下: spring: application: name: service-consumer cloud: consul: host: 127.0.0.1 port: 8500 discovery: service-name: service-consumer如下定义RestController,发布HTTP接口。 ...

May 24, 2019 · 4 min · jiezi

spring-cloud-consul-config小demo遇到的问题

最近公司想让我看看微服务 正好我也想看看新东西,天天解决业务问题。。。太没有激情了。。。而且我们大多应用都还是springmvc,springboot的应用都很少,只有几个,唉,我也是深陷业务问题中 Spring Cloud也算是一个全家桶吧,里面东西也多,不过从感觉开箱即用的原则来看,用起来也比较顺手,demo也都很好搭建,从开始的网关+服务的着手,网关我采用的Zuul,服务治理采用的eureka,后面想用spring cloud config作为配置中心,但是还要自己搭一个server很是麻烦。。。我也懒。。。无意听同事说,其实全家桶里服务治理可以用spring cloud consul,而consul就自带一个配置功能,于是我去了解了spring cloud consul configspring cloud consul config本身依赖spring cloud consul的agent server,所以只要agent server启动了,其实就相当于有了一个server来做配置,我满心欢喜的把服务治理eureka改为spring cloud consul,嗖嗖两下,spring cloud consul也配置好了命令行里执行了,启动测试模式的agent server consul agent -dev打开localhost:8500, 很明显有了一个类似配置中心的菜单 点开进去啥也没有。。。只有右边一个创建按钮 也没灰心,我先是去官网介绍看了看 官网链接描述 我承认我英语是差了。。。看了半天,我真是没看明白怎么使用。。。当时我有点懵逼,说好的很好操作的呢 没办法,我只有去百度了哈,看了很多文章,基本所有文章说的都是差不太多,但是这个差不太多又都没有说清楚到底怎么玩。。。好吧,这个时候我有点承认我自己理解能力有点问题了,心想既然大家都没有说清楚,估计应该就是很容易理解,所以大家心照不宣,我又反复读了哈官方的描述,并且找了springcloud.cc里的中文说明文档,还是没看太懂。。。 当时我真的觉得有点懵了。。。心想今天算了还是不想这个,明天再想,于是我去把demo的网关换成了spring cloud gateway,这个基本没有半个小时就搞定了,还是比较简单的 第二天也就是今天,我再次来看了哈文档,百度的几篇文章除了说明了一点,要加一个配置文件bootstrap.yml,这里面要去指定一些spring cloud consul config的一些配置,并且意思感觉是application.yml里的配置都可以不用写了,完全维护在spring cloud consul config里,但是spring cloud consul config到底在哪,我还是无法把需要配置的属性,application.yml和consul agent里刚一片空白的配置页面,这三者联系起来 终于无意中,我发现有一篇文章的一句话让我警醒了。。。他不是像其他文章说一些貌似大家都懂的话,而是非常郑重了说了一句 感觉这难道也是一个理解能力和我差不多,但是比我强的人么。。。他这么一句让我明白,确实官网说的也不太明白,最后那句体会一下,我再去反复看了文章,和自己试验。。。 终于懂了。。。懂了之后再回过头来看,spring cloud consul config还是真的真的非常简单的。。。其实就是想要用spring cloud consul config,你要和它的一些约定或者说它的规范匹配起就完事了,剩下就跟普通的配置文件一样了,接下来我用我自己的理解来说明哈spring cloud consul config怎么使用,当然前提你对于服务治理consul有点点了解哈 spring cloud consul config其实就是一个服务的配置中心,配置统一管理的地方,你哪个服务需要这个配置中心,你就在那个服务里加上依赖 ...

May 24, 2019 · 1 min · jiezi

记录Spring-Cloud应用在阿里云架构部署

常用的Spring Cloud体系架构 系统部署采用阿里云平台,采用的技术架构为SpringCloud. 采用在线阿里云架构制图工具: Freedgo Design 地址:https://www.freedgo.com, 具体架构如下: 整体架构主要居于Spring Cloud的分布式微服务架构。主要功能包括: 服务注册发现中心(Eureka server)通过服务发现可以抽象出部署服务的物理位置如IP,服务调用通过了逻辑名称而不是实际的物理位置,同时服务发现也处理了注册和注销。 服务配置中心(config server)通过集中式的服务来处理应用程序配置数据。做到无论启动多少个微服务实例,这些实例始终使用相同的配置,同时服务的配置可以和微服务系统分离 服务网关(ZUUL)通过ZUUL网关,可以强制执行一些功能如内容过滤,路由转发,过滤器等等 Spring Sleuth & ZIPKIN(分布式服务跟踪)通过Sleuth 相关ID进行全链路跟踪,可以分析服务调用的性能 事件驱动及异步消息用于处理异步事件如短消息推送,邮件发送等。 用户认证中心(auth2)ZUUL网关ZUUL网关主要的功能路由及过滤器设置通常在ZUUL网关设置过滤器包括前置过滤器、后置过滤器、路由过滤器,可以自定义一些逻辑,在大多数情况下,这种自定义逻辑用于强制执行一组一致的应用程序策略,如安全性、日志记录和对所有服务的跟踪等等。 路由的设置可以指定路由地址URL对应的微服务如下图: 服务注册与发现:ZUUL网关服务器通过注册到Eureka服务器,实现了Eureka上注册的微服务的发现从而转发用户的请求到各应用模块,网关服务器中Ribbon同时会缓存微服务相关信息以减少对EureKa访问。 微服务应用Oauth2授权访问ZUUL网关负责请求的路由转发,Request请求不仅仅来在用户浏览器,有可能是微服务之间的相互调用。 登录用户请求或服务之前调用会在request请求头中携带Authorization 头信息来表示当前用户的身份信息, Http Restful Api微服务应用采用 Spring RestController 对外发布 Http Restful Api服务, 微服务之间的调用微服务之间相互调用而不必知道被调用者所在位置是通过Eureka服务发现实现,当微服务启动时会注册自己到Eureka服务中心,服务消费者可以使 Ribbon 来进行交互。有三种方式的调用: Spring DiscoveryClient启用了 RestTemplate 的 Spring DiscoveryClient通过 Netflix Feign 客户端方式部署方案(docker)采用Docker通过spotify 的docker-maven-plugin工具进行docker image进行打包镜像 灰度测试通过ZUUL的过滤对新上线的服务做路由的权重算法,做到限流,A/B测试。 平台开发开发语言:java,Java是一种可以撰写跨平台应用程序的面向对象的程序设计语言。开发工具:eclipse,Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。主要使用的开源软件软件功能版本JDKJAVA开发SDK包1.8 以上UbuntuLinux服务器操作系统14MySQL数据库5.7+Mavenjava 项目构建工具4.0Spring Framework系统架构5.0以上Spring cloud分布式微服务2.0+kafka消息订阅发布框架 Redis高性能Key value存储 Docker

May 22, 2019 · 1 min · jiezi