资讯

展开

SpringCloud学习笔记(一)-搭建一个SpringCloud

作者:快盘下载 人气:

简介

摘自百度百科;
SpringCloud是一系列框架的有序集合。它利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等;都可以用SpringBoot的开发风格做到一键启动和部署。SpringCloud并没有重复制造轮子;它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来;通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理;最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

反正SpringCloud是一个用来做微服务的框架;主要是基于SpringBoot来完成的;相关的微服务框架还有比较出名的Dubbo和DubboX。关于微服务是用来做什么的;有什么好处自行百度。

SpringCloud是Spring全家桶中的一员;所以SpringCloud对于Spring的其他组件都有着很好的支持。

SpringCloud主要采用的Eureka;Dubbo主要采用的是zookeeper。

上代码

provider 服务提供者

直接新建一个SpringBoot项目;由于是为了示例;本次示例中不使用数据库;只引入了spring-boot-starter-web

项目及其简单;只暴露了一个接口;用于测试;yml文件只配置了端口号为7900

SpringCloud学习笔记(一)-搭建一个SpringCloud

consumer 服务消费者

同样新建一个SpringBoot项目;使其调用consumer的接口;同样只引入了spring-boot-starter-web;yml文件只是修改了端口号为7910。

这里解释一下RestTemplates这个类;关于这个类;这个老哥https://blog.csdn.net/u012702547/article/details/77917939的解释我觉得非常完整了;RestTemplates在SpringCloud中;消费者通过这个类访问生产者;;bean注解是为了实例化这个类;实例化之后通过;AutoWired注解引入;将其交给Spring进行管理。

分别启动两个类;分别访问localhost:7900/provider/demohttp://localhost:7910/consumer/demo应该都能得到ProviderDemo这个结果;说明consumer成功调用了provider中的方法。

问题;
这样的编码方式是将接口;http://localhost:7900/provider/demo;硬编码在代码中;但是项目发布之后;ip地址必然是变动的。而且;硬编码的方式肯定是无法实现负载均衡的;就是说如果同时启动多个provider服务;这种硬编码方式是无法根据负载均衡策略去调用服务的。

解决方法;
在Dubbo中使用的ZooKeeper作为服务注册与发现的容器;在Springcloud中使用的是Eureka作为服务注册与发现的容器。

Eureka

同样创建一个SPringBoot项目;下面是pom.xml文件;我是在idea中直接添加spring-cloud-starter-netflix-eureka-server这个依赖的。

<?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>cn.edu.nuaa</groupId>
    <artifactId>eureka-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-demo</name>
    <description>eureka-demo</description>

    <parent>
        <groupId>org.springFramework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <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>Finchley.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </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>

</project>

然后在Springboot的启动类上添加;EnableEurekaServer或者;EnableDiscoveryClient;这两个注解的注解的区别主要是;

;EnableEurekaServer是基于 spring-cloud-netflix依赖;只能为eureka作用;是专门给Eureka用的
;EnableDiscoveryClient是基于 spring-cloud-commons依赖;并且在classpath中实现;是给比如zookeeper、consul使用的;
旧版本的;EnableEurekaServer的源码上面也是也是有;EnableDiscoveryClient注解的。
本示例是使用Eureka的;故推荐使用;EnableEurekaServer

