Springcloud笔记
一.微服务
1.什么是微服务?
微服务一词来源 Martin Fowler 的“Microservices” 一文, 微服务是一种架构风格, 将 单体应用划分为小型的服务单元, 微服务之间使用 HTTP 的 API 进行资源访问与操作。 在对单体应用的划分上, 微服务与前面的 SOA 架构有点类似, 但是 SOA 架构侧重于 将每个单体应用的服务集成到 ESB 上, 而微服务做得更加彻底, 强调将整个模块变成服务 组件, 微服务对模块的划分粒度可能会更细。 以我们前面的销售、 会员模块为例, 在 SOA 架构中, 只需要将相应的服务发布到 ESB 容器就可以了, 而在微服务架构中, 这两个模块 本身, 将会变为一个或多个的服务组件。
从技术维度理解:
微服务化的核心就是将传统的一站式应用,根据业务拆分成一个个的服务,彻底的去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事,从技术角度看就是一种小儿独立的处理过程,类似与进程的概念,能够单独启动或销毁,拥有自己独立的数据库。
微服务 Martin Fowler 译文
https://blog.csdn.net/u013970991/article/details/53333921
2.面试题
2.1 spring cloud 与dubbo区别?
最大区别:SpringCloud 抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式,ubbo只是类似Netflix的一个子集了 。
Dubbo 刘军:未来积极适配 Spring Cloud 生态
首先要明确的一点是 Dubbo 和 Spring Cloud 并不是完全的竞争关系,两者所解决的问题域并不一样:Dubbo 的定位始终是一款 RPC 框架,而 Spring Cloud 的目标是微服务架构下的一站式解决方案。
如果非要比较的话,我觉得 Dubbo 可以类比到 Netflix OSS 技术栈,而 Spring Cloud 集成了 Netflix OSS 作为分布式服务治理解决方案,但除此之外 Spring Cloud 还提供了包括 config、stream、security、sleuth 等等分布式问题解决方案。
当前由于 RPC 协议、注册中心元数据不匹配等问题,在面临微服务基础框架选型时 Dubbo 与 Spring Cloud 是只能二选一,这也是为什么大家总是拿 Dubbo 和 Spring Cloud 做对比的原因之一。
Dubbo 之后会积极寻求适配到 Spring Cloud 生态,比如作为 Spring Cloud 的二进制通信方案来发挥 Dubbo 的性能优势,或者 Dubbo 通过模块化以及对 http 的支持适配到 Spring Cloud 。
Spring Boot中application.yml与bootstrap.yml的区别
Bootstrap.yml(bootstrap.properties)在application.yml(application.properties)之前加载
application.yml通常覆盖Bootstrap.yml 中的内容 。
@RefreshScope
当配置更改时,标有@RefreshScope的Spring @Bean将得到特殊处理。
首先先介绍下实现后的效果:
1、在需要动态配置属性的类上添加注解@RefreshScope表示此类Scope为refresh类型的
2、启动工程,修改config-server对应的配置文件,这里修改的是system.order.serverName
3、以post的方式调用refresh接口,返回修改后的key值
4、访问infoTest接口,可以看到修改后的值
Spring RestTemplate
RestTemplate可以自动配置为使用功能区。要创建负载平衡RestTemplate创建RestTemplate @Bean并使用@LoadBalanced限定符。
@Configuration
public class MyConfiguration {
//Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
public class MyClass {
@Autowired
private RestTemplate restTemplate;
/**
* 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
* ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
*/
public String doOtherStuff() {
String results = restTemplate.getForObject("http://stores/stores", String.class);
return results;
}
}
Spring Cloud Config
Spring Cloud Config服务器
@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
SpringApplication.run(ConfigServer.class, args);
}
}
配置SVN仓库
server:
port : 8888
management :
security :
enabled : false
spring :
profiles:
active : subversion
cloud:
config :
server:
svn :
uri : https : //localhost/svn/test-project
username: admin
password: 123456
default-label : default-config
Spring Cloud Config客户端
spring :
application:
name : spring-book - service
cloud :
config :
uri: http : //localhost : 8888
profile : dev
management :
security :
enabled : false
Eureka
Eureka 包含两个组件:Eureka Server 和Eureka Client
4.1 eureka server
启动类上@EnableEurekaServer
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
eureka:
client:
registerWithEureka: false #声明是否将自己的信息注册到Eureka 服务器
fetchRegistry: false #是否到 Eureka服务器中抓取注册信息
地址栏 进入eureka界面
公益eureka地址: eureka.client.serviceUrl.defaultZone=http://eureka.didispace.com/eureka/
4.2 service provider
<!-- 将微服务provider侧注册进eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
@SpringBootApplication
@EnableDiscoveryClient
public class FirstInvoker {
public static void main(String[] args) {
SpringApplication.run(FirstInvoker.class, args);
}
}
1,@EnableDiscoveryClient 注解是基于spring-cloud-commons依赖,并且在classpath中实现;
2,@EnableEurekaClient 注解是基于spring-cloud-netflix依赖,只能为eureka作用;
就是如果选用的注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他的注册中心,那么推荐使用@EnableDiscoveryClient。
需要注意的是@EnableEurekaClient 注解已经包含了 @EnableDiscoveryClient 的功能,
spring:
application:
name: first-service-provider
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
4.3 service invoker
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
@SpringBootApplication
@EnableDiscoveryClient
public class FirstInvoker {
public static void main(String[] args) {
SpringApplication.run(FirstInvoker.class, args);
}
}
spring:
application:
name: first-service-invoker
eureka:
instance:
hostname: localhost
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
4.4 eureka集群搭建
就是N个服务器启动后, 它们会互相注册。
编写 REST 客户端 进行测试
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #注册集群
instance:
instance-id: microservicecloud-dept8001
prefer-ip-address: true #访问路径可以显示IP地址
Eureka 自我保护机制:好死不如赖活着
Ribbon 负载均衡框架
Ribbon 主要有以下三大子模块:
ribbon-core: 该模块为 Ribbon 项目的核心, 主要包括负载均衡器接口定义、 客户 端接口定义, 内置的负载均衡实现等 API。
ribbon-eureka: 为 Eureka 客户端提供的负载均衡实现类。
ribbon-httpclient: 对 Apache 的 HttpClient 进行封装, 该模块提供了含有负载均衡 功能的 REST 客户端。
负载均衡器
客户端在发送请求时, 会使用负载均衡器( ILoadBalancer) 接口, 根据特定的逻辑来选择服务器
// 创建负载均衡器
ILoadBalancer lb = new BaseLoadBalancer();
自定义负载规则
选择哪个服务器进行请求处理, 由 ILoadBalancer 接口的 chooserServer 方法决定, 而在 BaseLoadBalancer 类中, 则使用 IRule 接口的 choose 方 法来决定选择哪一个服务器对象。 如果想自定义负载均衡规定, 可以编写一个 IRule 接口的 实现类
public class MyRule implements IRule {
ILoadBalancer lb;
public MyRule() {
}
public MyRule(ILoadBalancer lb) {
this.lb = lb;
}
public Server choose(Object key) {
// 获取全部的服务器
List<Server> servers = lb.getAllServers();
// 只返回第一个 Server 对象
return servers.get(0);
}
}
Ping机制
在负载均衡器中, 提供了 Ping 的机制, 每隔一段时间, 会去 Ping 服务器, 判断服务器 是否存活。 该工作由 IPing 接口的实现类负责 。
//自定义Ping
public class MyPing implements IPing {
public boolean isAlive(Server server) {
System.out.println("自定义Ping类,服务器信息:" + server.getHostPort());
return true;
}
}
springcloud与ribbon
springcloud 集成了ribbon ,结合eureka ,ribbon可自动从eureka server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。
RestTemplate 负载均衡原理
@LoadBalanced 注解
RestTemplate 本身不具有负载均 衡的功能, 该类也与 Spring Cloud 没有关系, 但为何加入@LoadBalanced 注解后, 一个 RestTemplate 实例就具有负载均衡的功能呢? 实际上这要得益于 RestTemplate 的拦截器 功能。
在 Spring Cloud 中, 使用@LoadBalanced 修饰的 RestTemplate, 在 Spring 容器启动 时, 会为这些被修饰过的 RestTemplate 添加拦截器, 拦截器中使用了 LoadBalancerClient 来处理请求, LoadBalancerClient 本来就是 Spring 封装的负载均衡客户端, 通过这样间接处理, 使得 RestTemplate 就拥有了负载均衡的功能 。
Feign---Rest客户端
feign是一个声明web服务客户端,这便得编写web服务客户端更容易,使用Feign 创建一个接口并对它进行注解,它具有可插拔的注解支持包括Feign注解与JAX-RS注解,Feign还支持可插拔的编码器与解码器,Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign 。
调用端-invoker
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
/**************************/
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class InvokerApplication {
public static void main(String[] args) {
SpringApplication.run(InvokerApplication.class, args);
}
}
/*****controller*************************/
@Autowired
private PersonClient personClient;
@RequestMapping(value = "/invokeHello", method = RequestMethod.GET)
public String invokeHello() {
return personClient.hello();
}
//声明一个接口
@FeignClient("spring-feign-provider") //声明调用的服务名称
public interface PersonClient {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
String hello();
}
服务提供者--provider
@SpringBootApplication
@EnableEurekaClient
public class ProviderApplication {
public static void main(String[] args) {
// 读取控制台输入的端口,避免端口冲突
Scanner scan = new Scanner(System.in);
String port = scan.nextLine();
new SpringApplicationBuilder(ProviderApplication.class).properties(
"server.port=" + port).run(args);
}
}
@RestController
public class FirstController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "Hello World";
}
}
spring cloud feign 客户端负载均衡 是通过spring cloud ribbon实现的。
Hystrix 断路器
(1)在微服务中,单个服务为了高可用性防止单点故障通常会集群部署。由于网路或其他原因服务变得不可用时服务调用者会出现长等待的线程阻塞,此时会有大量的其他请求涌入,servlet容器线程资源会被消耗完毕。服务之间有依赖性,于是会出现故障传播引起雪崩效应,断路器就是为了解决这样的问题。
(2)在服务与用户之间通过api进行交互,用户调用api消费服务,当某个服务不可用(有一个时间阈值)时断路器就会打开,同时为这个服务的调用者返回一个固定的值。简单来说就是为服务的瘫痪做一个保险,防止用户得不到服务返回结果而阻塞等待进而影响其他服务和用户。
(3)当hystrix检测到服务不可用时,会自动断开不可用服务,具体的就是每次消费者调用方法都不再去访问服务提供者,而是直接返回一个设定好的固定值。当服务再次可用时在打开服务,同时允许消费者调用方法再去访问服务提供者。如果hystrix打开服务如何知道服务可用呢?hystrix允许额外发送一些请求到服务提供者检测服务是否可用。
3种情况触发回退--fallback:
断路器被打开。
线程池、 队列、 信号量满载。
实际执行命令失败。
public static void main(String[] args) {
// 断路器被强制打开
ConfigurationManager.getConfigInstance().setProperty(
"hystrix.command.default.circuitBreaker.forceOpen", "true");
FallbackCommand c = new FallbackCommand();
c.execute();
// 创建第二个命令,断路器关闭
ConfigurationManager.getConfigInstance().setProperty(
"hystrix.command.default.circuitBreaker.forceOpen", "false");
FallbackCommand c2 = new FallbackCommand();
c2.execute();
}
断路器关闭
断路器打开后,在一段时间,命令不在执行(一直触发回退),这段时间我们称为“休眠期”,休眠期默认为5秒。
隔离机制
命令的真正执行,除了断路器要关闭外,还要再过一关;执行命令的线程池或信号量是否满载。如果满载,命令就不会执行,而是直接触发回退。隔离策略有2种:
thread:默认值,有线程池决定命令的执行,线程池默认为10
semaphore:由信号量来决定命令的执行。
在spring cloud中使用Hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
//服务调用者加入@EnableCircuitBreaker 注解
@EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
/*******************************/
@HystrixCommand(fallbackMethod = "getPersonFallback")
public Person getPerson(Integer id) {
// 使用RestTemplate调用Eureka服务
Person p = restTemplate.getForObject(
"http://spring-hystrix-provider/person/{personId}",
Person.class, id);
return p;
}
/**
* 回退方法,返回一个默认的Person
*/
public Person getPersonFallback(Integer id) {
Person p = new Person();
p.setId(0);
p.setName("Crazyit");
p.setAge(-1);
p.setMessage("request error");
return p;
}
在 Spring Cloud 中使用@HystrixCommand 来声明一个命令,命令的相关配置也可以在
该注解中进行
被@HystrixCommand 修饰的方法, Hystrix(javanica)会使用 AspectJ
对其进行代理, Spring 会将相关的类转换为 Bean 放到容器中,在 Spring Cloud 中,我们无
须过多关心 Hystrix 的命令管理 。
Feign 与 Hystrix 结合
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-feign</artifactId>
</dependency
在 application.yml 中打开 Feign 的 Hystrix 开关 ,请见以下配置 :
feign :
hystrix :
enabled : true
hystrix:
command:
HelloClient#hello():
execution:
isolation:
thread:
timeoutInMilliseconds: 500
circuitBreaker:
requestVolumeThreshold: 3
@FeignClient(name = "spring-hystrix-provider", fallback = HelloClientFallback.class)
public interface HelloClient {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
public String hello();
@Component
static class HelloClientFallback implements HelloClient {
public String hello() {
return "error hello";
}
}
}
Hystrix监控
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-actuator</artifactid>
<version>l.5.3.RELEASE</version>
</dependency>
@SpringBootApplication
@EnableHystrixDashboard
public class MyApplication {
public static void main(String[] args) {
// 设置启动的服务器端口
new SpringApplicationBuilder(MyApplication.class).properties(
"server.port=8082").run(args);
}
}
使用了@EnableHystrixDashboard 注解开启 Hystrix 控制台,启动的端口为 8082。完成 后,启动整个集群,最后再启动监控项目,在浏览器输入以下地址 http://localhost:8082/hystrix, 在文本框中输入需要监控的地址 , 本例需要监控的地址是 http://localhost:9000/ hystr以 .stream。单击监控按钮,即可。
Zuul--API网关服务
@EnableZuulProxy
路由配置
zuul:
routes :
routeTest :
path : /routeTest/163
url :http://www.163.com
以上的配置访 问 http 😕/localhost:8080/reuteTest/ 1 63 ,将会跳转到 163 网站。为了配置简 便,可 以省略 path , 默认情况下使用 routeld 作为 path,以下的配置省略了 path 配置:
zuul :
routes :
route163 :
url : http ://www.163.com
跳转路由
zuul:
routes :
helloRoute:
path: /test/**
url: forward:/source/hello
当外部访 问/test 地址时,将会自动跳转型J/source/hello 地址 。 打开浏览器,输入 http:// localhost:8080/test/anugs,可以看到浏览器会返回字符串 hello angus,可见源服务被调用 。 跳转路由实现较为简单 , 实际上是调用了 RequestDispatcher 的 forward 方法进行跳转。
ribbon路由
zuul:
routes:
sale:
path: /sale/**
serviceid : zuul-sale-service
与简单路由类似, serviceId 也可以被省略。当省略时,将会使用 routeld 作为 serviceld , 下面的配置片断,效果等同于上面的配置:
zuul:
routes:
zuul-sale-service :
path : /sale/**
自由配置路由规则
忽略路由
zuul.ignoredServices
路由端点
1.网关项目中引入了 Spring B oot Actuator。
- 项目中使用了@EnableZuulProxy 注解。
Zuul 与 Hystrix
spring cloud stream
绑定器:binder
您可以将@EnableBinding注释添加到应用程序,以便立即连接到消息代理,并且可以将@StreamListener添加到方法中,以使其接收流处理的事件
Spring Cloud Stream 内置了 3 个接口: Sink、 Source 与 Processor ,
//消费者
@EnableBinding(Sink.class)
//绑定消息输入通道,Sink.class为Spring Cloud Stream自带的一个消息通道绑定接口,可以自行定义
public class SinkReceiver {
Logger logger = LoggerFactory.getLogger(SinkReceiver.class);
@StreamListener(Sink.INPUT) //Sink.INPUT为一个静态String变量,值为"input",此处监听消息通道"input",并打印收到的信息
public void receive(String payload){
logger.info("Receive收到:"+payload);
}
}
//生产者
@EnableBinding(Source.class)
public class SinkSender {
@Bean
@InboundChannelAdapter(value=Source.OUTPUT,poller = @Poller(fixedDelay = "2000"))
public MessageSource<String> timerMessageSource(){
return ()->new GenericMessage<String>(new Date().toString());
}
}
编辑application.properties,添加以下属性:
spring.cloud.stream.bindings.output.destination=input
spring cloud bus --消息总线
如何实现对配置信息的实时更新?
在实现配置属性刷新时,我们在修改git仓库上的配置信息之后,往总线上的某个节点发送一个请求/bus/refresh来触发总线上的所有节点进行配置刷新。
消息代理中间件 将消息路由到一个或多个目的地。
微服务跟踪
Elasticsearch : 是一个分布式数据仓库,提供了 RESTful 服务,可用于数据存储 、分析 。
Logstash:主要用于数据收集、转换,可将数据保存到指定的数据仓库中。
Kibana:是可视化的数据管理平台,主要用于操作 Elasticsearch 的数据,它提供了
多种图表展示数据,支持动态报表 。
ELK