首页 > 经验记录

说是简单,tm那是找到解决方案之后才简单。

可能是我用的SpringCloud版本太新了,自己配zipkin server把我给配吐了。

又是版本冲突、又是注册不进去Eureka、又是访问ui报错、又是找不到ObjectProvider.orderedStream()方法的,我从百度搜到必应搜到google搜到Stack Overflow,整了一个上午。

我就想着,这玩意怎么能这么恶心呢?感觉像写maven的时候狂报xml错误那种感觉。

 

后来怼到zipkin官网 zipkin.io 上去,卧槽,快速入门里有这么句话:

If you have Java 8 or higher installed, the quickest way to get started is to fetch the latest release as a self-contained executable jar:

 

 

我佛了。然后又查了些关于高版本资料,关于 Zipkin 的服务端,在使用 Spring Boot 2.x 版本后,官方就不推荐自行定制编译了,反而是直接提供了编译好的 jar 包来给我们使用,这是官方提供的演示: https://github.com/openzipkin/docker-zipkin

白搞了半天,原来只要自己去下他的jar包然后启动这个服务就行了,至于如何将微服务跟踪的数据存到mysql/kafka/es 里边去,也可以直接用启动参数指定。

那我还自己配个蛇皮的zipkin server。

 

可以去这个网址: https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/ 选择下载zipkin的各个不同版本的启动jar,我随便找了一个,启动很顺畅,进入 localhost:9411 可以访问ui。

那服务端就算这样配完了,全部流程: 下载 –> 使用 java -jar 命令运行下载的jar

 

服务端搞完后,就到客户端了。

微服务链路跟踪嘛,需要得到请求经过了哪些微服务,了解请求流转的具体参数,那么客户端自然就是一个个不同的微服务了。

 

以我之前的user微服务为例,配置都一样。

build.gradle中加上这一行:

本来应该是spring-cloud-starter-sleuth,spring-cloud-sleuth-zipkin这两个依赖,但是spring-cloud-starter-zipkin这个集成了前面那俩,和前面那俩依赖效果是一样的。

加完依赖后只需要指定zipkin服务地址就好了

我的applicayion.yml:

 

spring.zipkin.base-url 指定地址。zipkin端口号默认9411。

spring.sleuth.sampler.probability 设置采样百分比,采样百分比就是会按比例来跟踪/保存多少条请求数据,因为在线上运行的话那数据是相当庞大的。默认设置的是0.1,也就是百分之十,我这设置百分之百是为了本地调试。

 

然后就完事了

对,没问题。所有微服务开起来,Eureka、Zuul等等,当然还有Zipkin官方服务。网页请求几个API,再去 localhost:9411 刷新一下,就可以看到每一条请求的详细信息了。

 

实现微服务跟踪需要的步骤:

1、 下载官方推荐的jar包

2、运行起来

3、改下微服务,加个依赖加个配置

完事了,如果想要保存数据到es/mysql/kafka里分析,可以设置启动参数,具体可以去看官方、github

 

 

我的使用Gradle搭的SpringCloud Finchley.SR3 项目整体地址:

https://github.com/skypyb/codeDemo/tree/master/sc-demo-microservice

阅读全文

上篇文章主要是搭建了一下Zuul的服务,并且实现了Zuul过滤器的自定义需求。

里边讲到了,Zuul 已经集成了 Ribbon、Hystrix ; 而 Ribbon无需配置,会在请求路由时自动给你进行负载均衡。

但是在Zuul服务路由不到对应微服务时,是没有对应的回退机制的,还是得自己手动写一下。

 

实现路由失败回退机制,首先需要继承 FallbackProvider 类,实现其getRoute() 和 fallbackResponse() 方法。

getRoute方法是指定你需要回退的线路,返回一个服务名就行。它会在路由该服务发生故障时调用 fallbackResponse 方法从而返回你一个 ClientHttpResponse 对象。

 

我写的回退代码:

 

 

这个代码会在路由到sc-demo-microservice-user这个服务出错时触发,然后根据不同的异常给出不同的响应(我这就是变了个Status哈)

配上一个回退机制后,就让Zuul服务更加完善健壮了,这样子,就算路由的服务挂掉了,我也能返回个东西让前端显示,也能做一些其余的抢救操作。

 

