SpringBoot day04

一个中心 :eureka
两个配置:hystrix ribbon
三个集成工具:feign zuul config
四个监控工具:tubbin ,hystrix dashboard

zuul API网关

相当于一个代理,
在这里插入图片描述
1 统一的调用入口
2 统一的权限校验(过滤器)
将权限的判断放在网关,后台只负责代码逻辑的编写
3 可以集成hystrix和ribbon

统一的调用入口

相当于一个代理
1 依赖
1.添加zuul依赖
2 eureka client依赖
3 common依赖
2 yml配置

spring:
  application:
    name: zuul
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

zuul:
  routes:
    item-service: /item-service/**
    user-service: /user-service/**
    order-service: /order-service/**

配置路由转达规则:

zuul:
  routes:
    item-service: /item-service/**  
    user-service: /user-service/**
    order-service: /order-service/**
默认配置路径    根据注册表的注册信息,自动配置    一般需要手动配置,因为注册表的注册信息可能不全(有一些服务可能没有启动)
 #   XX服务名:/子路径 /XX     *单层子路径,**深层路径

3 主程序添加注解
添加 @EnableZuulProxy 和 @EnableDiscoveryClient 注解
4 启动服务,访问测试
http://eureka1:2001

http://localhost:3001/item-service/35

http://localhost:3001/item-service/decreaseNumber
使用postman,POST发送以下格式数据:
[{“id”:1, “name”:“abc”, “number”:23},{“id”:2, “name”:“def”, “number”:11}]

http://localhost:3001/user-service/7

http://localhost:3001/user-service/7/score?score=100

http://localhost:3001/order-service/123abc

http://localhost:3001/order-service/
在这里插入图片描述
在这里插入图片描述

zuul + ribbon 负载均衡

zuul 已经集成了 ribbon,默认已经实现了负载均衡,没有重试

zuul + ribbon 重试

1 pom.xml 添加 spring-retry 依赖

<dependency>
	<groupId>org.springframework.retry</groupId>
	<artifactId>spring-retry</artifactId>
</dependency>

2 配置 zuul 开启重试,并配置 ribbon 重试参数
需要开启重试,默认不开启,重试有默认参数
默认一次重试,跟换服务器一次

spring:
  application:
    name: zuul
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

zuul:
  retryable: true

#  routes:
#    item-service: /item-service/**
#    user-service: /user-service/**
#    order-service: /order-service/**
    
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 1000
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 1

zuul + hystrix 降级

在这里插入图片描述

创建降级类
getRoute() 方法中指定应用此降级类的服务id,星号或null值可以通配所有服务
ItemServiceFallback
在这里插入图片描述

package cn.tedu.sp11.fallback;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import cn.tedu.web.util.JsonResult;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class ItemServiceFallback implements FallbackProvider {
	@Override
	public String getRoute() {
	    //当执行item-service失败,
	    //应用当前这个降级类
		return "item-service";
		//星号和null都表示所有微服务失败都应用当前降级类
		//"*"; //null;
	}

    //该方法返回封装降级响应的对象
    //ClientHttpResponse中封装降级响应
	@Override
	public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return response();
	}

	private ClientHttpResponse response() {
        return new ClientHttpResponse() {
            //下面三个方法都是协议号
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }
            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }
            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }

            @Override
            public void close() {
            }

            @Override
            public InputStream getBody() throws IOException {
            	log.info("fallback body");
            	String s = JsonResult.err().msg("后台服务错误").toString();
                return new ByteArrayInputStream(s.getBytes("UTF-8"));
            }

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

OrderServiceFallback

package cn.tedu.sp11.fallback;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import cn.tedu.web.util.JsonResult;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class OrderServiceFallback implements FallbackProvider {
	@Override
	public String getRoute() {
		return "order-service"; //"*"; //null;
	}

	@Override
	public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return response();
	}

	private ClientHttpResponse response() {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }
            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }
            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }

            @Override
            public void close() {
            }

            @Override
            public InputStream getBody() throws IOException {
            	log.info("fallback body");
            	String s = JsonResult.err().msg("后台服务错误").toString();
                return new ByteArrayInputStream(s.getBytes("UTF-8"));
            }

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


package cn.tedu.sp11.fallback;

import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

@Component
public class ItemFB implements FallbackProvider {
    @Override
    public String getRoute() {
       //返回一个serviceId  针对指定服务进行降级处理
        //只针对商品降级  不对order和user进行降级
        //返回“*” 或null,对所有服务都应用这个降级类
        return "item-service";
    }
    //降级的响应,返回一个封装响应的response对象
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {

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

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                //设置协议体   JsonResult{code:401,msg:调用商品服务失败,data:null}
               String json=
                       JsonResult.err().msg("商品调用失败").toString();
                return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
            }

            @Override
            public HttpHeaders getHeaders() {
                //设置协议头  Content-Type:application/json;charset=UTF-8
                HttpHeaders h=new HttpHeaders();
                h.add("Content-type","application/json;charset=UTF-8");
                return h;
            }
        } ;
    }
}

订单降级类

package cn.tedu.sp11.fallback;

import cn.tedu.web.util.JsonResult;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@Component
public class OrderFB implements FallbackProvider {
    @Override
    public String getRoute() {
        //返回一个serviceId  针对指定服务进行降级处理
        //只针对商品降级  不对order和user进行降级
        //返回“*” 或null,对所有服务都应用这个降级类
        return "order-service";
    }
    //降级的响应,返回一个封装响应的response对象
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {

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

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                //设置协议体   JsonResult{code:401,msg:调用商品服务失败,data:null}
                String json=
                        JsonResult.err().msg("订单调用失败").toString();
                return new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8));
            }

            @Override
            public HttpHeaders getHeaders() {
                //设置协议头  Content-Type:application/json;charset=UTF-8
                HttpHeaders h=new HttpHeaders();
                h.add("Content-type","application/json;charset=UTF-8");
                return h;
            }
        } ;
    }
}

在这里插入图片描述

降低 hystrix 超时时间,以便测试降级

spring:
  application:
    name: zuul
    
server:
  port: 3001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

zuul:
  retryable: true
    
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 2000
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 1
  
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 500

启动服务,测试降级
http://localhost:3001/item-service/35
在这里插入图片描述

zuul + hystrix 数据监控

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

暴露 hystrix.stream 监控端点
zuul 已经包含 actuator 依赖

management:
  endpoints:
    web:
      exposure:
        include: hystrix.stream

turbbin上加暴露的服务:
在这里插入图片描述

启动服务,查看暴露的监控端点
http://localhost:3001/actuator
http://localhost:3001/actuator/hystrix.stream
开启监控
启动 sp08-hystrix-dashboard,填入 zuul 的监控端点路径,开启监控

http://localhost:4001/hystrix

填入监控端点:
http://localhost:3001/actuator/hystrix.stream
在这里插入图片描述
使用turbine进行联合数据监控:测试代码顺序
在这里插入图片描述
监控数据显示:
在这里插入图片描述

必须通过zuul网关访问后台服务才会长生监控数据

http://localhost:3001/item-service/35

http://localhost:3001/item-service/decreaseNumber
使用postman,POST发送以下格式数据:
[{“id”:1, “name”:“abc”, “number”:23},{“id”:2, “name”:“def”, “number”:11}]

http://localhost:3001/user-service/7

http://localhost:3001/user-service/7/score?score=100

http://localhost:3001/order-service/123abc

http://localhost:3001/order-service/

zuul + turbine 聚合监控
修改 turbine 项目,聚合 zuul 服务实例


spring:
  application:
    name: turbin
    
server:
  port: 5001
  
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
      
turbine:
  app-config: order-service, zuul
  cluster-name-expression: new String("default")

使用hystrix仪表盘, 对 turbine 监控端点进行监控, 此端点聚合了订单服务和zull网关服务的监控数据
http://localhost:5001/turbine.stream
在这里插入图片描述

熔断测试
ab -n 20000 -c 50 http://localhost:3001/order-service/123abc
在这里插入图片描述

统一的权限校验

通过zuul提供的过滤器判断用户权限,后台服务不需要判断权限,值关注业务就可以

zuul提供一个过滤器,可以继承过滤器,在子类中添加权限判断

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

package cn.tedu.sp11.filter;

import cn.tedu.web.util.JsonResult;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;


import javax.servlet.http.HttpServletRequest;

@Component
public class AccessFilter extends ZuulFilter {
    //过滤器类型   pre,post,routing,error  前置,后置,路由,错误
    @Override
    public String filterType() {
        //前置过滤器   前置过滤器中有五个默认过滤器,将自定义过滤器放在第六个
        return FilterConstants.PRE_TYPE;
    }
   //过滤器插入的位置
    @Override
    public int filterOrder() {
        return 6;
    }
   //返回一个布尔值,对用户的请求进行判断,是否执行过滤器
    @Override
    public boolean shouldFilter() {
        /**
         * 只对item-service 调用进行过滤
         * 如果user-service order-service 不进行过滤代码
         * */
        //获取调用的服务id
        RequestContext ctx=RequestContext.getCurrentContext();
        String serviceId = (String)ctx.get(FilterConstants.SERVICE_ID_KEY);

        return "item-service".equalsIgnoreCase(serviceId);
    }
    //执行过滤代码
    @Override
    public Object run() throws ZuulException {
        //获取request对象
        RequestContext ctx=RequestContext.getCurrentContext();
        HttpServletRequest request=ctx.getRequest();
        //获取token参数
        String token=request.getParameter("token");
        //如果没有token,直接访问,并直接向客户端返回响应
        if(StringUtils.isBlank(token)){
            //阻止继续访问
            ctx.setSendZuulResponse(false);
            //向客户端的响应
            String json=
                    JsonResult.
                            err()
                    .code(JsonResult.NOT_LOGIN)
                    .msg("not login")
                    .toString();

            ctx.addZuulResponseHeader("Content-Type", "application/json;charset:UTF-8");
            ctx.setResponseBody(json);

        }
        return null;
    }
}

