SpringCloud基础框架快速搭建及几个基础组件的使用介绍

SpringCloud是个啥我就不说了,直接进入正题。

1.Eureka

Eureka作为SpringCloud的注册中心,有着非常重要的作用,所有的服务都需要在注册之后,才能被注册中心发现,从而供其他的服务调用。除了Eureka之外,SpringCloud还支持Consul、Zookeeper作为注册中心。这里简单记录一下开发步骤:

1.创建maven项目
2.new一个module,导入eureka server,这个时候就自动把需要的依赖包下好
3.在application启动类中添加注解 @EnableEurekaServer,声明其为注册中心
4.写yml配置文件,启动即可
关于Eureka的搭建,我之前找到过一篇比较详细的文章,这里就不做赘述,网址如下:
https://blog.csdn.net/zhou199252/article/details/80745151

下面是我在搭建高可用Eureka时的配置,贴出来供参考:

spring:
  application:
    name: spring-cloud-eureka
  profiles: peer1
server:
  port: 8761    #服务端口
eureka:
  instance:
    hostname: peer1               #与此实例相关联的主机名,是其他实例可以用来进行请求的准确名称
  client:
#    registerWithEureka: false       #服务器自己不注册自己: 实例是否在eureka服务器上注册自己的信息以供其他服务发现,默认为true
#    fetchRegistry: false            #服务器自己不获取自己信息:此客户端是否获取eureka服务器注册表上的注册信息,默认为true
    serviceUrl:
      defaultZone: http://peer2:8762/eureka/			#再做高可用的时候注册到另一EurekaServer上
#注册中心配置结束

#搭建高可用的eureka集群,搭建高可用集群的时候配置registerWithEureka、fetchRegistry为true,或不配置(默认为true),供其他eureka注册中心发现
---
server:
  port: 8762
spring:
  application:
    name: spring-cloud-eureka
  profiles: peer2
eureka:
  instance:
    hostname: peer2
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/

2.Ribbon

在springCloud构建的微服务系统中,Ribbon作为负载均衡器。他有两种使用方式,一是和RestTemplate结合,另一种是和Feign相结合

ribbon目前主要的几个子模块:
ribbon-loadbalancer:可独立使用或与其他模块一起使用的负载均衡器API
ribbon-eureka:Ribbon结合Eureka客户端的API,为负载均衡器提供动态服务注册列表信息
ribbon-core:Ribbon的核心API

这里先讲讲ribbon结合RestTemplate,demo如下:(需要在Eureka所需依赖基础上额外引入Spring-cloud-starter-ribbon的依赖包)

/**
* restTemplate结合Ribbon,开启负载均衡功能
*/
@Configuration
public class RibbonConfig {
	@Bean
	@LoadBalanced
	RestTemplate restTemplate(){
		return new RestTemplate();
	}
}

如上就实现了restTemplate和Ribbon结合,只要在service层注入restTemplate,直接调用服务即可,如下
@Service
public class HelloService {
	@Autowired
	RestTemplate restTemplate;

/**
* 调取生产者的服务接口
* @param name
* @return
*/
	public String hiService(String name)
	{
		return restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class); //调取服务名为SERVICE-HI的服务,将返回的json字符串转换成一个String对象
	}
}

这里简单说一下Ribbon的原理:
Ribbon通过LoadBalancerClient来实现负载均衡,而LoadBalancerClient具体交给ILoadBalancer来处理,ILoadBalancer通过配置IRule、IPinng等,向EurekaClient获取注册列表的信息,默认10秒钟向EurekaClient发送一次Ping,来检查是否需要更新注册列表信息。最后,ILoadBalancer根据IRule的策略进行负载均衡。
RestTemplate上加@LoadBalanced之后在远程调度的时候可以实现负载均衡,主要是在远程调度方法前加拦截器,把调度方法交由负载均衡器处理。

3.Feign

Ribbon除了结合RestTemplate在消费服务时做负载均衡外,还可以通过Ribbon和Feign相结合的方式来实现。
Feign目标是使Http客户端调用过程变得简单,采用声明式API接口的风格,将Http客户端绑定到它的内部

Feign开发步骤如下:(需要引入Feign的起步依赖:spring-cloud-starter-feign)

