Spring Cloud与Docker微服务架构实战简单学习笔记(一)
- Eureka架构图
- 1. 如何让一个项目变成Eureka Server
- 1.1 POM中引入依赖包
- 1.2 application.properties添加以下配置
- 1.3 启动类加注解@EnableEurekaServer
- 1.4 启动后,访问“http://localhost:8761”看效果
- 2. 整合Actuator监控
- 2.1 POM中引入依赖包
- 2.2 访问以下地址看信息
- 3. 为Eureka Server添加用户认证
- 3.1 POM中引入依赖包
- 3.2 application.properties添加配置
- 3.3 关闭CSRF检验
- 3.4 再访问http://localhost:8761/输入用户名密码即可。
- 4. 如何注册服务到注册中心
- 4.1 POM引入依赖
- 4.2 添加配置
- 4.3 启动类加注解@EnableEurekaClient,注册到注册中心
- 5 Eureka的元数据
- 5.1 添加一个叫“hht-metadata”的自定义元数据
- 5.2 通过DiscoveryClient查看元数据
- 5.3 通过eureka查看Eureka的metadata
- 6. Eureka的自我保护模式
- 7. Eureka的健康检查
- 8. 如何新建一个Eureka Client
- 8.1 引入依赖包
- 8.2 添加配置项
- 8.3 新建FeignClient接口
- 8.4 新建FallbackFactory
- 8.5 新建controller
- 8.6 启动类加注解
- 8.7 测试验证
Eureka架构图
1. 如何让一个项目变成Eureka Server
1.1 POM中引入依赖包
<!-- 添加Eureka Server的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
1.2 application.properties添加以下配置
单注册中心
server.port=8761
spring.application.name=microservice-simple-eureka-server
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=true
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
集群注册中心
eureka.client.register-with-eureka要设置为true,保持高可用。可以不设置,默认为true。
spring.application.name=microservice-simple-eureka-server
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/,http://localhost:8762/eureka/
1.3 启动类加注解@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication1
{
public static void main( String[] args )
{
SpringApplication.run(EurekaServerApplication1.class, args);
}
}
1.4 启动后,访问“http://localhost:8761”看效果
.
2. 整合Actuator监控
2.1 POM中引入依赖包
<!-- 添加Actuator监控依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.2 访问以下地址看信息
.
3. 为Eureka Server添加用户认证
3.1 POM中引入依赖包
<!-- 添加为Eureka Server提供用户认证能力的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
3.2 application.properties添加配置
#为Eureka Server提供用户认证能力的相关配置
security.basic.enabled=true
spring.security.user.name=admin
spring.security.user.password=123456
注册服务的地方要加上用户名密码
eureka.client.serviceUrl.defaultZone=http://admin:123456@localhost:8762/eureka/
3.3 关闭CSRF检验
新版(Spring Cloud 2.0 以上)的security默认启用了csrf检验,要在eurekaServer端配置security的csrf检验为false
新建如下类:
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/eureka/**");
super.configure(http);
}
// @Override
// protected void configure(HttpSecurity http) throws Exception {
// http.csrf().disable();
// super.configure(http);
// }
}
3.4 再访问http://localhost:8761/输入用户名密码即可。
.
4. 如何注册服务到注册中心
4.1 POM引入依赖
<!-- 添加Eureka Client依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
4.2 添加配置
#eureka client相关配置
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/,http://localhost:8762/eureka/
eureka.client.instance.prefer-ip-address=true
4.3 启动类加注解@EnableEurekaClient,注册到注册中心
@SpringBootApplication
@EnableEurekaClient
public class UserApplication
{
public static void main( String[] args )
{
SpringApplication.run(UserApplication.class, args);
}
}
5 Eureka的元数据
Eureka的元数据有两种:标准元数据和自定义元数据。
标准元数据:主机名、IP地址、端口号、状态页和健康检查等信息,这些信息都会被发布在服务注册表中,用于服务之间的调用。
自定义元数据:可以使用eureka.instance.metadata-map配置,这些元数据可以在远程客户端中访问,但是一般不改变客户端行为,除非客户端知道该元数据的含义。
5.1 添加一个叫“hht-metadata”的自定义元数据
#自定义元数据
eureka.instance.metadata-map.hht-metadata=this is my metadata!
5.2 通过DiscoveryClient查看元数据
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/user-instance")
public List<ServiceInstance> showInfo(){
return this.discoveryClient.getInstances("microservice-simple-provider-user");
}
访问上面的地址“/user-instance”效果如下:
5.3 通过eureka查看Eureka的metadata
访问“http://localhost:8761/eureka/app”效果如下:
6. Eureka的自我保护模式
默认情E况下,如果Eureka Server在一定时间内没有接受到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。
但是当网络分区故障发生时,微服务与eureka server之间无法正常通信,以上行为就可能变得非常危险了——因为微服务本身其实是健康的,此时不应该注销这个服务。
Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
在Spring Cloud中,可以使用以下配置禁用自我保护模式:
eureka.server.enable-self-preservation=false
7. Eureka的健康检查
进入到Eureka的首页,在Status栏有个UP,表示应用程序状态正常。应用程序状态还有其他值,例如:DOWN、OUT_OF_SERVICE、UNKNOWN等。只有标记为“UP”的微服务会被请求。
前文讲过,Eureka Server与Eureka Client之间使用心跳机制来确定Eureka Client的状态,默认情况下,如果心跳保持正常,应用程序就会始终保持“UP”状态。这种机制并不能完全反映应用程序的状态。
例如:如果心跳正常,但微服务的数据源发生了问题,服务无法使用,但在Eureka中仍然是“UP”状态。
如何解决?前文说过,Spring Boot Actuator提供了/health端点,该端点可以展示应用程序的健康信息。那么如何才能将该端点中的健康状态传播到Eureka Server呢?
只需要开启Eureka的健康检查,这样程序就会把自己的健康状态传播到Eureka Server。
开启方法只需要添加以下配置:
eureka.client.healthcheck.enable=true
某些场景下,可能希望更细粒度的控制健康检查,可以实现com.netflix.appinfo.HealthCheckHandler接口。
8. 如何新建一个Eureka Client
8.1 引入依赖包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 添加Eureka Client依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<!-- 添加Feign依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- 添加Hystrix依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
8.2 添加配置项
server.port=8035
spring.application.name=microservice-simple-consumer-food
eureka.client.serviceUrl.defaultZone=http://hht:123456@localhost:8761/eureka/,http://hht:123456@localhost:8762/eureka/
eureka.client.instance.prefer-ip-address=true
microservice-simple-provider-user.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
feign.hystrix.enabled=true
8.3 新建FeignClient接口
@FeignClient(name = "microservice-simple-provider-user", fallbackFactory = UserFeignClientFallbackFactory.class)
public interface UserFeignClient {
@GetMapping("/user/findByName/{name}")
public List<UserEntity> findByName(@PathVariable String name);
}
8.4 新建FallbackFactory
@Component
public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient> {
private static final Logger log = LoggerFactory.getLogger(UserFeignClientFallbackFactory.class);
@Override
public UserFeignClient create(Throwable cause) {
return new UserFeignClient() {
@Override
public List<UserEntity> findByName(String name) {
// 日志最好放在各个fallback方法中,不要直接放在create方法中
// 否则在引用启动时,就会打印该日志
UserFeignClientFallbackFactory.log.error("=========== fallback reason is :", cause);
List<UserEntity> userList = new ArrayList<UserEntity>();
UserEntity user = new UserEntity();
user.setId(-1l);
user.setAge(20);
user.setUsername("account-1");
user.setName("默认用户(打印fallback原因)");
user.setBalance(new BigDecimal(9999));
userList.add(user);
return userList;
}};
}
}
8.5 新建controller
@RestController
@RequestMapping("/food")
public class FoodController {
@Autowired
UserFeignClient userFeignClient;
@GetMapping("/user/findByName/{name}")
public List<UserEntity> findByName(@PathVariable String name){
return userFeignClient.findByName(name);
}
}
8.6 启动类加注解
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
public class FoodApplication
{
public static void main( String[] args )
{
SpringApplication.run(FoodApplication.class, args);
}
/**
* 低版本直接启动即可使用 http://ip:port/hystrix.stream 查看监控信息 高版本需要添加本方法方可使用
* http://ip:port/hystix.stream 查看监控信息
*
* @return
*/
@Bean
public ServletRegistrationBean<HystrixMetricsStreamServlet> hystrixMetricsStreamServlet() {
ServletRegistrationBean<HystrixMetricsStreamServlet> registration = new ServletRegistrationBean<HystrixMetricsStreamServlet>(new HystrixMetricsStreamServlet());
registration.addUrlMappings("/hystrix.stream");
return registration;
}
// @Bean
// public ServletRegistrationBean<HystrixMetricsStreamServlet> getServlet() {
// HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
// ServletRegistrationBean<HystrixMetricsStreamServlet> registrationBean = new ServletRegistrationBean<HystrixMetricsStreamServlet>(streamServlet);
// registrationBean.setLoadOnStartup(1);
// registrationBean.addUrlMappings("/hystrix.stream");
// registrationBean.setName("HystrixMetricsStreamServlet");
// return registrationBean;
// }
}
8.7 测试验证
验证接口:http://localhost:8035/food/user/findByName/%E5%BC%A0%E4%B8%89
验证Hystrix监控:http://www.localhost:8035/hystrix.stream