访问测试
没有token参数不允许访问
http://localhost:3001/item-service/35

有token参数可以访问
http://localhost:3001/item-service/35?token=1234

自定义过滤器必须加载第六个,在第五个过滤器中在上下文对象中添加了serviceId,后面的过滤器才能访问serviceId

zuul和feign

在这里插入图片描述

尽量在zuul中加hystrix??
尽量不要在所有后台处理服务上加hystrix,会造成混乱,不知道服务究竟在哪里发生的熔断降级
应该在最前面加hystrix,比如zuul中
为什么zuul中不加重试??
会加大访问压力,每次失败都会重新连接,加上新的访问,后台所有访问压力倍增,所以重试尽量加载最后面

配置中心 Config

所有服务的配置文件都集中存放在配置中心,所有服务启动时都需要先连接配置中心进行下载
配置中心都放在git仓库,配置中心启动时先连接git仓库,clone下配置文件
在这里插入图片描述
在这里插入图片描述
yml 配置文件保存到 git 服务器,例如 github.com 或 gitee.com

微服务启动时,从服务器获取配置文件

git仓库存放所有的配置文件

2,3,4,11项目的application.yml放在git仓库
准备本地仓库
1.新建Directory:config
在这里插入图片描述
在这里插入图片描述
2. 复制2,3,4,11项目的application.yml到config目录下
在这里插入图片描述

