Spring-cloud微服务 Eureka学习教程-分布式搭建EurekaServer、EurekaClient(中级)
我们这里只有一台服务器,所以我们先仿集群搭建。
完整demo项目代码:https://github.com/wades2/EurekaDemo2
在这之前我们先分析分析Eureka相比其他注册中心的好处。在一般的应用过程中,如果注册中心service出现了问题,然而没有备用的节点去替代这个主节点去分发服务,就会造成相关注册服务的瘫痪,因此我们在分布式架构中,都会有备用节点。
我们先看看Doubel,在doubel中,zookeeper(以下简称zk)是作为服务注册中心的,在集群配置中,会有一个主从关系节点。如果Master挂了, zk就会启动节点推举,而在节点推举的过程中,整个服务是不能使用的。但是zk强调的是CAP理论中的CP强调高的一致性,【注:什么是CAP理论:Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得】,在实际上线的站点或者网站中,30~60s的选举过程导致站点不可用,损失是很大。
而我们再看看Eureka(如上图),Eureka是去中心化的,每个Eureka server都是平级的。Eureka取CAP中的AP,注重可用性,Eureka内置了心跳服务(用于淘汰一些“濒死”的服务器),即使当你的应用服务某个server挂掉了,其他的服务是可以立即顶上去,保证客户端向其发起请求有响应。
两者的对比我们先大致分析到这里。具体的分析可以看我转的一篇博客:
https://blog.csdn.net/asd529735325/article/details/85049662
接下来我们尝试自己搭建一个分布式的包含:Eureka Server,Application Service,Application Client的Eureka注册中心。
通过上面这张图我们可以看到,一个Eureka有三个角色:
1、Eureka Server(通过Register, Get,Renew等接口提供注册和发现)
2、Application Service(服务提供方,把自身服务实例注册到Eureka Server):
3、Application Client(Service Consumer):服务调用方,通过Eureka Server获取服务实例,并调用Application Service
他们主要进行的活动如下:
每个Region有一个Eureka Cluster, Region中的每个Zone都至少有一个Eureka Server。
Service作为一个Eureka Client,通过register注册到Eureka Server,并且通过发送心跳的方式更新租约(renew leases)。如果Eureka Client到期没有更新租约,那么过一段时间后,Eureka Server就会移除该Service实例。
当一个Eureka Server的数据改变以后,会把自己的数据同步到其他Eureka Server。
Application Client也作为一个Eureka Client通过Get接口从Eureka Server中获取Service实例信息,然后直接调用Service实例。
Application Client调用Service实例时,可以跨可用区调用。(【引】)
在上面一篇文章中我们已经搭建好了Eureka Server和Application Client,如果不清楚的朋友建议可以先看看这篇博文(https://blog.csdn.net/asd529735325/article/details/84992538,git代码:https://github.com/wades2/EurekaDemo ),再来本篇中一起探讨学习。
为了保护eureka安全性,在上一篇的基础上,我加了service访问密码。因此在client端和集群配置的service都需要加上相互的访问密码。
先看看我个人demo大致架构吧:
其中:EurekaServer模块和Eurekaserver_back是两个相互平级依赖的server,EurekaClient是我们服务提供方,EurekaCaller是我们服务的调用方。大致的调用过程如下图:
基于上一篇的基础,我们从新看看pom文件和相关配置。
首先是Eureka Server(此处我们是集群配置,因此有两个server)
首先修改电脑的hostname,添加:127.0.0.1 localhost server1 server2,作为两个server的相互依赖。
两个server的pom文件都一样:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.M3</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
相关注意点在上一篇博客有提到,这里就不赘述。
EurekaServer的配置文件:
# 应用程序的名称
spring.application.name=Eureka-server2
security.user.name=user
security.user.password=123456
#修改启动端口
server.port=8083
# 是否将该实例的注册信息注册到Eureka服务器上,在只有一个Eureka服务器的情况下没必要,只是用于实例的发现
eureka.client.register-with-eureka=true
# 是否向Eureka服务器获取注册信息,在单实例的Eureka中共没必要
eureka.client.fetch-registry=true
#Eureka Server能够迅速有效地踢出已关停的节点,但是新手由于Eureka自我保护模式,以及心跳周期长的原因,常常会遇到Eureka Server不踢出已关停的节点的问题
# 设为false,关闭自我保护
eureka.server.enable-self-preservation=true
#清理间隔
eureka.server.eviction-interval-timer-in-ms=6000
eureka.client.serviceUrl.defaultZone=http://user:123456@server2:8082/eureka
eureka.instance.hostname=server1
EurekaServer_back的配置文件:
# 应用程序的名称
spring.application.name=Eureka-server2
security.user.name=user
security.user.password=123456
#修改启动端口
server.port=8082
# 是否将该实例的注册信息注册到Eureka服务器上,在只有一个Eureka服务器的情况下没必要,只是用于实例的发现
eureka.client.register-with-eureka=true
# 是否向Eureka服务器获取注册信息,在单实例的Eureka中共没必要
eureka.client.fetch-registry=true
#Eureka Server能够迅速有效地踢出已关停的节点,但是新手由于Eureka自我保护模式,以及心跳周期长的原因,常常会遇到Eureka Server不踢出已关停的节点的问题
# 设为false,关闭自我保护
eureka.server.enable-self-preservation=true
#清理间隔
eureka.server.eviction-interval-timer-in-ms=60000
eureka.client.serviceUrl.defaultZone=http://user:123456@server1:8083/eureka
eureka.instance.hostname=server2
因为我们引入了security的jar包,保证访问server页面的安全性,因此,在client和其他节点配置的时候,都应该加上用户名和密码,把defaultZone改为:http://用户名:密码@hostname:端口号/eureka的形式。
【注意!!!!,这里因为是相互依赖,所以在EurekaServer中defaultZone使用的是EurekaServer_back的用户名,密码和它对应的hostname+端口,同理EurekaSerer_back对应的是EurekaServer的。】
运行类都一样:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
然后我们可以启动一个server访问一下:
访问需要用户名密码,就是配置文件里面的security.user.name,和security.user.password,我们可以看到界面如下:
这里我们可以看到因为我们8082端口的server因为没有启动,所以无法依赖到,但是已经注册进去了。我们再启动server_back可以看到界面如下:
这样的界面就是注册成功了。然后我们开始第二部:
Application Service注册到server里面,也就是我们上一篇说的client端,也就是我这个demo的EurekaClient:
pom文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.M3</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-netflix-eureka-client</artifactId>-->
<!--<version>1.3.6.RELEASE</version>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>1.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
application配置文件:
spring.application.name=Eureka-client
#eureka.client.allow-redirects=false
#修改启动端口
server.port=8084
eureka.client.serviceUrl.defaultZone=http://user:123456@localhost:8083/eureka,http://user:123456@localhost:8082/eureka
#eureka.client.register-with-eureka=true
eureka.instance.ip-address=true
启动类:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@EnableEurekaClient
//@EnableDiscoveryClient
@ComponentScan(basePackages = {"com.example.demo.controller"})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
这里我们设置了扫描controller包下面的java文件,我的demo中contorller如下:
其中UserController放置在controller这个包下,还有一个作为测试的Contrller放置在启动类平级目录(你也可以随便放一个,我们只是做后期实验的)
我们的UserController
package com.example.demo.controller;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.DiscoveryClient;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.converters.Auto;
import com.netflix.discovery.shared.Applications;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("user")
public class UserController {
// private static final Logger logger = LoggerFactory.getLogger(UserController.class);
// @Autowired
// private IUserService userService;
// @GetMapping("getUser")
// public List<UserEntity> getUser() {
// UserEntity user = new UserEntity();
// return userService.getUser();
// }
@Autowired
private EurekaClient eurekaClients;
// @Autowired
// private DiscoveryClient discoveryClient;
@GetMapping("getUser")
public String getUser() {
//todo 得到eureka server的服务实例
InstanceInfo info=eurekaClients.getNextServerFromEureka("Eureka-client",false);
// return info.getHomePageUrl();
return "hello one";
}
}
我们的Controller:
package com.example.demo;
import com.netflix.appinfo.InstanceInfo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("user")
public class Controller {
@GetMapping("getUser2")
public String getUser() {
return "hello tow....";
}
}
然后启动。
我们可以看到如下界面:
这里client已经注册进来了,然后我们可以访问一下http://localhost:8084/user/getUser
访问没问题。
访问http://localhost:8084/user/getUser2,报错,因为我们启动类没有扫描其他的包。
最后一步:Application Client(Service Consumer):服务调用方,通过Eureka Server获取服务实例,并调用Application Service
也就是我们的EurekaCaller:
直接使用Eureka Client还是比较麻烦的,幸运的是,RestTemplate整合了EurekaClient,Ribbon为我们提供了多样的负载均衡的功能,为我们提供了很多便利,我们所需要做的就是在Spring中注册一个RestTemplate,并且添加@LoadBalanced
注解。
加入Ribbon的原因是服务调用者不关心服务提供者有多少个服务实例,它只关注它要调用这个服务ID,因而可能需要一定的负载均衡。
pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RC1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
application配置文件:
spring.application.name=Eureka_caller
server.port=8086
eureka.client.serviceUrl.defaultZone=http://user:123456@localhost:8083/eureka,http://user:123456@localhost:8082/eureka
启动类一样扫描controller:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan({"com.example.demo.controller"})
@EnableEurekaClient
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
我们这里的controller开始通过Rest客户端映射调用注册的Eureka_client。
package com.example.demo.controller;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Configuration
public class Controller {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
@GetMapping("getUser/routine")
public String routine() {
RestTemplate restTemplate = getRestTemplate();
String json = restTemplate.getForObject("http://Eureka-client/user/getUser", String.class);
return json;
}
@GetMapping("getUser/routine2")
public String routine2() {
RestTemplate restTemplate = getRestTemplate();
String json = restTemplate.getForObject("http://Eureka-client/user/getUser2", String.class);
return json;
}
}
restTemplate.getForObject方法请求特定的服务url,注意里面使用的Eureka-client正是我们刚才在服务提供者客户端项目中配置的服务名称,它已经被注册到Eureka服务上。
然后我们启动,访问http://localhost:8086/getUser/routine
我们可以看到内容和访问http://localhost:8084/user/getUser一样,但是依旧访问http://localhost:8086/getUser/routine2访问不到,其实要想访问到很简单,在EurekaClient扫描中带上Conrtoller所在的包就可以了!
OK,全文结束,接下来我们讲解,如何充分利用ribbon来动态调用服务消费者。
Spring-cloud微服务 Eureka学习教程-分布式搭建EurekaServer、EurekaClient(中级)的更多相关文章
- Spring-cloud微服务 Eureka学习教程-分布式搭建EurekaServer、EurekaClient+Ribbon(中级)
我们这里只有一台服务器,所以我们先仿集群搭建. 完整demo项目代码:https://github.com/wades2/EurekaDemo2 在这之前我们先分析分析Eureka相比其他注册中心的好 ...
- Spring Cloud 微服务架构学习笔记与示例
本文示例基于Spring Boot 1.5.x实现,如对Spring Boot不熟悉,可以先学习我的这一篇:<Spring Boot 1.5.x 基础学习示例>.关于微服务基本概念不了解的 ...
- Spring-cloud微服务 Eureka学习教程-单服务器配置之快速搭建EurekaServer、EurekaClient(基础)
以下实例代码下载地址:https://github.com/wades2/EurekaDemo Eureka是Spring Cloud Netflix的一个子模块,也是核心模块之一.用于云端服务发现, ...
- Spring Cloud 微服务:Eureka+Zuul+Ribbon+Hystrix+SpringConfig实现流程图
相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新 ...
- Spring cloud微服务安全实战-7-3prometheus环境搭建
Prmetheus 主要用来做来Metrics的监控和报警,这张图是官方的架构图. 这是他的核心 它的作用是根据我们的配置去完成数据的采集.服务的发现,以及数据的存储. 这是服务的发现,通过Servi ...
- Spring cloud微服务安全实战_汇总
Spring cloud微服务安全实战 https://coding.imooc.com/class/chapter/379.html#Anchor Spring Cloud微服务安全实战-1-1 课 ...
- spring cloud微服务快速教程之(七) Spring Cloud Alibaba--nacos(一)、服务注册发现
0.前言 什么是Spring Cloud Alibaba? Spring Cloud Alibaba 是阿里开源的,致力于提供微服务开发的一站式解决方案.此项目包含开发分布式应用微服务的必需组件,方便 ...
- Spring Cloud微服务学习笔记
Spring Cloud微服务学习笔记 SOA->Dubbo 微服务架构->Spring Cloud提供了一个一站式的微服务解决方案 第一部分 微服务架构 1 互联网应用架构发展 那些迫使 ...
- 如何优化Spring Cloud微服务注册中心架构?
作者: 石杉的架构笔记 1.再回顾:什么是服务注册中心? 先回顾一下什么叫做服务注册中心? 顾名思义,假设你有一个分布式系统,里面包含了多个服务,部署在不同的机器上,然后这些不同机器上的服务之间要互相 ...
随机推荐
- pychram编写代码鼠标变粗处理
现象:如下图 解决: 键盘 点击 insert 按钮即可解决
- List集合分页
原文链接:https://www.cnblogs.com/haiyangsvs/p/6210852.html import java.util.Arrays; import java.util.Col ...
- P3943 星空 区间异或差分
\(\color{#0066ff}{ 题目描述 }\) 逃不掉的那一天还是来了,小 F 看着夜空发呆. 天上空荡荡的,没有一颗星星--大概是因为天上吹不散的乌云吧. 心里吹不散的乌云,就让它在那里吧, ...
- P1891 疯狂LCM
\(\color{#0066ff}{ 题目描述 }\) 众所周知,czmppppp是数学大神犇.一天,他给众蒟蒻们出了一道数论题,蒟蒻们都惊呆了... 给定正整数N,求LCM(1,N)+LCM(2,N ...
- luogu3327 [SDOI2015]约数个数和
link 设\(d(x)\)表示x约数个数,给定n,m,\(\sum_{i=1}^n\sum_{j=1}^md(ij)\) 多组询问,1<=T<=50000,1<=N, M<= ...
- react 中文文档案例四 (登陆登出按钮)
import React from 'react'; import ReactDOM from 'react-dom'; class LoginControl extends React.Compon ...
- Pandas基本功能详解
Pandas基本功能详解 Pandas Pandas基本功能详解 |轻松玩转Pandas(2) 参考:Pandas基本功能详解 |轻松玩转Pandas(2)
- css过渡transition
定义 过渡transition是一个复合属性,包括transition-property.transition-duration.transition-timing-function.transiti ...
- PHP的魔术常量
PHP的魔术常量(变量).魔术方法(函数).超全局变量 一.魔术常量(魔术变量) 概念:所谓的魔术常量就是PHP预定义的一些常量,这些常量会随着所在的位置而变化. 1.__LINE__ 获取文件中的 ...
- python--selectors模块
它的功能与linux的epoll,还是select模块,poll等类似:实现高效的I/O multiplexing, 常用于非阻塞的socket的编程中: 简单介绍一下这个模块,更多内容查看 pyt ...