Spring Cloud微服务的服务注册搭建与CAP分布式思想

目录

微服务概述

CAP理论

微服务框架

SpringCloud

eureka

Eureka的角色

服务注册者和服务注册中心的逻辑关系

eureka报警

自我保护机制

实战

EUREKA高可用

Ribbon组件+restTemplate=feign

RestTemplate方法的解析

负载均衡策略

Hystrix

搭建一个ribbon+hystrix的工程

Feign

Spring Cloud Config 

ZUUL


微服务概述

微体现小(功能小);可以将系统中能够独立运行的各种功能拆分开来,各自围绕一个主题工程实现解耦和独立调用;

CAP理论

分布式技术中一个基础理论(BASE)

C:consistency,一致性(更新操作成功并返回客户端完成后,分布式的所有节点在同一时间的数据完全一致)

A:avalibility,可用性(系统技术的响应速度快,在P存在的情况下,可用性,与数据一致性要求是相反的)

P:partition,分区容错性(由于各种故障,各种问题,导致分布式系统本来是一个整体的通信,整体通信由于故障问题,导致分区出现.)

 

在任何一个分布式技术中,CAP理论中的三个元素,最多只能存在2个:CA,CP,AP。原因:

由于网络问题,环境问题,人为因素,P是很难保证的,所以我们可以认为 CAP 的 P 总是成立。

假如杭州,广州两地服务器要保持一致,那么 广州在写操作时,锁定杭州的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,杭州不能读写,没有可用性。如果保证 杭州 的可用性,那么势必不能锁定杭州,所以一致性不成立。所以C和A不可能同时存在。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。

选择权衡:

AP:大多数互联网应用来说(如网易门户),放弃数据一致性

CA:模型网络故障时完全不可用,银行

CP:模型具备部分可用性,放弃可用性

redis:不能完美支持数据一致性(牺牲了一致性,满足可用性)

zookeeper:强调数据一致性,性能慢

微服务框架

一旦系统切分,切分,拆分,形成非常庞大的功能个体的集群,对于这样一套分布式的集群系统,急需一个能够管理,协调,优化所有集群微服务关系的架构技术--微服务框架.

springcloud

dubbo

一种轻量级的微服务框架

一种重量级的框架技术

中小型企业常用的微服务框架

大型企业开发大型分布式微服务系统常用的架构;

持RESTful,http协议,可用性高,

除了支持http协议,rpc等其他通信协议,

