集群组件以及关系
部署(eureka-client *2 ,ribbon 1 ,eureka-server3)
eureka-client
eureka-client:微服务的服务具体实现,单节点具体服务注册,注册到同一eureka集群可实现集群部署
ribbon:负载均衡,客户端访问的是该节点,实现多种负载均衡策略
eureka-server
EurekaServer同时也是EurekaClient。用于微服务集群的管理
eureka-server部署
项目结构
服务端客户端唯一区别在标红部分注解不一样。pom文件版本必须一致
eureka pom,parent,dependencies,dependencyManagement,build,repositories:
<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>
<groupId>com.cxz</groupId>
<artifactId>eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eureka</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</exclusion>
</exclusions>
</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>
java:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* Hello world!
*
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
单机eureka
单机启动时
application.yml配置如下:
server:
port: 8761
eureka:
instance:
hostname: eureka1
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://eureka1:8761/eureka/
注意,name不能用localhost
hostname在hosts中添加映射
127.0.0.1 eureka1
127.0.0.1 eureka2
127.0.0.1 eureka3
完成后即可启动成功,访问对应主页即可
集群eureka
application-dev1.yml配置如下:
server:
port: 8762
#spring:
# application:
# name: spring-cloud-eureka-server
eureka:
instance:
#服务注册中心实例的主机名
hostname: eureka1
# = true 就可以将IP注册到Eureka Server上,而如果不配置就是机器的主机名。
prefer-ip-address: false
client:
#是否向服务注册中心注册自己
register-with-eureka: true
#是否检索服务
fetch-registry: true
#服务注册中心的配置内容,指定服务注册中心的位置
serviceUrl:
defaultZone: http://eureka2:8763/eureka/, http://eureka3:8764/eureka/
application-dev2.yml配置如下:
server:
port: 8763
#spring:
# application:
# name: spring-cloud-eureka-server
eureka:
instance:
hostname: eureka2
# = true 就可以将IP注册到Eureka Server上,而如果不配置就是机器的主机名。
prefer-ip-address: false
client:
register-with-eureka: true
fetch-registry: true
serviceUrl:
defaultZone: http://eureka1:8762/eureka/, http://eureka3:8764/eureka/
application-dev3.yml配置如下:
server:
port: 8764
#spring:
# application:
# name: spring-cloud-eureka-server
eureka:
instance:
#要用域名,不能用localhost
hostname: eureka3
# = true 就可以将IP注册到Eureka Server上,而如果不配置就是机器的主机名。
prefer-ip-address: false
client:
register-with-eureka: true
fetch-registry: true
serviceUrl:
defaultZone: http://eureka1:8762/eureka/, http://eureka2:8763/eureka/
application.properties内容如下:
spring.profiles.active=@spring.profiles@
#java -jar eureka-server.jar --spring.profiles.active=dev2
#java -jar eureka-server.jar --spring.profiles.active=dev3
#java -jar eureka-server.jar --spring.profiles.active=dev4
打包时,运行对应的文件即可
成功后,相关界面显示如下:
踩坑总结
1.版本boot和cloud有相关版本对应关系,不兼容会启动失败
SpringBoot SpringCloud
1.2.X Angel
1.3.X Brixton
1.4.X Camden
1.5.X Dalston、Edgware
2.0.X Finchley
2.1.X Greenwich
详情查看 https://spring.io/projects/spring-cloud
2.available-replicas为空
= true 就可以将IP注册到Eureka Server上,而如果不配置就是机器的主机名。
prefer-ip-address: false
3.项目用properties,官网用yml
可以同时使用
client注册
具体服务
继续使用springboot项目onemillion作为具体服务提供者:
pom中增加和eureka-server相同配置:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mysqlVersion>8.0.13</mysqlVersion>
<druidVersion>1.1.14</druidVersion>
<springCloudVerion>Greenwich.RELEASE</springCloudVerion>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${springCloudVerion}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
然后在项目启动类加入注解@EnableEurekaClient即可:
@SpringBootApplication
//@EnableEurekaClient 和 @EnableDiscoveryClient的区别:
//这两个都是服务发现的注解,区别是:前者是只针对注册中心是Eureka使用的注解,后者是兼容所有的注册中心,例如:Zookeeper等。
@EnableEurekaClient
//因为多模块中其他配置模块也需要spring组件功能,所以发布模块需要加载其他模块的内容.
@ComponentScan(basePackages = {"org.million.**"})
//mybatis扫描
@MapperScan("org.million.dao.**")
public class Start extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Start.class, args);
}
为了方便定位服务,我们application.properties给项目起个明作为服务名,以及注册到eureka集群中心
#app
server.port=8898
spring.application.name=one-million
server.servlet.context-path=/one-million-dev
# 注册中心地址,如果是集群,那就逗号分隔
eureka.client.serviceUrl.defaultZone=http://eureka1:8762/eureka/, http://eureka2:8763/eureka/,http://eureka3:8764/eureka/
使用不同端口启动:
项目名称ONE-MILLION 在后面ribbon中需要用到
ribbon
我们用ribbon作为服务对外的真正提供者,使用之前用的testboot作用ribbon项目
ribbon pom和onemillion这个具体服务者pom文件类似,只是多新增了一个ribbon包依赖
<!-- 服务提供者.利用Ribbon实现。 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
启动类新增client扫描@EnableDiscoveryClient以及模板注入
/**
* Hello world!
*
*/
@SpringBootApplication
//因为多模块中其他配置模块也需要spring组件功能,所以发布模块需要加载其他模块的内容.
@ComponentScan(basePackages = {"boot.**"})
//服务发现
@EnableDiscoveryClient
//mybatis扫描
@MapperScan("boot.dao.**")
public class Start {
public static void main(String[] args) {
SpringApplication.run(Start.class, args);
}
/**
* Spring提供的用于访问Rest服务的客户端
* @return
*/
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
新增application.yml配置
eureka:
client:
service-url:
defaultZone: http://eureka1:8762/eureka/, http://eureka2:8763/eureka/,http://eureka3:8764/eureka/
instance:
appname: ribbon-client
server:
port: 8092
spring:
application:
name: ribbon-client
在ribbon中新建一个controller作为代理
TestRibbonApi:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping(value = "/test")
public class TestRibbonApi {
/**
* 注入RestTemplate
*/
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/get" ,method = RequestMethod.GET)
public String testGetNameOfBlog(){
String url="http://ONE-MILLION/one-million-dev/redisTest";
return restTemplate.getForObject(url,String.class);
}
}
访问rest/get时,真正访问的是ONE-MILLION集群中one-million-dev/redisTest具体服务
redisTest,开启两个端口作为集群:
8898端口
@GetMapping("/redisTest")
public String redisTest() {
MDC.clear();
MDC.put("uuid", StringUtils.getUUID());
if (StringUtils.isEmpty(redisService.getNew("hello"))) {
redisService.setNew("hello", "world world world");
}
System.out.println(new Gson().toJson(redisSetting));
logger.info("hello-------:"+redisService.getNew("hello"));
logger.info("hello-------:"+redisService.getNew("hello"));
return redisService.getNew("hello")+" new-----------";
}
redisTest:
8896端口
@GetMapping("/redisTest")
public String redisTest() {
MDC.clear();
MDC.put("uuid", StringUtils.getUUID());
if (StringUtils.isEmpty(redisService.getNew("hello"))) {
redisService.setNew("hello", "world world world");
}
System.out.println(new Gson().toJson(redisSetting));
logger.info("hello-------:"+redisService.getNew("hello"));
logger.info("hello-------:"+redisService.getNew("hello"));
return redisService.getNew("hello")+" old-----------";
}
根据ip访问具体服务节点:
http://localhost:8898/one-million-dev/redisTest 返回 world new-----------
http://localhost:8896/one-million-dev/redisTest 返回 world old----------
访问ribbon部署的端口号8092:http://localhost:8092/test/get 返回为world new-----------或者world old----------交替出现