注册中心(eureka)
Eureka是Netflix开源的服务发现组件,本身是基于Rest的服务,它包含服务端和客户端两部分;在SpringCloud中将它集成在其中,从而实现了微服务的发现与注册;
Eureka Server
- 服务端-没有存储,内存保持,每服务实例需要发送心跳去续约
- 客户端-在内存中缓存着eureka的注册信息,因此不必每请求到eureka查找服务
- eureka之间会做注册服务同步,从而保证状态一致,客户端只需访问一个eureka
Service Provider
- 会向Eureka Server做Register(服务注册)、Renew(服务续约)、Cancel(服务下线)等操作
Service Consumer
- 会向Eureka Server获取注册服务列表,并消费服务
简单实例
服务端(application.properties):
server.port=7070
#对该应用另起别名
spring.application.name=my-dinner-register
#表示是否将自己注册在EurekaServer上,默认为true。由于当前应用就是EurekaServer,所以置为false
eureka.client.register-with-eureka=false
#表示表示是否从EurekaServer获取注册信息,默认为true。单节点不需要同步其他的EurekaServer节点的数据
eureka.client.fetch-registry=false
#设置服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除
eureka.instance.lease-expiration-duration-in-seconds=30
#设置replicas EurekaServer的地址
eureka.client.serviceUrl.defaultZone=http://192.168.1.118:7070/eureka
客户端(application.properties)
#对该应用另起别名-在注册中心显示的服务名称
spring.application.name=my-dinner-server
server.port=8081
#注册中心url,与服务端的配置保持一致
eureka.client.serviceUrl.defaultZone=http://my-dinner-register-master:7070/eureka/
#每隔这个时间会主动心跳一次,更新自己的状态
eureka.instance.lease-renewal-interval-in-seconds=10
HA
修改hosts文件:
192.168.1.118 my-dinner-register-master my-dinner-register-slave
master(application.properties):
server.port=7070
spring.application.name=my-dinner-register-master
spring.profiles.active=my-dinner-register-master
#指定主机名
eureka.instance.hostname=my-dinner-register-master
#设置服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除
eureka.instance.lease-expiration-duration-in-seconds=30
#设置replicas EurekaServer的地址,将自身注册到slave
eureka.client.serviceUrl.defaultZone=http://my-dinner-register-slave:7071/eureka
slave(application.properties):
server.port=7071
spring.application.name=my-dinner-register-slave
spring.profiles.active=my-dinner-register-slave
#指定主机名
eureka.instance.hostname=my-dinner-register-slave
#设置服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除
eureka.instance.lease-expiration-duration-in-seconds=30
#设置replicas EurekaServer的地址,将自身注册到master
eureka.client.serviceUrl.defaultZone=http://my-dinner-register-master:7070/eureka
SpringCloud-微服务的注册与发现Eureka
Eureka服务下线后快速感知配置
编程实战
依赖包
‘org.springframework.cloud:spring-cloud-starter-netflix-eureka-server’
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) throws Exception{
SpringApplication.run(EurekaServerApplication.class);
}
}
配置中心
配置中心分为两部分组成:客户端和服务端。
服务端是单独的服务,需要注册到注册中心中。
而客户端则是存在于各个其他服务中的。
配置中心的服务端既可以将配置文件保存在远程的git仓库中,也可以将这些配置文件保存在本地,因为平常开发用本地配置中心较多,此次主要讲本地配置中心的搭建。
config server配置(application.properties)
##对该应用另起别名-在注册中心显示的服务名称
spring.application.name=my-dinner-config
server.port=8888
eureka.client.serviceUrl.defaultZone=http://my-dinner-register-master:7070/eureka/
spring.profiles.active=native
spring.cloud.config.server.native.searchLocations=classpath:/properties/
客户端
application.properties
#配置中心拿配置
spring.application.name=my-dinner-server1
spring.cloud.config.profile=dev
启动时指定config server的地址
--spring.cloud.config.uri=http://192.168.1.118:8888/
或者通过注册中心获取config server的服务列表
#发现服务
spring.cloud.config.discovery.enabled=true
#注册中心的地址
eureka.client.serviceUrl.defaultZone=http://my-dinner-register-master:7070/eureka/
#config server的服务名称
spring.cloud.config.discovery.service-id=my-dinner-config
实战
依赖:
‘org.springframework.cloud:spring-cloud-config-server’
‘org.springframework.cloud:spring-cloud-starter-netflix-eureka-client’
@SpringBootApplication(exclude= DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
@EnableConfigServer
public class MyDinnerConfigApplication {
public static void main(String[] args) {
SpringApplication.run(MyDinnerConfigApplication.class, args);
}
}
负载均衡
负载均衡是微服务架构中必须使用的技术,通过负载均衡来实现系统的高可用、集群扩容等功能。负载均衡可通过硬件设备及软件来实现,硬件比如:F5、Array等,软件比如:LVS、Nginx等。
服务端负载均衡
用户请求到达负载均衡器(nginx), 负载均衡器根据负载均衡算法将请求转发到后端的服务实例。负载均衡算法有:轮询,随机,加权,地址hash等方法,负载均衡器维护了一份服务列表,根据负载均衡算法将请求转发到相应的服务实例,所以负载均衡器可以为服务集群分发请求,降低系统压力。
客户端负载均衡
客户端负载均衡与服务端负载均衡的区别在于客户端要维护一份服务列表,Ribbon从Eureka Server获取服务列表,Ribbon根据负载均衡算法 ==直接请求到具体的微服务,中间省去了负载均衡服务 ==
Feign
Feign是Netfix公司开源的轻量级rest客户端,使用Feign可以非常方便的实现Http客户端以及声明式服务的调用。
工作原理:
1 启动类添加@EnableFeignClients注解,Spring会扫描标记了 @FeignClient注解的接口,并生成此接口的代理对象;
2 @FeignClient(value=‘xxx’)指定了服务名称,Feign会从注册中心获取服务列表,并通过负载均衡算法进行服务调用;
3 在接口方法中使用注解@GetMapping 指定调用的URL,Feign将根据URL进行远程调用。
注意点:
SpringCloud对Feign进行了增强兼容了SpringMVC的注解 ,我们在使用SpringMVC的注解时需要注意
1: feignclient接口有参数必须在参数列表加@PathVariable(“XXX”)和@RequestParam(“XXX”);
2: feignclient返回值为复杂对象时,其类型必须有无参构造函数。
编程实战
1添加依赖
'org.springframework.cloud:spring‐cloud‐starter‐openfeign‘
2 定义FeignClient接口
@FeignClient(value =’service_manage_cms‘)
public interface CmsPageClient {
@GetMapping("/cms/page/get/{id}")
public CmsPage findById(@PathVariable("id") String id);
}
3 启动类添加@EnableFeignClients注解
thymeleaf
依赖文件:
‘org.springframework.boot:spring-boot-starter-thymeleaf’
配置:
#开发时关闭缓存,不然没法看到实时页面
spring.thymeleaf.cache=false
#前缀
spring.thymeleaf.prefix=file:./templates/tl/
#后缀
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
#编码
spring.thymeleaf.encoding=UTF-8
#类型
spring.thymeleaf.content-type=text/html
#json输出时间的格式
spring.jackson.date-format=yyyy-MM-dd
#静态资源的存储路径
spring.resources.static-locations=file:./static/
实例:
@GetMapping("/index")
public String index(ModelMap modelMap) {
JsonData data = goodsClassesFeignService.goodsClasses();
System.out.println("original:" + data.toString());
modelMap.addAttribute("data", data);
return "index";
}
public class JsonData implements Serializable {
private Integer code; // 状态码 0 表示成功,1表示处理中,-1表示失败
private Object data; // 数据
private String msg;// 描述
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎光临我的小餐</title>
<link rel="stylesheet" type="text/css" href="/css/main.css">
</head>
<body>
<div class="container">
<!--头部-->
<div id="header">
<nav id="headerNav">
<div class="header-wrap">
<div>
<a href="/">
<img src="/img/index.jpg"/>
</a>
</div>
<ul>
<li th:each="info,infoStat : ${data.data}">
<a href="/pages/coo/cooperation.html" target="_blank" th:text="${info.name}">菜系</a>
</li>
<li>
<a href="/pages/coo/cooperation.html" target="_blank">招商加盟</a>
</li>
</ul>
</div>
</nav>
</div>
</div>
</body>
</html>