一致性差(可用性高dubbo中可以使用eureka的服务治理,一旦强调数据的一致性,服务治理组件替换成zookeeper

所有接口,都已经成为组件维护

非常多的接口需要开发人员

SpringCloud

spring家族的一员,可以开发实现一个轻量级的微服务集群(开发成本低),提供的组件功能非常丰富,可以实现注册,发现,熔断等等诸多功能的基于springboot的微服务框架工具;

springCloud的微服务框架具有很多的功能组件:

1 服务治理:eureka 所有工程都可以在eureak中注册自己的服务名称,如果名称一致,将会被eureka作为同一个服务来使用;

2 负载均衡调用组件:ribbon, 前端的客户端的组件

3 熔断器:Hystrix, 当服务调用出现任何异常或者问题时,可以利用熔断的逻辑完成错误的解决;类似代码中的try catch

4 接口客户端组件: feign 底层依赖ribbon+template实现的调用。看不到实际调用的方法,利用接口,注解

5 分布式配置:config,分布式配置组件;

6 网关组件:zuul实现网关路由,监听,对当前的需要的服务进行网关治理;

eureka

eureka是springcloud中的核心组件spring netflix的二次封装,没有它就无法形成微服务的框架;有服务治理中心,有服务注册客户端,可以提供服务的注册,监听,续约等逻辑;

Eureka的角色

服务端称为注册中心,管理所有在注册中心注册了服务名称的eureka客户端
客户端服务的真正提供者,在注册中心注册服务,提交节点信息
外部访问者调用服务,访问注册中心,获取服务提供者的list列表,并且间隔一段时间,从注册中心更新列表,调用端实现负载均衡的访问这个服务的提供集群;

如图所示:eureka的客户端有3个他们提供一样的功能,在erreka注册中心注册在同一个服务上servive1,那么客户端不需要知道我的微服务是怎么搭建的,只需要访问注册中心。就可以得到具体信息内容,当微服务客户端增加时,不需要改变以前的,主需要注册到erreka注册中心,那么我的外界访问者自己可以读到更新的数据

服务注册者和服务注册中心的逻辑关系

注册中心启动,监听接口localhost:8090/eureka,接收服务注册者发送的消息

服务提供者(eureka的客户端):通过接口发送消息/心跳/续约到注册中心

每30秒,服务提供者都会进行续约的逻辑,对注册中心发送心跳消息,给注册中心告知存活状态

90秒之内,服务注册中心都没有接收到注册者的续约发送,

判断没续约状态持续再60秒之后,将会剔除,判断断开了;

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 client断开连接,程序关闭,宕机等问题,导致服务治理中心无法发现或连接通信服务提供者时,可连接的服务提供者占用所有服务提供者的85%(默认值)以下时,出现以上预警,并且拒绝剔除;

自我保护机制

微服务注册中心的自我保护机制,就是防止意外的大范围宕机造成的服务剔除,会影响整体集群的使用(又不是真的宕机,网络波动);同时心跳检测连接失败的15%以上,会造成自我保护机制的开启(测试环境非常容易达到);剔除的逻辑就不执行,等待恢复;

实战:

1.搭建一个服务注册中心

1.1所需要依赖:pom.xml

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.9.RELEASE</version>
	<relativePath/> <!-- lookup parent from repository -->
</parent>

<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>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
    <dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka-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>

 1.2 配置文件:application.properties

server.port=8090

eureka.instance.hostname=localhost //当前中心访问的域名,如果想要配置别的,必须通过hosts文件完成IP地址映射

eureka.client.registerWithEureka=false //当前的注册中心默认情况会在自己启动的中心注册一个自己的服务

eureka.client.fetchRegistry=false  //抓取注册信息

eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka/ //匹配eureka.instance.hostname的值的中心访问地址,

 1.3 编写启动类,查看注册中心内容。注解:@EnableEurekaServer

@SpringBootApplication
@EnableEurekaServer
public class StarterEurekaCenter {
	public static void main(String[] args) {
         SpringApplication.run(StarterEurekaCenter.class, args);
    }
}

浏览器访问测试:localhost:8090

2 eureka客户端(服务调用的服务提供者)

pom文件:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.9.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>

<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>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
    <dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</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>

2.1 application.properites

server.port=8091   //eureka客户端的端口
server.context-path=/
spring.application.name=service-hi   
//eureka中心注册一个service-hi的服务
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka  //指向注册中心,与eureka center一致

2.2 编写启动类(注册服务,利用注解)  注解:@EnableEurekaClient

@SpringBootApplication
@EnableEurekaClient
public class StarterEurekaClient {
	public static void main(String[] args) {
		SpringApplication.run(StarterEurekaClient.class, args);
	}
}

3.编写一个测试controller标识一下当前工程的返回内容端口8091/8092/8093

@RestController
public class HiController {
	//注入一个当前端口属性值
	@Value("${server.port}")
	private String port;
	
	@RequestMapping("hi")
	public String sayHi(String name){
		return "hello "+name+" eureka,I am from "+port;
	}
}

我们发现一个8091端口的进程注册在service-hi的服务,当访问页面时可以返回我们端口8091

此时来进行高可用的测试,我们把eureka客户端这个工程复制三份,把每一个客户端工程的配置文件端口分别变成8092,8093,并且把启动类名称修改一下,如果启动类名称一样就不能启动了

我们先启动注册中心,在启动三个eureka客户端工程,

浏览器访问测试:localhost:8090,我们发现在服务名称为service-hi 的一栏Status已经把我们的8091,8092,8093三个客户端全部加进来,

我们访问localhost:8091/hi?name=小李,页面显示hello 小李 eureka,I am from 8091

我们再来访问localhost:8092/hi?name=小李,页面显示hello 小李 eureka,I am from 8092

我们发现这并不是我们想要的效果,我们不应该直接访问具体端口(因为实际开发中有各种各样的服务,每个服务对应各种功能的集群,我们不可能知道每个功能的访问地址),而是我们访问eureka注册中心,eureka注册中心去访问eureka客户端工程并给我们返回结果,所以我们看接下来的Ribbon

EUREKA高可用

基本原理:多个eureka服务之间相互注册,当服务提供者注册在任意一个注册中心时,服务列表信息会同步.

service1

server.port=8089
spring.application.name=server1
eureka.instance.hostname=localhost
eureka.client.registerWithEureka=true  
eureka.client.fetchRegistry=true 
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka/,http://localhost:8089/eureka/

service2:

server.port=8090
spring.application.name=server2
eureka.instance.hostname=localhost
eureka.client.registerWithEureka=true  
eureka.client.fetchRegistry=true 
eureka.client.serviceUrl.defaultZone=http://localhost:8089/eureka/,http://localhost:8090/eureka/

service1和service2相互注册到对方的服务列表中:在各自的配置文件中,分别指向对方的defaultZone地址,两个服务列表完全一样,既可以抓取就可以注册到注册中心,所以他们及时服务端又是客户端

这样即使其中一个宕机,我所有的服务列表又会在另一个服务上注册

Ribbon组件+restTemplate=feign

ribbon实现通过springcloud内部服务调用,从eureka注册中心获取服务list,完成负载均衡的访问(默认是轮询),从服务提供者调用工程代码/数据,就是为了解决微服务集群中某个独立的服务无法单独完成一个任务,需要别的服务帮助的情况;

如图所示:外界访问者调用service-ribbon服务,他自己完成不了,就调用注册中心的service-hi服务来帮他完成,rureka客户端ribbon除了可以在中策中心注册,他还有一个抓取的功能,把service-hi的服务列表抓取过来,ribbon客户端内部还有一个可以实现负载均衡的restTemplate,从而可以实现访问service-hi,来负载均衡的访问eureka8091,8092的两个客户端

pom文件

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.9.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
</properties>
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>

	<!--Eureka相关依赖 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</artifactId>
	</dependency>

	<!--Ribbon相关依赖 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-ribbon</artifactId>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<!--注意这个位置,必须是springboot支持的版本。否则会报出依赖会有错误,但是编译没有问题 运行出 java.net.UnknownHostException: 的错 -->
			<version>Dalston.SR4</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

配置文件

server.port=8094
eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka/
spring.application.name=service-ribbon

启动类:创建这个RestTemplate,指明它的负载逻辑(Balanced),完成负载均衡的访问 

@SpringBootApplication
@EnableEurekaClient
public class StarterRibbon {
	public static void main(String[] args) {
		SpringApplication.run(StarterRibbon.class, args);
	}
	//生成一个restTemplate对象,实现服务的代码调用
	@Bean
	@LoadBalanced//表示当前restTemplate实现的默认负载均衡逻辑roundBin轮询
	public RestTemplate initRest(){
		return new RestTemplate();
	}
	//生成一个随机策略
	@Bean
	public IRule rule(){
		//权重,轮询,随机等策略的实现对象
		//WeightedResponseTimeRule
		return new RandomRule();
	}
}

Controller 实现服务的调用,调用client01,client02工程的数据,需要实现调用的对象注入,RestTemplate

@RestController
public class HiController {
	//测试案例,访问ribbon工程,调用template对象负载均衡访问8091/8092实现服务的内部调用
	@Autowired
	private HiService hiService;
	@RequestMapping("hi")
	public String sayHi(String name){
		return "RIBBON:"+hiService.sayHi(name);
	}
}

Service:

@Service
public class HiService {
	//注入restTemplate完成负载均衡的访问service-hi
	@Autowired
	private RestTemplate template;
	public String sayHi(String name) {
		//做一个template的get方法调用
		//url:发起的请求所访问的服务,并且携带访问地址和参数
		//responseType:restTemplate默认底层会做序列化,直接可以接收对方返回的类对象数据
		String result = template.getForObject("http://service-hi/hi?name="+name, String.class);	
		return result;
	}
}

此时开始启动注册中心,client01,client02,ribbon分别启动

我们访问localhost:8094/hi?name=小王,页面显示——RIBBON:hello 小王 eureka,I am from 8091,但我们刷新页面时我们会访问8092,此时8091和8092这两个页面进行轮训,可以发现是template在帮我们把service-hi上的服务列表抓取过来,进行显示。

当我们觉得client01,client02不够用的时候我们可以添加client03,直接加入集群,访问的负载均衡可以直接访问;动态添加,其他的结构任何位置都没有发生任何变动;

我们把client01,复制一份,修改配置文件端口8093,启动类名称,启动这个工程

我们访问localhost:8094/hi?name=小王,会发现8091,8092,8093三个端口开始轮训

RestTemplate方法的解析

GET请求:

getForEntity;

getForEntity(URI url,Class responseType); 

String result = template.getForObject("http://service-hi/hi?name="+name,String.class);

getForEntity(String url,Class responseType,Object…urlVariables);

template.getForObject("http://service-hi/hi?name={1}&age={2}&gender={3}", String.class, name,"18","male");

getForEntity(String url,Class responseType,Map urlVariables)

Map<String,Object> param=new HashMap<String,Object>();

param.put("haha", name);

template.getForObject("http://service-hi/hi?name={haha}", responseType, param);

参数意义:

URI url:JAVA类中的URI对象,可以是一个普通的url地址字符串;

responseType:响应体封装的数据类型

Object…urlVariables:底层是个数组,会将所有的参数拼接成一个多个元素的数组;和url地址中的参数位置的代替数字有关;

Map urlVariables:map对象,key就是url中的代替符号;

 

getForObject同样存在三个重载方法,参数意义和getForEntity一模一样;

区别:getForEntity返回的是响应体的数据,一些响应头,

          getForObject返回的是封装了响应体的所有数据;

ResponseEntity<String> entity = template.getForEntity("http://service-hi/hi?name="+name, String.class);

String result =entity.getBody();   //以上这两行代码,=getForObject

POST请求

postForEntity三个重载方法

postForObject三个重载方法;关系和getForObject与getForEntity一样的;

 

postForEntity(String url,Object request,Class responseType,Map urlVariables)

Object request:如果是普通的数据类型(user)将会作为请求体的内容进行发送请求;

                           如果是HttpEntity 类型的requet就是作为一个完整的request对象,封装想要的各种内容(请求头等信息);

template.postForEntity(url, request, responseType);

HttpEntity entity=new HttpEntity<>(headers);  //entity既有请求体的内容,又有请求对象,请求头等信息,如果关心除了请求体以外的信息,可以用entity

负载均衡策略

原理:ribbon客户端在使用restTemplate对象之前,进行的发送请求的拦截;看看他是用哪种负载均衡策略

轮询:遍历

权重策略:WeightedResponseTimeRule,每次访问实例时,记录响应时间,根据不同的实例的响应时间内部计算权重逻辑;,响应时间越长(处理能力越低) 访问次数越少

随机策略 radomRule:在启动类中,添加IRule的对象返回,返回一个randomRule的对象;

//生成一个随机策略
@Bean
public IRule rule(){
   return new RandomRule();
}

Hystrix

熔断器,容错管理工具,当服务集群中出现访问服务的异常(或者错误,或者http请求的断开),可以利用熔断的机制完成各种方法的封装,调用方法,实现错误的管理逻辑;

熔断/断熔:绝不允许集群中局部的问题导致整体的瘫痪;一旦局部出现问题,微服务集群将会抛弃/牺牲这个部分;(小区停电)

服务降级:在局部出现问题后,采用熔断的处理逻辑,必定导致服务的依赖/使用降级;采用次级处理响应的措施;

               想法海飞丝洗发水,没有,买个飘柔的也行

搭建一个ribbon+hystrix的工程

pom文件:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.9.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
</properties>
<dependencies>	
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-hystrix</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>

	<!--Eureka相关依赖 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</artifactId>
	</dependency>

	<!--Ribbon相关依赖 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-ribbon</artifactId>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<!--注意这个位置,必须是springboot支持的版本。否则会报出依赖会有错误,但是编译没有问题 运行出 java.net.UnknownHostException: 
				的错 -->
			<version>Dalston.SR4</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

配置文件:

eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka/
server.port=8096
spring.application.name=service-ribbon-hystrix

启动类:

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class StarterRHClient {
	public static void main(String[] args) {
		SpringApplication.run(StarterRHClient.class, args);
	}
	@Bean
	@LoadBalanced
	public RestTemplate getRest(){
		return new RestTemplate();
	}
}

controller:

@RestController
public class HiController {
	@Autowired
	private HiService hiService;
	@RequestMapping("hi")
	public String sayHi(String name){
		return "RH:"+hiService.sayHi(name);
	}
}

service:

@Service
public class HiService {
	@Autowired
	private RestTemplate template;
	//引入HysTrix的熔断降级服务
	//服务降级,当前调用的方法中存在调用后续服务的逻辑,一旦调用失败,可以通过fallback参数指定调用其他可用的方法,方法名称叫做error,error方法除了名称与sayHi不一样其他结构一模一样,默认情况下超时2秒就算连接失败
	@HystrixCommand(fallbackMethod="error")
	public String sayHi(String name) {
		String result = template.getForObject("http://service-hi/hi?name="+name, String.class);
		return result;
	}
	public String error(String name){
		//return "error happened,sorry "+name;
		String result = template.getForObject("http://service-hi/hi?name="+name, String.class);
		return result;
	}
}

 

96调用91,92,92断了,就会出现error的方法

Feign

负载均衡调用服务的客户端组件,声明式(注解)客户端。使得调用更简单(无需关心底层调用的api getForEntity getForObject post..);底层基于ribbon+restTemplate(内部整合了容错的断容器Hystrix)

pom

<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.9.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-feign</artifactId>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<!--注意这个位置,必须是springboot支持的版本。否则会报出依赖会有错误,但是编译没有问题
			运行出 java.net.UnknownHostException: 的错-->
			<version>Dalston.SR4</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

 

配置文件:

eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka/
server.port=8095
spring.application.name=service-feign
 

启动类:

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class StarterFeign {
	public static void main(String[] args) {
		SpringApplication.run(StarterFeign.class, args);
	}
}

Controller:

@RestController
public class HiController {
	//不是编写实体类的service,需要接口实现,底层代理完成,方法的调用
	@Autowired
	private HiService hiService;
	@RequestMapping("hi")
	public String sayHi(String name){
		return "FEIGN:"+hiService.sayHi(name);
	}
}


 Service:

//feign客户端注解,表明当前service调用的服务名称,定义了访问的服务名称后,当前接口的所有抽象方法,都会访问这个服务
@FeignClient("service-hi")
public interface HiService {
	//不需要编写restTemplate的方法访问service-hi,springmvc的注解帮助实现底层的调用逻辑
	@RequestMapping(value="hi",method=RequestMethod.GET)
	String sayHi(@RequestParam(value="name")String name);
}

Spring Cloud Config 

分布式配置中心

在大量的集群中,各种工程都需要属性的配置properties文件

一旦出现属性的共享,例如redis配置,es配置,数据库配置;各自工程维护起来比较麻烦,而且更新不及时;

微服务框架提供一个共享的分布式配置中心,所有的服务注册者都可以是分布式配置中心的客户端,通过中心管理的github上的配置文件,实现共享配置;

github: 开源的资源,代码,框架,技术分享的网站

和git有个相同的特点,就是资源可以实现回滚和版本控制;

每个不同的用户可以拥有免费的和付费的github资源,使用线下的git向github传递数据;

搭建服务器端:

pom文件:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.9.RELEASE</version>
	<relativePath />
	<!-- lookup parent from repository -->
</parent>
<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>Edgware.RELEASE</spring-cloud.version>
</properties>
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-config-server</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>

applicatin.properties

spring.application.name=config-server
server.port=8098

spring.cloud.config.server.git.uri=  github仓库地址(共享资源)

 //github仓库地址可以由多级的路径文件存在,如果仓库下所有目录都要就可以不用这个配置
spring.cloud.config.server.git.searchPaths=/project 
spring.cloud.config.label=master  //主分支还是分分支

启动类:

@SpringBootApplication
@EnableConfigServer
public class StarterConfig {
	public static void main(String[] args) {
		SpringApplication.run(StarterConfig.class, args);
	}
}

在仓库里有一个:info-test.properties 的文件。内容是name=haha,age=19其中info--application应用名称。test--profile文件名称

那么我们访问的路径是localhost:8000/{application}/{profile}——localhost:8098/info/test

这是页面可以访问到我们在仓存储文件内容。

2 配置的客户端工程(读取中心工程的共享资源)

pom文件:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.9.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>

<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>Edgware.RELEASE</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-config</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>

配置文件-bootstrap.properties,注意名称

spring.application.name=info //读取配置中心文件文件的前缀application

spring.cloud.config.profile=test //读取前缀profile application-profile.properties

spring.cloud.config.label=master

spring.cloud.config.uri=http://localhost:8098  //配置中心的来源

server.port=8099

测试controller:

@RestController
@SpringBootApplication
public class StarterConfigClient {
	@Value("${name}")
	private String name;
	@Value("${age}")
	private Integer age;
	
	public static void main(String[] args) {
		SpringApplication.run(StarterConfigClient.class, args);
	}
	
	@RequestMapping("age")
	public String age(){
		return name+"/"+age;
	}
}

 测试访问:localhost:8099/age,我们可以发现我们可以在客户端读到配置中心的数据

ZUUL

微服务集群提供了网关,监听等功能的微服务组件;

访问的时候根据url路径,过滤网关拦截的信息,访问指向的服务

搭建ZUUL工程:ZUUL-client

pom文件:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.5.9.RELEASE</version>
	<relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
</properties>

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-zuul</artifactId>
	</dependency>
</dependencies>
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Dalston.SR4</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

properties

eureka.client.serviceUrl.defaultZone=http://localhost:8090/eureka/
server.port=8097
spring.application.name=service-zuul


zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.serviceId=SERVICE-FEIGN

zuul.routes.product.path=/product/**
zuul.routes.product.serviceId=product

访问并不是直接访问ribbon客户端,SERVICE-FEIGN客户端,而是利用url中域名+端口访问zuul工程,

启动类:

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class StarterZuul {
	
	public static void main(String[] args) {
		SpringApplication.run(StarterZuul.class, args);
	}
}

测试:访问localhost:8097/api-b/hi?name=小七   访问的是zuul  指向服务SERVICE-FEIGN     http://service-feign/hi?name=小七

进行高可用:复制ZUUL-client工程,修改配置文件端口server.port=8097,改成8002,搭建zuul网关集群

此时在进行访问:localhost:8002/api-b/hi?name=小七  ,name8002和8097可以进行替换

此时通过nginx转发进行轮询两个网关地址

#网关服务器
upstream zuul{
    server 127.0.0.1:8097;
    server 127.0.0.1:8002;
}
server {
    listen       80;
    server_name  zuul.lj.com;
                
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    location / {
           proxy_pass http://zuul;
           proxy_connect_timeout 600;
           proxy_read_timeout 600;
    }
}

 浏览器访问 zuul.lj.com ,将会监听80端口,同时转发到内部虚拟http://zuul地址,找到负载均衡轮询访问的地址8002,8097两个地址

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值