项目实施-10 (搭建SpringClood微服务)

概述

为了应对高并发的场景,javaweb项目一般都是部署成集群形式,同时通过Spring CloudEureka 技术,实现web模块,负载均衡的访问服务模块。本文介绍了,搭建简单的高可用的Eureka集成方案。

整体框架

在这里插入图片描述
在这里插入图片描述

搭建注册中心

①依赖
<?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>

    <groupId>com.baizhi</groupId>
    <artifactId>Eureka</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>
	<!--引入Cloud-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!--引入Eureka依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>
②编写入口类

@EnableEurekaServer 开启服务注解 需要在入口类上加上此注解,注册中心才能生效。

package com.baizhi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer //开启服务注解
public class SpringBootEurekaService {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootEurekaService.class,args);
    }
}

③配置核心文件
# 自定义端口号
server.port=1111

# 指定当前注册中心的服务名称
spring.application.name=eureka-registry

## 启用注册中心主动失效,并且每次主动失效检测间隔为5s 默认值60s
eureka.server.eviction-interval-timer-in-ms= 5000
## 设置eureka注册中心的响应更新时间
eureka.server.responseCacheUpdateIntervalMs=3000

eureka.server.responseCacheAutoExpirationInSeconds=60
# 客户端每60s 发送一个心跳 (期待值)
eureka.server.expected-client-renewal-interval-seconds=60
# 接收的心跳达到预期的百分比85%
eureka.server.renewal-percent-threshold=0.85
# 当没有新数据产生是间隔多少时间同步一次数据
eureka.server.wait-time-in-ms-when-sync-empty=10000

## 配置注册中心的主机名
eureka.instance.instance-id = eureka-1
eureka.instance.hostname = pro1
## 服务刷新时间配置,每隔这个时间会主动心跳一次
eureka.instance.lease-renewal-interval-in-seconds= 5
## 服务提供者被认定为丢失心跳超时,失效多久后被删除
eureka.instance.lease-expiration-duration-in-seconds=15

## 配置定时获取|抓取注册中心的数据时间
eureka.client.registry-fetch-interval-seconds= 5
eureka.client.instance-info-replication-interval-seconds= 5
## 配置集群中其他eureka实例,用于本eureka实例的注册方。
eureka.client.region=beijing
## 这里配置其他的中心的标识名 例: zone-2,zone-3
eureka.client.availability-zones.beijing=zone-2
## 这里配置实际的中心地址 
## 多个时,重开一行复写
eureka.client.service-url.zone-2=http://pro2:1111/eureka/

高可用时,其他的配置文件,对比
因为是跑在不同的服务器上的,所以,端口号不会冲突

server.port=1111

# 指定当前注册中心的服务名称
spring.application.name=eureka-registry

## 启用注册中心主动失效,并且每次主动失效检测间隔为5s 默认值60s
eureka.server.eviction-interval-timer-in-ms= 5000
## 设置eureka注册中心的响应更新时间
eureka.server.responseCacheUpdateIntervalMs=3000
eureka.server.responseCacheAutoExpirationInSeconds=60
eureka.server.expected-client-renewal-interval-seconds=60
eureka.server.renewal-percent-threshold=0.85
eureka.server.wait-time-in-ms-when-sync-empty=10000

## 配置注册中心的主机名
eureka.instance.instance-id = eureka-2
eureka.instance.hostname = pro2
## 服务刷新时间配置,每隔这个时间会主动心跳一次
eureka.instance.lease-renewal-interval-in-seconds= 5
## 服务提供者被认定为丢失心跳超时,失效多久后被删除
eureka.instance.lease-expiration-duration-in-seconds=15

## 配置定时获取|抓取注册中心的数据时间
eureka.client.registry-fetch-interval-seconds= 5
eureka.client.instance-info-replication-interval-seconds= 5
## 配置集群中其他eureka实例,用于本eureka实例的注册方。
eureka.client.region=beijing
eureka.client.availability-zones.beijing=zone-1
eureka.client.service-url.zone-1=http://pro1:1111/eureka/

☆、以下是单机版的注册中心配置 ↓↓↓
# 服务基本配置
server.port=8750

# 配置Eureka服务注册中心

# 服务实例的主机名
eureka.instance.hostname=localhost