1.启动类中添加注解@EnableFeignClients
/**
 * Feign启动类
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients         //开启FeignClient功能
public class EurekaFeignClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaFeignClientApplication.class, args);
    }
}
 2.编写调用类
@Component
@FeignClient(value = "service-hi",configuration = FeignConfig.class) //value是远程调用的其他服务名  FeignConfig.class为FeignClient的配置类
public interface EurekaClientFeign {
	@GetMapping(value = "/hi")
	String sayHiFromClientEureka(@RequestParam(value = "name")String name);
}

配置类FeignConfig ,如下:
@Configuration
public class FeignConfig {
	@Bean //注入Retryer,注入该bean后,Feign在远程调用失败后会进行重试
	public Retryer feignRetryer(){
		return new Retryer.Default(100,SECONDS.toMillis(1),5);
	}
}

 3.编写controller,编写service,sevice调用这里的sayHiFromClientEureka方法

4.Hystrix

Hysyrix是为了解决分布式服务中的雪崩效应:
在分布式服务中,业务错综复杂,各个服务相互依赖,如果其中某个服务故障或者挂掉了,会导致所有请求该服务的线程处于阻塞状态,可能会在短时间内造成大量的资源消耗,导致整个系统的不可用,这就是服务的雪崩效应。Hystrix熔断器在单个服务出现问题的时候,采用快速失败机制来防止大量线程阻塞,或者通过预先设计好的回退方案转接到其他方法的方式来防止雪崩。

Hystrix熔断器工作原理:
当服务的某个API接口失败次数在一定时间内小于设定的阈值时,熔断器处于关闭状态,API接口正常提供服务;当失败次数大于阈值时,Hystrix判定接口出现故障,熔断器打开,此时请求该API接口会执行快速失败的逻辑(即fallback回退逻辑)。一段时间后,处于打开状态的熔断器会处于半打开状态,并将一部分的请求执行正常逻辑,如果执行成功了,就打开熔断器,如果失败,就关闭熔断器,这样就实现了熔断器的自我修复功能。

这里分别就在Restemplate和Feign上使用熔断器做一个记录:
4.1.RestTemplate和Ribbon上使用熔断器:

 1.导入熔断器起步依赖spring-cloud-starter-hystrix,在启动类添加注解@EnbaleHystrix
 2.在要加熔断器的方法上加@HystrixCommand注解,指定回退方法,如下,此时熔断器配置完毕
@Service
public class HelloService {
	@Autowired
	RestTemplate restTemplate;

	/**
	* 调取生产者的服务接口
	* @param name
	* @return
	*/
	@HystrixCommand(fallbackMethod = "hiError") //熔断器器配置,当无法调用如下方法时,会调用自定义的hiError方法,fallbackMethod即处理回退逻辑的方法
	public String hiService(String name)
	{
		return restTemplate.getForObject("http://SERVICE-HI/hi?name=" + name, String.class); //
	}

	//回退逻辑不用写的很复杂,方便快速失败,释放线程资源,不建议在回退逻辑里调用其他服务,如果实在要调用,建议再加个熔断器
	public String hiError(String name)
	{
		return "hey " +name + ", there is some problem with hi page";
	}
}

4.2在Feign上使用熔断器:
注意:Feign的依赖spring-cloud-starter-feign的pom文件中默认引入了熔断器Hystrix和负载均衡Ribbon的依赖,实现了服务熔断和负载均衡,所以这里不需要再重复导包

1.在application.yml中添加配置,如下:
feign:
    hystrix:
        enabled: true
2.在feign调用服务的方法前的注解中指定回退处理类,如下:
@Component
@FeignClient(value = "service-hi",configuration = FeignConfig.class,fallback = HiHystrix.class)
//value是远程调用的其他服务名FeignConfig.class为FeignClient的配置类,fallback指定熔断器快速失败的处理类,这个类需要继承这里的EurekaClientFeign接口
public interface EurekaClientFeign {
	@GetMapping(value = "/hi")
	String sayHiFromClientEureka(@RequestParam(value = "name")String name);
}
3.回退处理类中重写方法,如下:
/**
* 熔断器快速失败处理类,需要继承Feign调用服务的接口类,并把回退逻辑实现在重写的方法里面
*/
@Component
public class HiHystrix implements EurekaClientFeign{
	@Override
	public String sayHiFromClientEureka(String name) {
		return "hi,"+name+",sorry,error!";
	}
}