;SpringBootApplication
;EnableEurekaServer
public class EurekaDemoApplication {

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

然后在yml文件中配置如下信息;

server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8761/eureka/

这个端口号官网设置成8761;这里也设置成8761;

;register-with-eureka: false这个的默认值为true;设置为true不会对使用不会有很大的影响;但是在启动的时候会保下面的错误;
was unable to refresh its cache! status = Cannot execute request on any known server
是因为启动的时候自己注册了自己而引起的冲突

defaultZone配置eureka的地址;这个如果有多个注册中心;则用逗号隔开。
为了服务注册中心的安全考虑;很多时候我们都会为服务注册中心加入安全认证。通常与SpringSecurity整合;主要是SpringSecurity的内容;这里不做讨论;主要是我自己尝试的时候失败了;啊哈哈哈;。

配置信息完成之后;启动eureka项目;访问localhost:8761便可以得到下面的界面;目前上面两个写的provider和consumer还没有注册到该注册中心;
搭建一个SpringCloud

关于Eureka配置的含义及其默认值主要参考下表;

服务注册类配置

省略了eureka.client前缀

参数名说明默认值enabled启用Eureka客户端trueregistryFetchIntervalSeconds从Eureka服务端获取注册信息的间隔时间;单位为秒30instanceInfoReplicationIntervalSeconds更新实例信息的变化到Eureka服务端的间隔时间;单位为秒30initialInstanceInfoReplicationIntervalSeconds初始化实例信息到Eureka服务端的间隔时间;单位为秒40eurekaServiceUrlPollIntervalSeconds轮询Eureka服务端地址更改的间隔时间;单位为秒。当我们与Spring CLoud Config整合;动态刷新Eureka的serviceURL地址时需要关注该参数300eurekaServerReadTimeoutSeconds读取Eureka Server信息的超时时间;单位为秒8eurekaServerConnectTimeoutSeconds链接Eureka Server的超时时间;单位为秒5eurekaServerTotalConnections从Eureka客户端到所有Eureka服务端的连接总数200eurekaServerTotalConnectionsPerHost从Eureka客户端到每个Eureka服务端主机的连接总数50eurekaConnectionIdleTimeoutSecondsEureka服务端连接的空闲关闭时间;单位为秒30heartbeatExecutorThreadPoolSize心跳连接池的初始化线程数2heartbeatExecutorExponentialBackOffBound心跳超时重试延迟时间的最大乘数值10cacheRefreshExecutorThreadPoolSize缓存刷新线程池的初始化线程数2cacheRefreshExecutorExponentialBackOffBound缓存刷新重试延迟时间的最大乘数值10useDNSForFetchingServiceUrls使用DNS来获取Eureka服务端的serviceUrlfalseregisterWithEureka是否要将自身的实例信息注册到Eureka服务端truepreferSameZoneEureka是否偏好使用处于相同Zone的Eureka服务端truefilterOnlyUpInstances获取实例时是否过滤;仅保留UP状态的实例truefetchRegistry是否从Eureka服务端获取注册信息true

服务实例类配置

eureka.instance.instanceId为实例的id;可以自定义;默认值为

${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}

省略了eureka.instance为前缀

参数名说明默认值preferIpAddress是否优先使用IP地址作为主机名的标识falseleaseRenewalIntervalInSecondsEureka客户端向服务端发送心跳的时间间隔;单位为秒30leaseExpirationDurationInSecondsEureka服务端在收到最后一次心跳之后等待的时间上限;单位为秒。超过该时间之后服务端会将该服务实例从服务清单中剔除;从而禁止服务调用请求被发送到该实例上90nonSecurePort非安全的通信端口号80securePort安全的通信端口号443nonSecurePortEnabled是否启用非安全的通信端口号truesecurePortEnabled是否启用安全的通信端口号appname服务名;默认取spring.application.name的配置值;如果没有则为unknownhostname主机名;不配置的时候讲根据操作系统的主机名来获取

注册服务到Eureka

回到之前写的provider-demo项目中;在项目中添加下面这个依赖;注意version;

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <version>RELEASE</version>
</dependency>

在之前的SpringCloud版本中;还有出现过下面的依赖;但是目前最新的版本是上面这个;亲测;在本示例中两个都是可以的。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>RELEASE</version>
</dependency>

然后在项目的启动类上添加;EnableEurekaClient注解

;SpringBootApplication
;EnableEurekaClient
public class ProviderDemoApplication {

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

从依赖的名字spring-cloud-starter-netflix-eureka-client的名字就知道这个依赖是用来做eureka的客户端;然后注册服务到eureka上的。然后在项目的启动类上的添加的注解为;EnableEurekaClient

回到上文中会发现搭建eureka注册中心的时候会发现引入的包是spring-cloud-starter-netflix-eureka-server;在项目的启动类上的添加的注解为;EnableEurekaServer还是很好记忆和理解的。

最后在yml文件中添加上eureka注册中心的地址并可以了;

server:
  port: 7900
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

分别启动一下eureka和provider项目;然后访问一下localhost:8761便会得到下面的页面;
搭建一个SpringCloud

可以看到provider的服务已经注册上eureka上了。
发现application的名称为UNKNOWN;可以在yml文件中添加下面内容修改名字;

spring:
  application:
    name: provider-demo

重启一下服务便可以看到名字;这里就不贴图片了。

有可能会遇到下面的红色字体;

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.

这个主要是eureka的自我保护的心跳机制导致的;即如果真实的服务已经Down掉;但在注册中心界面服务却一直存在;且显示为UP状态。解决方法可以添加下面内容;上面有eureka的配置信息中解释含义;

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    lease-renewal-interval-in-seconds: 1
    lease-expiration-duration-in-seconds: 2

服务监控

对于服务的众多信息可能都需要监控和监听;SpringCloud主要采用的是下面这个依赖对其实现监听的;

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

添加这个依赖之后重启服务会发现console中多了下图这几个端点;

SpringCloud学习笔记(一)

/actuator/health和/actuator/info以及/actuator这三个就是actuator提供的端点;注意以前的版本是没有/actuator前缀的;2.0以后的版本都加了/actuator前缀。可以访问localhost:7900/actuator尝试看监听的都是一些什么内容

如果要开启全部的监听端点;可以在yml文件中加入下面的配置信息;

management:
  endpoints:
    web:
      exposure:
        include: ;*;

重启服务便可以看到所有的端点都开启用了。

主要的端点的含义可以参考下面的表格;

端点描述actuator为其他端点提供“发现页面”。要求Spring HATEOAS在classpath路径上。auditevents陈列当前应用程序的审计事件信息。autoconfig展示自动配置信息并且显示所有自动配置候选人以及他们“被不被”应用的原因。beans显示应用程序中所有Spring bean的完整列表。configprops显示所有配置信息。dumpdump所有线程。env陈列所有的环境变量。flywayShows any Flyway database migrations that have been applied.health显示应用程序运行状况信息info显示应用信息。loggers显示和修改应用程序中的loggers配置。liquibase显示已经应用的任何Liquibase数据库迁移。metrics显示当前应用程序的“指标”信息。mappings显示所有;RequestMapping的url整理列表。shutdown关闭应用;默认情况下不启用;。trace显示跟踪信息;默认最后100个HTTP请求;。

使用同样的方法把consumer-demo一起注册到Eureka上。

ribbon

上文只是将服务注册到eureka上;但是consumer还是硬编码调用;前文也有提到这种硬编码方式肯定是不合理的;一来服务上线之后;IP地址肯定是变动的; 再则;采用硬编码的方式是无法实现负载均衡的。

ribbon便是一个用来做负载均衡的组件。

点进spring-cloud-starter-netflix-eureka-client依赖;会发现;这个依赖中已经添加了spring-cloud-starter-netflix-ribbon;故在项目中可以直接使用ribbon;不用重新添加依赖。

在加载restTemplates的方法上添加;LoadBalanced注解;使其具有负载均衡的能力;然后将硬编码的ip地址换成服务提供者的应用名字;application.name属性的值;;修改之后controller便变成了下面的样子;其他地方不做修改。

;RestController
public class ConsumerController {