# 注册中心服务相关配置 ,如果收到的心跳低于期望心跳85%,则注册中心会进入`自我保护机制` - 不删除注册中心认定失效的节点

# 客户端每60s 发送一个心跳
eureka.server.expected-client-renewal-interval-seconds=60
# 每1s检查一次,是否有down机的实例
eureka.server.eviction-interval-timer-in-ms=1000
# 接收的心跳达到预期的百分比85%
eureka.server.renewal-percent-threshold=0.85
# 当没有新数据产生是间隔多少时间同步一次数据
eureka.server.wait-time-in-ms-when-sync-empty=10000

# 关闭Eureka自我注册和抓取功能
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
☆、作为参考的配置选项,与本次项目无关 ↑↑↑
④配置日志
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender" >
        <encoder>
            <pattern>%p %c#%M %d{yyyy-MM-dd HH:mm:ss} %m%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 控制台输出日志级别 -->
    <root level="ERROR">
        <appender-ref ref="STDOUT" />
    </root>

    <logger name="org.springframework" level="INFO" additivity="false">
        <appender-ref ref="STDOUT" />
    </logger>

</configuration>
⑤启动注册中心

打包后发布到集群的服务器上

启动命令:

后方的参数根据,配置文件中的参数,在不同机器上,启动不同的服务。
例:以本次项目参考 --spring.profiles.active=eureka-1--spring.profiles.active=eureka-2

java -jar Eureka-1.0-SNAPSHOT.jar --spring.profiles.active=eureka-1 
⑥访问

以配置文件中的端口为准,出现下图 蓝色框内表示,成功启动。
在这里插入图片描述

配置服务实例

服务实例,即指 Eureka代理后实际访问的控制模块

①引入依赖
 <!--引入cloud-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
	<dependencies>
 <!--集成Eureka-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
     </dependencies>
②配置属性

注:如果是单机模式,直接在最后的默认地址中配置为单个即可


#Spring设置
spring:
   #配置以此名进行Euraka注册
  application:
    name: USER-SERVICE

# Eureka的配置
eureka:
  instance:
    instance-id: 001          # 服务实例的id
    prefer-ip-address: true  # 服务实例是否优先在注册中心显示ip
    lease-renewal-interval-in-seconds: 10   # 主动发送心跳频率10s
    lease-expiration-duration-in-seconds: 30    # 认定实例失效时间30s
  client:
    register-with-eureka: true    # 在Eureka注册中心注册
    fetch-registry: false         # 不需要在Eureka抓取数据
    service-url:
      defaultZone: http://pro1:1111/eureka/,http://pro2:1111/eureka/        # Eureka的地址
③发布运行

打包发布到集群服务器

扫描二维码关注公众号,回复: 10352079 查看本文章

启动命令:

java -jar UserModel-1.0-SNAPSHOT.jar 

当有多个服务器共同运行时,其他节点在启动时要给定不一样的实例参数id,命令如下:

java -jar UserModel-1.0-SNAPSHOT.jar --eureka.instance.instance-id=002

配置使用端

即配置web模块的使用

①引入依赖
 <!--引入cloud-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
       <!--集成Eureka-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

    </dependencies>
②开启访问请求的负载均衡

在入口类,注册restTemple实例到工厂的时候,需要添加 @LoadBalanced 注解

package com.baizhi;

import com.baizhi.loadbalance.UserDefinedClientHttpRequestIntterceptor;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RoundRobinRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class UserWebmodelApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserWebmodelApplication.class, args);
    }


    //注册一个Rest组件 SpringMVC中自带的一个Rest客户端工具,可以无缝和SpringBoot集成

    @Bean
    @LoadBalanced  //开启负载均衡
    public RestTemplate restTemplate(){
        RestTemplate restTemplate = new RestTemplate();
     /*   //添加拦截器
        restTemplate.getInterceptors().add(new UserDefinedClientHttpRequestIntterceptor());

*/
        return restTemplate;
    }

    @Bean
    public IRule rule(){
        return new RoundRobinRule();//设置轮训策略
    }

}
③配置属性

注:单机模式下,直接在最后的参数中修改为唯一ip即可


# 向Eureka注册中心获取服务

eureka:
  client:
    fetch-registry: true          # 需要获取服务
    register-with-eureka: false   # 不需要注册
    service-url:
      defaultZone: http://pro1:1111/eureka/,http://pro2:1111/eureka/    # Eureka地址