—item-service-dev.yml dev profile
—user-service-dev.yml
—order-service-dev.yml
—zuul-dev.yml
3 .添加配置,防止注册中心的注册信息覆盖本地命令行配置
在这里插入图片描述
配置中心的配置优先级最高,会覆盖本地配置和本地命令行配置 此时8002端口配置失效

#以本地配置为主
spring:
  ......
  cloud:
    config:
      override-none: true

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
仓库的设置:
1 将工程设置为本地仓库 springcloud1
2 将文件夹设置为本地仓管 这样就会一个仓库中有多个project springcloud1和springcloud2和springcloud3在一个仓库
新建远程仓库:
在这里插入图片描述
复制远程仓库地址:
在这里插入图片描述
在idea把本地库推送到远地
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

搭建配置中心

1.添加config server依赖
2 yml配置
eureka注册
配置git仓库地址,和仓库里的子目录
3.启动类注解 @Enable

创建项目

在这里插入图片描述

<?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 https://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.2.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>cn.tedu</groupId>
	<artifactId>sp12-config</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>sp12-config</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.RELEASE</spring-cloud.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-config-server</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</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>

</project>

spring:
  application:
    name: config-server

  cloud:
    config:
      server:
        git:
          uri: https://github.com/yinxia1/springcloud1
          searchPaths: config
          #username: your-username
          #password: your-password

server:
  port: 6001

eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

主程序添加 @EnableConfigServer 和 @EnableDiscoveryClient

package cn.tedu.sp12;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer;

@EnableConfigServer
@EnableDiscoveryClient
@SpringBootApplication
public class Sp12ConfigApplication {

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

}

启动,访问测试
访问 item-service-dev.yml 可以使用以下形式:

http://localhost:6001/item-service-dev.yml
在这里插入图片描述

http://localhost:6001/item-service/dev
在这里插入图片描述

测试其他文件

http://localhost:6001/user-service/dev
在这里插入图片描述

http://localhost:6001/zuul/dev
在这里插入图片描述

http://localhost:6001/order/dev
在这里插入图片描述

config 客户端

修改以下项目,从配置中心获取配置信息

sp02-itemservice
sp03-userservice
sp04-orderservice
sp11-zuul
pom.xml 添加 config 客户端依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-config</artifactId>
</dependency>

在四个项目中添加 bootstrap.yml
bootstrap.yml,引导配置文件,先于 application.yml 加载
item-service

spring: 
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config-server
      name: item-service
      profile: dev
      
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

user-service

spring: 
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config-server
      name: user-service
      profile: dev
      
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

order-service

spring: 
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config-server
      name: order-service
      profile: dev
      
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

zuul

spring: 
  cloud:
    config:
      discovery:
        enabled: true
        service-id: config-server
      name: zuul
      profile: dev
      
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka

启动服务,观察从配置中心获取配置信息的日志
在这里插入图片描述
在这里插入图片描述

虚拟机

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

systemctl stop NetworkManager
systemctl disable NetworkManager
在这里插入图片描述

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值