Zuul这个服务到这,其实也就差不多了,该有的都有,虽说也有Zuul这个服务挂掉的可能,但是Zuul也是可以集群的呀,前端可以访问一个负载均衡的服务器(比如Nginx),让他来转发请求到集群Zuul服务上边,这样子,整个微服务架构就非常健壮了(像这种Nginx服务一般不会挂哈,就一个纯走流量的服务器都能挂了,那你的流量是有多猛   除非硬件问题,那没辙)

 

咳咳, 说起来Zuul服务搭是搭好了,但是你就做一个服务路由+负载均衡,那也不是个事啊,我客户端那边请求服务,我要是需要多个数据,我是不是要发多个请求?

每个请求都要走–>zuul–>service 这一套流程,是不是不大好,毕竟我发多个请求来请求多个服务,总会有性能损耗。

那要是我就发一个请求到Zuul Server ,然后由Zuul 来帮我聚合请求多个微服务,包装成一个数据返回响应给我好不好鸭,那当然是极好的。这些微服务所在的服务器八成是在一个局域网里(除非你买的实例所在地区不同甚至供应商都不同哈) 那个网络传输速度,快的飞起来。

 

这个是我写请求聚合的代码:

 

我这就请求了zuul一个服务,然后就全权交给zuul给我把我要的数据都拿到了,组合成一个数据响应给我,是不是非常nice。我客户端的请求代码编写,也变得简单了。

 

到现在为止,整个Zuul架构就差不多了。自定义过滤器、回退、请求聚合、我还提供了一个zuul的集群高可用方案。基本上可以满足大多生产需求。

我的项目地址:Github

阅读全文

 

微服务架构有一个问题,那就是客户端如何访问各个微服务。

总不能在客户端APP/HTML写很多个不同的地址来请求吧?这样维护及其困难、开发不易。

这时候就需要一个网关,客户端的请求都发给这个网关, 然后由他来给你路由到别的微服务里边。

netflix 就开源了一个微服务网关:Zuul ,可以和 SpringCloudNetflix 全家桶(Eureka、Ribbon、Hystrix等)完美集成。

 

废话不多说.代码撸起来。

首先,项目创建,当然,创建的还是我那个Gradle搭的SpringCloudFinchley项目的子模块。

这回不用加什么依赖,只需要一个Zuul的依赖和Eureka Client的依赖就够了。

而且Zuul自己本身就集成了Ribbon和Hystrix,非常强大。

build.gradle:

 

然后在Application启动类上边加上@EnableZuulProxy 用以声明zuul代理

最主要的: 配置类yml文件

既然这个 zuul 是提供一个服务路由的功能,又已知 zuul 完美的集成了 Eureka。可以从Eureka Server中得到所有注册进去的服务。

那么,最需要进行配置的。自然是访问路径所对应的服务啦, 在zuul这个服务的配置文件里,专门有个地方给你写这个路由规则( zuul.routes )

我的配置文件:

 

虽然我这个配置文件里注释已经写得挺详细了,但还是简单的解释一下:

zuul.routes 这个属性树下面第一级节点,即我写的local-router、user-router 等,这一级只是让你写个路由规则的名字。 瞎写就行。

再下一级,大致可以分为两种:

1、路由到其余微服务的 指定好 service-id(即服务注册进Eureka的服务名) 和对应的访问路径就行了 ( 例如: 我用户微服务有个API请求路径是 user/{id},我现在就可以通过 ZUUL_ADDRESS:ZUUL_PORT/zuul_user/user/{id} 来访问我sc-demo-microservice-user中的API)。

 2、路由到本地由Zuul自己进行处理的 指定好客户端访问路径,和对应的本地API地址( forward: +本地API的地址) 就行

 

到这步,其实Zuul这个服务就搭建完毕了, 已经可以使用了。而且,不但可以帮你进行服务路由,还会用自带的Ribbon给你的请求进行负载均衡。

 

搭建完了,当然还不够,还能让这个 zuul 服务更加强大

zuul的路由功能是基于他自己编写的一大堆过滤器实现的,这里先简单说下他的过滤器类型

他主要有四大标准过滤器类型,这四种是最主要的

1、PRE  在请求被路由之前调用这个过滤器

2、ROUTING 这个过滤器将请求路由到微服务

3、POST 这个过滤器在路由到对应微服务之后再执行

4、ERROR 出错时进的

 

zuul 他自己有这几个过滤器的实现,当然,他写的我不动他,我可以自己额外写过滤器来实现自己的功能嘛。

zuul过滤器的实现非常简单,只要继承 ZuulFilter 这个类就完事了。

我写了个日志记录的过滤器:

这几个方法不多说,看下ZuulFilter源码的注释就知道具体是什么意思了。反正就是关于你写的过滤器的设置(类型、执行顺序、是否执行、具体逻辑)

我这过滤器很简单,就记录一下请求方法、地址,是个PRE类型的过滤器,会在路由之前调用。过滤器能干的事情很多,认证啊、加密啊啥的都行,看业务需求了。

 

 

阅读全文

上个文章使用了Eureka搭建了集群服务注册中心,但是最后实现 RPC 的方式还是  从代码中获得服务对应地址->字符串拼接->请求获得响应  的这样一种方式。

这种方式弊端还是有不少的。如果可以像调用自己的服务一样调用别人提供的服务那该多舒适啊。

 

而 Feign 就可以实现这种需求,Feign也是网飞开发的,SpringCloud 使用 Feign 非常简单,我下边演示一下:

首先 服务消费者这边肯定需要一个对应的依赖:

需要启用Feign的话,也得在启动类上面加个注解 @EnableFeignClients

然后,创建一个 Feign 的接口,像这样子

@FeignClient 注解里边的默认属性,也就是name属性是一个客户端的名字,如果使用了Eureka的话,会给他自动解析为 Eureka Server 服务注册表中的服务。

要是配了Ribbon,也会使用默认的负载均衡策略来执行请求。

Feign默认使用SpringMVC的注解声明请求,当然也可以用Feign自带的注解。不过没啥必要,还需要配置东西。

 

我上边这个例子写完了,实际使用的话只需要注入该类然后调用对应的方法就完事了。非常简便。

不过有几个点需要注意

在使用@FeignClient 声明的Feign伪装类中:

使用 @PathVariable 注解,必须加上参数!

GET请求无法使用对象作为入参! 要不有多少参数写多少参数(每个都要加@RequestParam(“参数名”) 注解),要不就用接受一个Map对象,也得加@RequestParam

POST请求可以接收对象,需要加上@RequestBody注解

 

 

Feign论使用的话,其实已经差不多了。

但是还有一些相关的操作也比较重要。

 

Feign 的请求都是使用的默认配置,我们其实可以实现自己的配置供 Feign 使用以实现编码、解码、日志记录、验证 等等等等。

比如我可以这么定义一个配置类:

该类配置了对应的日志记录器,和一个简单的效验,以应对请求的验证。

在对应的Feign伪装类中,上边的@FeignClient注解改一下,就可以使用自己写的配置:

之所以在 @FeignClient 注解中指定配置,是因为我的配置类是没有加 @Configuration 注解的,我想要实现细粒度的控制。 推荐这样做。

如果加了@Configuration 注解,则 Spring 会将其自动解析自动应用到全局,这样子就不方便为每个请求进行细粒度调整。

 

 

阅读全文

上一篇 Spring Cloud 项目的搭建文章 : 链接

 

再说下我的版本号 , 用的比较新:

 

Spring Boot 2.0.5 RELEASE

Spring Cloud Finchley.SR3

项目管理工具: gradle


进入正题:

从之前的项目构造来看,RPC虽然是实现了,但是调用的链接确是写死在代码中的,比较丑陋。

要是提供服务的地址突然换了,那这边消费者直接雪崩,只能更改代码重新部署。而且无法实现负载均衡,这在一个微服务架构中是很不合理的。

要解决这问题,作为服务消费者,必须要有一个牛逼的服务发现机制。

Spring Cloud 就提供了多种服务发现组件的支持。Eureka、ZooKeeper 等,我这就用 Eureka 了, 在 Spring Cloud 这个生态圈里Eureka是比较流行的。

Eureka是网飞(Netflix)开源的服务发现组件。有Server和Client两部分,按需使用就行,我这就使用他们来构建一个高可用的服务注册中心。

 

我先把之前父模块的的Mybatis、mysql依赖给去了,放到了实际的微服务中(user/movie)。因为Eureka服务不需要这几个依赖,要是加载了mysql依赖会自动连接mysql,不加mysql的配置就会报一堆错误。

 

既然 Eureka 也是个服务,那当然也得在父模块下创建一个Eureka子模块。和其余的模块创建相同,没什么好说的。

给 Eureka 服务注册中心模块加上这个 Eureka Server 依赖

compile(“org.springframework.cloud:spring-cloud-starter-netflix-eureka-server“)

然后在 Eureka 服务的入口 java 文件上加上该注解 @EnableEurekaServer , 这个Application就是完全体了。

 