4.3在SpringCluod中可以用Hystrix Dashboard监视熔断器状态
先说一下在restTemplate中使用Hystrix DashBoard步骤:
1.添加起步依赖hystrix、Hystrix DashBoard、Actuator
2.启动类添加@EnableHystrixDashboard注解,即可



org.springframework.cloud
spring-cloud-starter-hystrix
1.4.4.RELEASE




org.springframework.boot
spring-boot-starter-actuator


org.springframework.cloud
spring-cloud-starter-hystrix-dashboard
1.4.5.RELEASE

/**
* Eureka消费者
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableHystrixDashboard //开启Hystrix Dashboardg功能,用来对熔断器做状态监控
public class ConsumerApplication {
	public static void main(String[] args) {
		SpringApplication.run(ConsumerApplication.class, args);
	}
}

在Feign中使用Hystrix DashBoard步骤:
1.添加起步依赖hystrix、Hystrix DashBoard、Actuator
2.启动类添加@EnableHystrixDashboard注解,即可
步骤和在Restemplate类似,这里不做赘述,注意Feign中添加HystrixDashBoard时需要引入hystrix和Actuator依赖,因为它自带的并不是原生的。

Turbine聚合监视熔断器状态
Hystrix DashBoard每个服务都有一个监控主页,主页不是很方便,服务多了不利于监控,netflix开源了另一个组件Turbine,用于聚合监控多个Hystrix DashBoard,将多个Hystrix DashBoard组件的数据放在同一个页面上监控。有兴趣的同学可以去了解下,碍于篇幅这里就不记录了。

5.Zuul

Zuul作为微服务的网关组件,用于构建边界服务(Edge Service),致力于动态路由、过滤、监控、弹性伸缩和安全
Zuul网关的几个主要作用:
1.对外统一暴露API接口,调用者不需要知道内部服务之间是怎么调用的,避免敏感信息被外界获取
2.与Ribbon、Eureka结合可实现负载均衡和智能路由功能
3.可做流量监控,必要时进行服务降级,提供请求监控功能,实时日志输出,对请求进行记录
4.可用来做身份认证和权限认证,防止非法请求操作API接口,对服务器起到保护作用

Zuul的核心是一系列的过滤器,可在Http请求的发起和响应返回期间执行过滤器,主要包含以下四种:
PRE过滤器:请求路由到具体服务前执行,可用来做安全验证
ROUTING过滤器:用于将请求路由到具体的微服务实例
POST过滤器:用于在请求已被路由到微服务之后执行,可用来做信息收集统计等
ERROR过滤器:在其他过滤器发生错误时执行

5.1简单记录一下Zuul的开发步骤:
1.导依赖zuul、eureka、springboot-web、springboot-test
2.启动类添加注解@EnbaleZuulProxy
3.写配置文件,如下

spring:
    application:
        name: service-zuul
server:
    port: 5000
eureka:
    client:
        service-url:
            defaultZone: http://peer1:8761/eureka/
zuul:
    routes:
        hiapi: #制定好path和serviceId,所有以path开头的请求都会被路由到对应的服务。如下面/hiapi/**被路由到service-hi对应的服务,/ribbonapi/**被路由到service-ribbon对应的服务
            path: /hiapi/**
            serviceId: service-hi
        ribbonapi:
            path: /ribbonapi/**
            serviceId: service-ribbon
    prefix: /v1 #配置版本号,至此url请求地址变成:http://localhost:5000/v1/ribbonapi/**

至此,一个简单的Zuul demo就配好了,可以试着访问http://localhost:5000/v1/hiapi/****,会调用ID为service-hi的服务对应接口。

5.2.Zuul上配置熔断器:
zuul上配置熔断器需要继承ZuulFallbackProvider接口,这个接口里有两个方法,一个是getRoute(),用于指定熔断器应用于哪些服务,还有一个fallbackResponse()方法,用于做进入熔断功能时执行的逻辑

@Component
class MyFallbackProvider implements ZuulFallbackProvider {
@Override
public String getRoute() {
    return "service-ribbon";
}
如上表示熔断器应用于id为service-ribbon的服务,如果需要应用于所有服务,可以改成return "*";

@Override
public ClientHttpResponse fallbackResponse() {
    return new ClientHttpResponse() {
        @Override
        public HttpStatus getStatusCode() throws IOException {
            return HttpStatus.OK;
        }

        @Override
        public int getRawStatusCode() throws IOException {
            return 200;
        }

        @Override
        public String getStatusText() throws IOException {
            return "OK";
        }

        @Override
        public void close() {

        }

        @Override
        public InputStream getBody() throws IOException {
            return new ByteArrayInputStream("oooops!errpr,i'm the fallback.".getBytes());
        }

        @Override
        public HttpHeaders getHeaders() {
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            return httpHeaders;
        }
    };
}
}

5.3.Zuul配置过滤器:
需要继承ZuulFilter接口, 具体代码如下:

/**
* zuul配置过滤器
*/
@Component
public class Myfitler extends ZuulFilter {
@Override
public String filterType() { //设置过滤类型:pre、post、routing、error
    return PRE_TYPE;
}

@Override
public int filterOrder() { //设置过滤顺序,值越小越早执行
    return 0;
}

@Override
public boolean shouldFilter() { //是否过滤逻辑,如果为true则执行run()方法,如果false,则不执行run()方法
    return true;
}

@Override
public Object run() throws ZuulException { //具体的过滤逻辑,这里检查请求参数中是否包含token参数,如果没有,就直接返回响应,不路由到具体服务,状态码401
    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
    Object accessToken = request.getParameter("token");
    if(accessToken == null){
        ctx.setSendZuulResponse(false);
        ctx.setResponseStatusCode(401);
        try {
            ctx.getResponse().getWriter().write("token is empty");
        }catch (Exception e){
            return null;
        }
    }
    return null;
}
}

