服务启动时向注册中心注册,注册中心为了保证高可用性使用集群方式,客户端想要访问任何一个服务可以从注册中心拿取,也可以由代理转发请求到可用服务器。
服务注册和发现:
- 客户端发现:eureka就是,就是客户端通过注册中心按照负载均衡机制(轮询、hash等)从注册中心获取到ip,然后访问。
- 服务端发现:典型的nginx、zookeeper、kuberneters,客户端通过主机的ip和端口向代理发送请求,代理将请求转发到任何一个可用的服务上;注册中心和后台注册服务是对客户端不可见得。
一、注册中心服务端
@SpringBootApplication
//启动eureka注册中心服务
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
#服务器名称
spring:
application:
name: product
#服务器端口
#server:
# port: 8761
#euraka客户端设置
eureka:
client:
#是否注册到注册中心
# register-with-eureka: false
#当前客户端注册到eureka服务中心地址,集群互相注册信息传递,保证高可用
service-url:
defaultZone: http://localhost:8762/eureka/,http://localhost:8763/eureka/
server:
enable-self-preservation: false
# fetch-registry: false
二、客户端
@SpringBootApplication
@EnableDiscoveryClient
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
spring:
application:
name: order
eureka:
client:
# 当前客户端注册到eureka服务中心地址
service-url:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/,http://localhost:8763/eureka/
# 客户端网址开头部分
# instance:
# hostname: localhost
server:
port: 8088
三、客户端获取服务端信息
客户端通过restTemplate向eureka拉取所有的服务,然后过滤出可用服务,最后默认按照轮询的负载均衡策略获取一个主机地址和端口进行访问。
1、方式一:直接使用直接注入负载均衡和restTemplate
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* 功能:
* 创建时间:2020/10/29 20:39
*/
@RestController
@Slf4j
public class orderServerController {
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/msg1")
public String msgByBlance() {
ServiceInstance serviceInstance = loadBalancerClient.choose("product");
String url =String.format("http://%s:%s%s",serviceInstance.getHost(),serviceInstance.getPort(),"/msg");
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(url, String.class);
log.info("eureka请求的服务端地址为:{} 出现结果为:{},",url,result);
return result;
}
}
2、方式二、通过配置一个含有负载均衡的restTemplate
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
/**
* 功能:
* 创建时间:2020/10/29 20:41
*/
@Component
public class RestTemplateConfig {
@Bean
@LoadBalanced //通过RibbonLoadBalancerClient获取url和端口
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* 功能:
* 创建时间:2020/10/29 20:39
*/
@RestController
@Slf4j
public class orderServerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/msg")
public String msg() {
String url = "http://product/msg";
String result = restTemplate.getForObject(url, String.class);
log.info("eureka请求的服务端地址为:{} 出现结果为:{},",url,result);
return result;
}
}
负载均衡策略:
public ServiceInstance choose(String serviceId) {
return this.choose(serviceId, (Object)null);
}
public ServiceInstance choose(String serviceId, Object hint) {
Server server = this.getServer(this.getLoadBalancer(serviceId), hint);
return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
}
//如果没有配置负载均衡策略,就使用默认轮询
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");
}
//默认的负载均衡策略就是轮询
private final static IRule DEFAULT_RULE = new RoundRobinRule();
protected IRule rule = DEFAULT_RULE;
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}