此时可以在网页里通过 ip:port 来访问页面,可以得知注册中心的状态、多少服务链接到本机。

 

Eureka Server 端写完后,需要注册的服务则需要导入Eureka的Client依赖,就是这个:

compile(“org.springframework.cloud:spring-cloud-starter-netflix-eureka-client“)

然后只要在yml文件中配置好要连接的服务注册中心的地址就完事了,其实此时一个服务注册发现功能已经可以完成了。

但是还不够,需要考虑到若是 Eureka Server 端突然宕掉,那么整个系统就会出问题。

客户端虽然会有相应的缓存(服务注册时会将Server端储存的数据拿到本地缓存),但是在此时若是其他的服务发生变更,靠缓存中的信息去请求就不正确了。

 

所以,想要高可用的一个服务注册中心,则需要搞一个集群。宕掉一个,还有另外的,这样容错率将大大提高。

其实Eureka搞集群非常简单。不过是开启两个实例,A实例注册进B实例,B实例注册进入A实例而已。

只需要使用两种不同的配置即可。(你要是想开五个就是五个不同的配置,看着加就完事了)

像我这样,我这是写在一个yml文件里了,用“—”来隔开,要是配置比较多是可以另起一个文件的,就叫application-xxx.yml。

可以使用 –spring.profiles.active=xxx 来启动不同的服务。

(这里有部分Security的配置,下面就讲)

在IDEA里边,可以使用这种方式来启动不同的实例:

集群也搭完了,启动第一个Eureka Server时可能会出点连接错误,不过不影响启动,这是因为第二个Server还没启动起来,而配置里需要它注册进去导致的,第二个启动起来后就没错误了。

你要是一下子就从网页进去看Eureka的状态,可能会出现红色粗体的:EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

这个是Eureka的自我保护机制导致的。Eureka Server和Client之间每隔一段时间会进行一次心跳通信,告诉Server,Client还活着。要是某一段时间Server感觉自己这边少了几个心跳就会出这问题,只要不是真的你服务宕掉了,过一会就好了。

 

配置完毕后,客户端也只需要在配置文件中写两个链接就行,用逗号隔开。其实写一个也可以,因为Eureka集群会自动同步其他Eureka的注册信息。但还是推荐写俩,就是怕某些极端情况发生。

 

此时集群已经搭建完毕。客户端也可以连接得上,但是,这些端口就这样暴露出来也是很不科学的。攻击者可以轻易地得到你的服务信息。

最好的,当然还是加个验证啦!用户名密码这种验证永远不过时哈。

搭建完集群后,用 Spring Security 为 Eureka 增加 Basic 安全认证就很不错了!

只需要在 Eureka Server这边添加 Spring Security 的依赖就够了,Client端不用。

compile(“org.springframework.boot:spring-boot-starter-security“)

 

添加Security的依赖后就会自动开启验证,不用配置。用户名和密码的设定就像上边文件一样,只需要这样就行。

 

配置完用户名和密码后,连接Eureka Server自然就需要用到这些用户名和密码。

本来连接Server的的URL:   http://ip:port/eureka/

现在连接Server的的URL:   http://username:password@ip:port/eureka/

就算是从网页查看状态,也需要输入用户名和密码了哦。

 

Client端最终配置文件如下(反正配置都长得差不多,我这就放其中一个服务的文件就行了):

 

这样,其实应该就完事了,但是,在2.x版本的 Spring Security 中,引入依赖后,自动开启CSRF安全认证。

任何一次服务请求默认都需要CSRF 的token , 而我区区一个小Client,哪里来的这种东西。就是Eureka Server 自注册都会挂掉。

那么还是要让 Security 的CSRF拦截自动忽略掉注册Eureka的链接比较好。

在 Eureka Server 端增加这么一个配置类:

这样子去除 /eureka/  这个连接的 CSRF 效验。就都可以连接上了。

 

OK 整体 Eureka 注册中心都搭建完毕了。并且实现了集群高可用和安全策略,比较完善。

 

服务之间的调用在做一点点微小的改进:

 

通过 DiscoveryClient 这个类,可以获取到对应服务的信息,这里我便是用 movie 服务获取到了user 服务的 url  来进行的调用。

当然,就算是这样,也不是那么的方便,关于feign声明式调用之后也会写篇文章的。

 

我的项目地址: github

阅读全文
EA PLAYER &

历史记录 [ 注意:部分数据仅限于当前浏览器 ]清空

      00:00/00:00