6.Config

Config是微服务的配置中心,可以从本地仓库读取配置文件,也可以从远处git仓库读取。
6.1从本地读取配置步骤:
1创建maven工程,指定spring-boot版本为1.5.3,spring-cloud版本为Dalston.RELEASE,新建module,添加起步依赖spring-cloud-config-server
2在启动类上添加@EnableConfigServer注解,开启configServer功能
3配置application.yml

spring:
    cloud:
        config:
            server:
                native:
                    search-locations: classpath:/shared #指定本地读取的配置的路径:Resources目录下的shared文件夹
    profiles:
        active: native
    application:
        name: config-server
server:
    port: 8769

4Resources目录下创建shared文件夹,在文件夹中创建一个名为config-client-dev.yml的文件,用来填写配置信息,如下:

server:
    port: 8769
fool: fool version 1

5构建configClient,编辑配置文件bootstrao.yml( bootstrao.yml比 application.yml有优先的执行顺序),读取之前配置文件中的内容

spring:
    cloud:
        config:
            uri: http://localhost:8769
            fail-fast: true
    profiles:
        active: dev
    application:
        name: config-client
        
#spring-application-name和spring-profiles-active两者以“-”相连,构成了向ConfigServer读取的配置名,比如这里读取config-client-dev.yml

6.2.从远程git仓库读取配置
相比本地的好处是可以统一管理配置,并通过消息总线在不人工启动的情况下对配置进行刷新
其他步骤与本地一样,application.yml配置与配置在本地略有出入,如下:

spring:
    cloud:
        config:
            server:
                git:
                    url: https://github.com/forezp/SpringcloudConfig
                    searchPaths: respo        #搜索远程仓库的文件夹地址
                    username: aaa   #git用户名
                    password:  bbb   #git密码
            label: master        #指定从哪个分支读取
    application:
        name: config-server
server:
    port: 8769

6.3.构建高可用configServer
当服务实例很多时,所有服务都要从配置中心读取配置,这个时候就要考虑将configServer做成一个微服务,并将其集群化,从而达到高可用。主要做法是将configServer和ConfigClient注册到注册中心,并多实例部署configServer,实现负载均衡。步骤如下:
1.创建eureka注册中心
2.注册configServer,在原有配置的基础上往application中添加以下配置