④发布

因为是SpringMVC发布为war包即可。

 <groupId>com.baizhi</groupId>
    <artifactId>user_web_model</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

在服务器启动:

java -jar user_web_model-0.0.1-SNAPSHOT.war

Eureka 原理

配置restTemple上的拦截器

拦截器的存在,使得每次发送请求,都要先走拦截器,通过实现,决定去找哪个服务模块。

注册restTemple时添加拦截器
    package com.baizhi;
    
    import com.baizhi.loadbalance.UserDefinedClientHttpRequestIntterceptor;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @SpringBootApplication
    public class UserWebmodelApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(UserWebmodelApplication.class, args);
        }
    
    
        //注册一个Rest组件 SpringMVC中自带的一个Rest客户端工具,可以无缝和SpringBoot集成
        @Bean
        public RestTemplate restTemplate(){
            RestTemplate restTemplate = new RestTemplate();
           //添加拦截器
           restTemplate.getInterceptors().add(new UserDefinedClientHttpRequestIntterceptor());
    
            return restTemplate;
        }
    
    }
实现拦截器


    package com.baizhi.loadbalance;
    
    import org.springframework.http.HttpRequest;
    import org.springframework.http.client.ClientHttpRequestExecution;
    import org.springframework.http.client.ClientHttpRequestInterceptor;
    import org.springframework.http.client.ClientHttpResponse;
    
    import java.io.IOException;
    
    //创建拦截器
    public class UserDefinedClientHttpRequestIntterceptor implements ClientHttpRequestInterceptor {
        @Override
        public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
            return clientHttpRequestExecution.execute(new UserDefinedHttpRequest(httpRequest),bytes);
        }
    }
    
在拦截器中,执行逻辑


    package com.baizhi.loadbalance;
    
    import org.aspectj.weaver.ast.Var;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpRequest;
    
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.util.*;
    
    public class UserDefinedHttpRequest implements HttpRequest {
        //提供一个存储真实请求地址的map
        private Map<String, List<HostAndPort>> sourceMap = null;
    
        //属性 目标请求
        private HttpRequest httpRequest;
        //构造
        public UserDefinedHttpRequest(HttpRequest httpRequest){
            this.httpRequest=httpRequest;
            //向地址属性中,放入真实的请求地址
            sourceMap = new HashMap<>();
            sourceMap.put("USER-SERVICE", Arrays.asList(
                    new HostAndPort("pro1",9090),
                    new HostAndPort("pro2",9090)
            ));
        }
    
        @Override
        public String getMethodValue() {
            return httpRequest.getMethodValue();
        }
    
        //获取真实的请求地址
        @Override
        public URI getURI() {
            //获取请求中的地址
            URI originURI = httpRequest.getURI();
            //创建最终返回值的引用
            URI outURI = null;
            try {
                //如果请求中有符合已注册的真实地址,则进行选择返回
                if (sourceMap.containsKey(originURI.getHost())) {
                    //负载均衡,随机返回
                    List<HostAndPort> ips = sourceMap.get(originURI.getHost());
                    //随机返回ip地址
                    HostAndPort finalIp = ips.get(new Random().nextInt(ips.size()));
    
                    //进行最终的请求释放
                    outURI = new URI(originURI.getScheme(), originURI.getUserInfo(), finalIp.getHost(), finalIp.getPort(), originURI.getPath(), originURI.getQuery(), originURI.getFragment());
                } else {
                    outURI = originURI;
                }
            }catch (Exception e){
                    e.printStackTrace();
            }
            System.out.println("目前选择的访问地址是"+outURI.getHost());
            return outURI;
        }
        @Override
        public HttpHeaders getHeaders() {
            return httpRequest.getHeaders();
        }
    }
    
需要一个实体类,配置实际的ip和端口
    package com.baizhi.loadbalance;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    @Accessors(chain = true)
    public class HostAndPort {
        private String host;
        private Integer port;
    }
使用
     //定义一个访问地址抬头
        private String prefix="http://USER-SERVICE:9090/user/restUserManager";
发布了32 篇原创文章 · 获赞 1 · 访问量 1152

猜你喜欢

转载自blog.csdn.net/ASYMUXUE/article/details/105230732
今日推荐