springcloud:其实说白了就是一个springboot的增强版,但是自己在做的时候发现还是不好做啊,一定要导入springcloud和springboot的pom文件时两种相关的jar包版本要一致。这不自己把eureka集群和负载均衡做个记录以备回顾。
eureka介绍
eureka中的核心概念
Spring Cloud中负载均衡器概览
Spring Cloud中的负载均衡策略
其实eureka里面包含客户端和服务端,关系图如下
代码自己放在自己的gitee上了,同时我也把代码粘上来了(其实我觉得初级选手还是先敲,把结果展示出来再研究原理)
(一)代码如下然后开启时是先开启多个eureka在开启生产者最后开启利用feign调用的消费者:
eureka:
EurekaApplication:
package com.springcloud.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaServer //声明注册中心
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
eureka1 properties:
spring.application.name=eurekaserver
server.port=8000
#开启自己当做服务注册
eureka.client.register-with-eureka=true
#开启注册信息
eureka.client.fetch-registry=true
eureka.instance.hostname=eurekaproperties
#eureka.client.registry-fetch-interval-seconds=10
#eureka1 eurekaproperties eureka2 在C:\Windows\System32\drivers\etc\hosts 中 例如加入127.0.0.1 eurekaproperties
eureka.client.serviceUrl.defaultZone=http://eureka1:8001/eureka/,http://eureka2:8002/eureka/
# Running the evict task with compensationTime 0ms
logging.level.com.netflix=warn
#设置为false 关闭自我保护模式,默认是true 。设置为false,否则一个节点挂掉之后,不会在unavailable-replicas中出现
eureka.server.enable-self-preservation=false
#扫描并清理失效服务的间隔时间(单位毫秒,默认是60*1000)即60秒
eureka.server.eviction-interval-timer-in-ms=60000
#定义服务失效的时间,单位:秒 默认值为90 一下就出现在unavailable-replicas !!!lease-expiration-duration-in-seconds 至少应该大于lease-renewal-interval-in-seconds
eureka.instance.lease-expiration-duration-in-seconds=40
#定义服务续约任务(心跳)的调用间隔,单位:秒 默认值为30
eureka.instance.lease-renewal-interval-in-seconds=30
#只有开启自我保护才有用
#eureka.server.renewalPercentThreshold=0.49
注意1:eurekaproperties eureka1 eureka2 在C:\Windows\System32\drivers\etc\hosts中设置。
2:如果是一个eureka(单机)则
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
3:如果开启了security验证则
spring.security.user.password=user
spring.security.user.name=user
那么security 开头的配置是因为引入了spring security保护server端,因此 需要注意 service-url 中的 defaultZone 的值的写法 :
http://用户名:密码@主机:端口/eureka/
如果想关掉security则把下面注解放到启动类上:
@EnableAutoConfiguration(exclude = {
SecurityAutoConfiguration.class
})
4:关闭不停的节点日志打印:
logging.level.com.netflix=warn
5:Spring Cloud Eureka 自我保护机制(实际上在生产环境或其他环境应该开启)
eureka.server.enable-self-preservation=true 开启 (false 关闭)
#只有开启自我保护才有用(两者是共存的要有都有要无都无)
eureka.server.renewalPercentThreshold=0.49
这个小数到底是多少请参考:
https://www.cnblogs.com/xishuai/p/spring-cloud-eureka-safe.html
6:spring.application.name 表示注册到eureka服务上的名字,建议小写
7:开启自定义健康检查展示健康信息(我在两个生产者上加的自定义健康检查)
配置文件加上
#开启健康检查
eureka.client.healthcheck.enabled=true
#健康信息完整显示 http://localhost:9006/actuator/health {"status":"DOWN"} 这显示信息少
eureka.management.security.enabled = false
management.endpoint.health.show-details=always
pom:
org.springframework.boot
spring-boot-starter-actuator
自定义MyHealthHealthCheckHandler
import com.netflix.appinfo.HealthCheckHandler;
import com.netflix.appinfo.InstanceInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Status;
import org.springframework.stereotype.Component;
@Component
public class MyHealthHealthCheckHandler implements HealthCheckHandler{
@Autowired
private MyHealthIndicator myHealthIndicator;
@Override
public InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus currentStatus){
Status status=myHealthIndicator.health().getStatus();
if(status==Status.UP){
return InstanceInfo.InstanceStatus.UP;
}else{
return InstanceInfo.InstanceStatus.DOWN;
}
}
}
自定义MyHealthIndicator
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Status;
import org.springframework.stereotype.Component;
@Component
public class MyHealthIndicator implements HealthIndicator{
private int healthIndicatorErrorCount;
private int healthIndicatorCount;
private boolean hasError=false;
@Override
public Health health(){
if(!hasError){
healthIndicatorCount++;
//每检测5次,就返回DOWN
if(healthIndicatorCount%5==0){
hasError=true;
}
}else{
//DOWN计数10次就UP
healthIndicatorErrorCount++;
if(healthIndicatorErrorCount>10){
hasError=false;
healthIndicatorErrorCount=0;
}
}
if(hasError){
return new Health.Builder(Status.DOWN).build();
}
return new Health.Builder(Status.UP).build();
}
}
如图访问:http://localhost:9006/actuator/health (9006为down掉的项目的端口)即可显示Down
不自定义的话总是显示UP 。自定义后一旦服务所有提供者Down后则http://localhost:8000/actuator/health 永远显示上图,但是消费者调用时就请求不到了。
eureka2 properties:
spring.application.name=eurekaserver
server.port=8001
#开启自己当做服务注册
eureka.client.register-with-eureka=true
#开启注册信息
eureka.client.fetch-registry=true
eureka.instance.hostname=eureka1
#Eureka自我保护机制
#eureka.server.enable-self-preservation=true
#eureka.client.registry-fetch-interval-seconds=10
eureka.client.serviceUrl.defaultZone=http://eureka2:8002/eureka/,http://eurekaproperties:8000/eureka/
logging.level.com.netflix=warn
#设置为false 关闭自我保护模式,否则一个节点挂掉之后,不会在unavailable-replicas中出现
eureka.server.enable-self-preservation=false
eureka.instance.lease-expiration-duration-in-seconds=10
eureka.instance.lease-renewal-interval-in-seconds=30
eureka.server.eviction-interval-timer-in-ms=1000
#eureka.server.renewalPercentThreshold=0.49
eureka3 properties:
spring.application.name=eurekaserver
server.port=8002
#开启自己当做服务注册
eureka.client.register-with-eureka=true
#开启注册信息
eureka.client.fetch-registry=true
eureka.instance.hostname=eureka2
#Eureka自我保护机制
#eureka.server.enable-self-preservation=true
#eureka.client.registry-fetch-interval-seconds=10
eureka.client.serviceUrl.defaultZone=http://eurekaproperties:8000/eureka/,http://eureka1:8001/eureka/
logging.level.com.netflix=warn
#设置为false 关闭自我保护模式,否则一个节点挂掉之后,不会在unavailable-replicas中出现
eureka.server.enable-self-preservation=false
eureka.instance.lease-expiration-duration-in-seconds=10
eureka.instance.lease-renewal-interval-in-seconds=30
eureka.server.eviction-interval-timer-in-ms=1000
#eureka.server.renewalPercentThreshold=0.49
eureka pom:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
com.springcloud
eureka
0.0.1-SNAPSHOT
eureka
Demo project for Spring Boot
UTF-8
UTF-8
1.8
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
2.0.0.RELEASE
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
2.0.0.RELEASE
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-config
org.springframework.cloud
spring-cloud-dependencies
Finchley.BUILD-SNAPSHOT
pom
import
spring-snapshots
Spring Snapshots
https://repo.spring.io/libs-snapshot
true
org.springframework.boot
spring-boot-maven-plugin
production:
注意:如果是做负载均衡只需在复制粘贴生产者随后改了端口号,其他不需要改动即可!!!!
HelloController
@RestController
@RequestMapping(value = "/home",method = RequestMethod.GET)
public class HelloController {
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String index(@RequestParam String name) {
return "hello "+name+",this is first messge";
}
}
ProductionApplication
package com.springcloud.production;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
//禁用Security 避免输入账号密码
@EnableAutoConfiguration(exclude = {
SecurityAutoConfiguration.class
})
@EnableDiscoveryClient
public class ProductionApplication {
public static void main(String[] args) {
SpringApplication.run(ProductionApplication.class, args);
}
}
注意:@EnableDiscoveryClient 启用服务注册与发现(表示这是客户端)
Eureka 使用 @EnableEurekaClient或者@EnableDiscoveryClient,其他的服务发现代理使用@EnableDiscoveryClient
application.properties
spring.application.name=production
server.port=9006
eureka.client.serviceUrl.defaultZone=http://eurekaproperties:8000/eureka/
Production pom
4.0.0
com.springcloud
production
0.0.1-SNAPSHOT
production
jar
Demo project for Spring Boot
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
UTF-8
UTF-8
1.8
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
2.0.0.RELEASE
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
2.0.0.RELEASE
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-config
org.springframework.cloud
spring-cloud-dependencies
Finchley.BUILD-SNAPSHOT
pom
import
spring-snapshots
Spring Snapshots
https://repo.spring.io/libs-snapshot
true
org.springframework.boot
spring-boot-maven-plugin
consumer:
ConsumerController:
package com.springcloud.consumer.controller;
import com.springcloud.consumer.service.HelloRemoteService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class ConsumerController {
@Autowired
private HelloRemoteService helloRemoteService;
@RequestMapping(value = "/hello/{name}",method = RequestMethod.GET)
public String index(@PathVariable("name") String name) {
return helloRemoteService.hello(name);
}
}
HelloRemoteService:
package com.springcloud.consumer.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Created by summer on 2017/5/11.
*/
//path 对应controller中的
@FeignClient(name = "production", path = "/home")
public interface HelloRemoteService {
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String hello(@RequestParam("name") String name);
}
ConsumerApplication:
package com.springcloud.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
//禁用Security 避免输入账号密码
@EnableAutoConfiguration(exclude = {
SecurityAutoConfiguration.class
})
@EnableDiscoveryClient //启用服务注册与发现
@EnableFeignClients //启用feign进行远程调用
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
consumer properties:
spring.application.name=consumer
server.port=9001
eureka.client.serviceUrl.defaultZone=http://eurekaproperties:8000/eureka/
comsumer pom:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
com.springcloud
consumer
0.0.1-SNAPSHOT
consumer
Demo project for Spring Boot
UTF-8
UTF-8
1.8
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
2.0.0.RELEASE
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
2.0.0.RELEASE
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
org.springframework.cloud
spring-cloud-starter-openfeign
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
org.springframework.security
spring-security-config
4.1.0.RELEASE
org.springframework.security
spring-security-web
4.1.0.RELEASE
org.springframework.cloud
spring-cloud-dependencies
Finchley.BUILD-SNAPSHOT
pom
import
spring-snapshots
Spring Snapshots
https://repo.spring.io/libs-snapshot
true
org.springframework.boot
spring-boot-maven-plugin
(二)报错整理:
(1)当你在启动三个eureka的时候会发现有的eureka报错
com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect
对于这个错,是在第一个节点eureka-server1启动后,向eureka-server2注册时连接拒绝(java.net.ConnectException: Connection refused: connect)导致,因为此时eureka-server2节点还未启动,所有出现此类错误信息是正常的,eureka-server2启动后,此类错误日志将不会出现。关于各类集群环境不同节点在顺次启动时都会出现类似错误信息的,大家不必惊慌!
启动的时候首先的保证把下图中默认的打钩去掉,意思是可以同时启动(启动一个在启动另一个)多个实例
eureka2是application-eureka2.properties 中的eureka2
(2)所有eureka跑完后发现eureka客户端里面有类似于如下的红字信息,就我知道的应该是配置文件中client 和server中配置不合适导致的,但是不影响功能:
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.
参考:https://segmentfault.com/a/1190000008378268
eureka.client.register-with-eureka=true
开启自己当做服务注册(单机话设为false,集群则设为true。和下面一个注解是共用的)
eureka.client.fetch-registry=true
即不去检索服务(单机话设为false,集群则设为true)
eureka.client.registry-fetch-interval-seconds
表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒
eureka.instance.lease-expiration-duration-in-seconds
leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,告诉服务端,如果我2s之内没有给你发心跳,就代表我“死”了,将我踢出掉。测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服务
eureka.instance.lease-renewal-interval-in-seconds
leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。
eureka.server.enable-self-preservation
是否开启自我保护模式,默认为true。
默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。
Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
eureka.server.eviction-interval-timer-in-ms
eureka server清理无效节点的时间间隔,默认60000毫秒,即60秒。
(四)注解使用:
(1)禁用Security 避免输入账号密码验证
写在启动类那里
@EnableAutoConfiguration(exclude = {
SecurityAutoConfiguration.class
})
(2)启用服务注册与发现
写在启动类那里
@EnableDiscoveryClient
(3)启用feign进行远程调用
写在启动类那里
@EnableFeignClients
结合使用@FeignClient(name = “production”, path = “/home”)
name: spring.application.name=production 中的名称
path:被调用者的路径.。总之consumer中路径拼接起来要和生产者一样
@FeignClient(name = "production", path = "/home")
public interface HelloRemoteService {
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String hello(@RequestParam("name") String name);
}
(4)声明注册中心Eureka
写在启动类那里
@EnableEurekaServer
(五)集群展示图:
localhost:9091/hello/{name} 输入例如:localhost:9091/hello/ljlo