eureka:
    client:
        serviceUrl:
            defaultZone: http://localhost:8761/eureka/

3.注册configClient,修改application.yml文件

spring:
    cloud:
        config:
            fail-fast: true
            discovery:
                endabled: true
                serviceId: config-server  #向服务名为config-server的配置服务读取配置文件
    profiles:
        active: dev
    application:
        name: config-client

4.开启多个configServer,实现高可用负载均衡

6.4.使用消息总线Spring Cloud Bus刷新配置
当配置中间开了很多个服务之后,更新配置需要开启多个服务,非常麻烦。通过消息总线就可以解决这个麻烦,配置了消息总线之后,只需要向其中一个服务发送“bus/refresh"Post请求,通过消息组件就可以通知其他的服务也去git仓库里读取更新配置。
可选取RabbitMQ、AMQP和Kafka作为消息总线。以RabbitMQ为例,步骤如下(安装rabbitmq服务器步骤这里不做阐述):
1.pom引入rabbitMQ依赖
2.application.yml中配置rabbitmq

spring:
	rabbitmq:
		host:localhost
		port:5672
		username:guest
		password:guest
management:
	security:
		enabled:false		#暂时先屏蔽安全验证
 3.启动类添加@RefreshScope注解。

至此就完成了消息总线的配置,通过发送http://localhost:8762/bus/refresh,就可以通知所有服务去重新读取配置了

7.SpringCloudSleuth

在微服务中,内部各个服务间调用关系经常是非常复杂的,一旦出现了错误和异常,将很难去定位是哪里发生的,这个时候就需要用到分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序是怎样的,从而去快速定位问题。
目前常见的追踪组件有Goolge的Dapper、Twitter的Zipkin,阿里的Eagleeye。这里介绍Zipkin
使用步骤如下:
1.编写ZipkinServer
1.1、添加zipkin-server依赖,添加zipkin的UI界面依赖
1.2、启动类上添加@EnbaleZipkinServer注解,开启ZipkinServer功能
1.3、编写配置文件,将此服务注册到注册中心

spring:
    application:
        name: zipkin-server
server:
    port: 9411
eureka:
    client:
        service-url:
            defaultZone: http://peer1:8761/eureka/

2.编写UserService提供服务
步骤和编写普通的eurekaClient基本一致,只是多引入zipkin的包,同时在配置文件中加入zipkin的配置,如下:

spring:
    application:
        name: user-service
    zipkin:
        base-url: http://localhost:9411/       #指定zipkinServer地址
    sleuth:
        sampler:
            percentage:  1.0         #以100%的概率将链路数据上传给ZipkinServer,默认为0.1
server:
    port: 8762
eureka:
    client:
        service-url:
            defaultZone: http://peer1:8761/eureka/

配置完之后再编写一个对外的api接口供调用。
3.编写Gateway Service
按常规步骤编写一个服务,引入eureka、zuul和zipkin,编写配置文件,如下

spring:
    application:
        name: gateway-service
    zipkin:
        base-url: http://localhost:9411/       #指定zipkinServer地址
    sleuth:
        sampler:
            percentage:  1.0         #以100%的概率将链路数据上传给ZipkinServer,默认为0.1
server:
    port: 5000
eureka:
    client:
        service-url:
            defaultZone: http://peer1:8761/eureka/
zuul:
    routes:
        api-a:
            path: /user-api/**
        serviceId: user-service

之后在启动类上添加eureka和zuul的启动注解。
浏览器通过网关访问user-service提供的接口,再访问http://localhost:9411/,即可打开zipkin的展示页面,查看此次的链路数据。应该可以看到gateway-service服务调用user-service服务的链路。
顺道提一下:
链路数据默认通过Http上传个zipkin-server,可通过消息组件rabbitMQ访问。
链路数据默认存储在内存中,但极易丢数据,可存在mysql、ElasticSearch、Cassandra上。有兴趣可以去了解下。

先写到这里吧…关于监控组件及安全组件,每个的篇幅都比较长,后面有时间专门重新写篇文章记录下。

你可能感兴趣的:(SpringCloud)