    ;Bean
    ;LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    ;Autowired
    private RestTemplate restTemplate;

    ;RequestMapping(;/consumer/demo;)
    public String ConsumerDemo(){
        return this.restTemplate.getForObject(;http://provider-demo:7900/provider/demo;, String.class);
    }

}

重启一下Eureka;provider-demo;consumer-demo;分别访问localhost:7900/provider/demohttp://localhost:7910/consumer/demo应该都能得到ProviderDemo 这个结果;说明consumer成功调用了provider中的方法。便解决了不采用硬编码的方式;使得consumer-demo调用provider-demo接口。

ribbon默认的负载均衡策略是轮询的。测试一下;

首先启动多个provider-demo项目;我这里分别用的接口是7900和7901两个接口;可以在Eureka中看一下provider的信息;

搭建一个SpringCloud

然后在consumer-demo项目的controller中添加下面的内容;代码应该很容易看懂就是模拟loadBalancerClient客户端来访问名字为provider-demo的服务接口;然后输出访问的接口端口号。

 ;Autowired
 private LoadBalancerClient loadBalancerClient;

 ;RequestMapping(;/consumer/getInterfaceInfo;)
 public void getInterfaceInfo(){
     ServiceInstance choose = loadBalancerClient.choose(;provider-demo;);
     System.out.println(choose.getPort());
 }

然后分别访问一下多次访问localhost:7910//consumer/getInterfaceInfo这个URL;可以看到控制台输出的信息在下面;很容易看出是轮询。

7901
7900
7901
7900
7901
7900
7901
7900
7901
7900
7901

ribbon有多种修改负载均衡的策略;可以通过代码;也可以通过配置文件;个人觉得配置文件的方法比较方便;其他的方法可以自行百度;

在consumer-demo的application.yml文件中添加下面的内容;这里使用的是随机的策略;该测试就不贴图了;反正最后结果是随机的;

#服务提供者的名字
provider-demo:  
  ribbon:
    # 所要采用的策略
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

ribbon所有的策略可以参照下表;

策略名策略描述实现说明BestAvailableRule选择一个最小的并发请求的server逐个考察Server;如果Server被tripped了;则忽略;在选择其中ActiveRequestsCount最小的serverAvailabilityFilteringRule过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server;并过滤掉那些高并发的的后端server;active connections 超过配置的阈值;使用一个AvailabilityPredicate来包含过滤server的逻辑;其实就就是检查status里记录的各个server的运行状态WeightedResponseTimeRule根据响应时间分配一个weight;响应时间越长;weight越小;被选中的可能性越低。一个后台线程定期的从status里面读取评价响应时间;为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行;没有形成status时;使用roubine策略选择server。RetryRule对选定的负载均衡策略机上重试机制。在一个配置时间段内当选择server不成功;则一直尝试使用subRule的方式选择一个可用的serverRoundRobinRuleroundRobin方式轮询选择server轮询index;选择index对应位置的serverRandomRule随机选择一个server在index上随机;选择index对应位置的serverZoneAvoidanceRule复合判断server所在区域的性能和server的可用性选择server使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server;前一个判断判定一个zone的运行性能是否可用;剔除不可用的zone;的所有server;;AvailabilityPredicate用于过滤掉连接数过多的Server。

加载全部内容

相关教程
猜你喜欢
用户评论
快盘暂不提供评论功能!