栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

微服务入门(一)微服务、Nacos、feign、gateway

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

微服务入门(一)微服务、Nacos、feign、gateway

前言

我前几年一直在做安卓,后来接触过小程序,最近几年开始接触spring boot,安卓和小程序比较技术比较专一,后台涉及面就很广了,最近做的项目多是CRUD,感觉比较单调,就开始学习微服务,主要学习资料是《谷粒商城》,之前也看过,当时也是脑子一热,有个印象,现在开发一年多后台以后,再看的话,稍微有点感觉,就把重点记录一下,不涉及具体编码,源码和课件可以在这个地方下载谷粒商城课件源码.rar,不过官方下载的代码不怎么全,哔站有人自己整理了一份,可以参考一下
Gulimall高级篇_持续更新中

微服务简介

先上一张谷粒商城-微服务架构图

微服务划分图

1、微服务

微服务架构风格, 就像是把一个单独的应用程序开发为一套小服务, 每个小服务运行在自己的进程中, 并使用轻量级机制通信, 通常是 HTTP API。 这些服务围绕业务能力来构建,并通过完全自动化部署机制来独立部署。 这些服务使用不同的编程语言书写, 以及不同数据存储技术, 并保持最低限度的集中式管理。
简而言之: 拒绝大型单体应用, 基于业务边界进行服务微化拆分, 各个服务独立部署运行。

2、集群&分布式&节点

集群是个物理形态, 分布式是个工作方式。只要是一堆机器, 就可以叫集群, 他们是不是一起协作着干活, 这个谁也不知道;“分布式系统是若干独立计算机的集合, 这些计算机对于用户来说就像单个相关系统”。分布式系统(distributed system) 是建立在网络之上的软件系统。分布式是指将不同的业务分布在不同的地方。集群指的是将几台服务器集中在一起, 实现同一业务。分布式中的每一个节点, 都可以做集群。 而集群并不一定就是分布式的。节点: 集群中的一个服务器

3、远程调用

在分布式系统中, 各个服务可能处于不同主机, 但是服务之间不可避免的需要互相调用, 我
们称为远程调用。SpringCloud 中使用 HTTP+JSON 的方式完成远程调用

4、负载均衡

分布式系统中, A 服务需要调用 B 服务, B 服务在多台机器中都存在, A 调用任意一个服务器均可完成功能。为了使每一个服务器都不要太忙或者太闲, 我们可以负载均衡的调用每一个服务器, 提升网站的健壮性。
常见的负载均衡算法:
轮询: 为第一个请求选择健康池中的第一个后端服务器, 然后按顺序往后依次选择, 直到最后一个, 然后循环。
最小连接: 优先选择连接数最少, 也就是压力最小的后端服务器, 在会话较长的情况下可以考虑采取这种方式。
散列: 根据请求源的 IP 的散列(hash) 来选择要转发的服务器。 这种方式可以一定程度上保证特定用户能连接到相同的服务器。 如果你的应用需要处理状态而要求用户能连接到和之前相同的服务器, 可以考虑采取这种方式。

5、服务注册/发现&注册中心

A 服务调用 B 服务, A 服务并不知道 B 服务当前在哪几台服务器有, 哪些正常的, 哪些服务已经下线。 解决这个问题可以引入注册中心;

如果某些服务下线, 我们其他人可以实时的感知到其他服务的状态, 从而避免调用不可用的服务

6、配置中心


每一个服务最终都有大量的配置, 并且每个服务都可能部署在多台机器上。 我们经常需要变更配置, 我们可以让每个服务在配置中心获取自己的配置。配置中心用来集中管理微服务的配置信息

7、服务熔断&服务降级

在微服务架构中, 微服务之间通过网络进行通信, 存在相互依赖, 当其中一个服务不可用时,有可能会造成雪崩效应。 要防止这样的情况, 必须要有容错机制来保护服务。
1) 、 服务熔断
a. 设置服务的超时, 当被调用的服务经常失败到达某个阈值, 我们可以开启断路保护机制, 后来的请求不再去调用这个服务。 本地直接返回默认的数据
2) 、 服务降级
a. 在运维期间, 当系统处于高峰期, 系统资源紧张, 我们可以让非核心业务降级运行。 降级: 某些服务不处理, 或者简单处理【抛异常、 返回 NULL、调用 Mock 数据、 调用 Fallback 处理逻辑】 。

8、API 网关

在微服务架构中, API Gateway 作为整体架构的重要组件, 它抽象了微服务中都需要的公共功能, 同时提供了客户端负载均衡, 服务自动熔断, 灰度发布, 统一认证, 限流流控, 日志统计等丰富的功能, 帮助我们解决很多 API 管理难题

项目搭建

项目结构如下

创建一个spring boot的project,gulimall,然后建立各个module,选择maven,然后project聚合module
gulimall的pom.xml配置



    4.0.0
    com.atguigu.gulimall
    >gulimall
    0.0.1-SNAPSHOT
    gulimall
    聚合服务
    pom

    
        gulimall-coupon
        gulimall-member
        gulimall-order
        gulimall-product
        gulimall-ware
        renren-fast
        renren-generator
        gulimall-common
    





gulimall-common是基础,其他Module引用这个,gulimall-common的pom.xml文件

   
        >gulimall
        com.atguigu.gulimall
        0.0.1-SNAPSHOT
    
    4.0.0

    >gulimall-common
    每一个微服务公共的依赖,bean,工具类等

其他module的pom.xml公共部分

   4.0.0
    
        org.springframework.boot
        >spring-boot-starter-parent
        2.1.8.RELEASE
         
    
    com.atguigu.gulimall
    >gulimall-order
    0.0.1-SNAPSHOT
    gulimall-order
    各模块描述

    
        1.8
        Greenwich.SR3
    

    
        
            com.atguigu.gulimall
            >gulimall-common
            0.0.1-SNAPSHOT
        
        ....
技术搭配方案


在gulimall-common引入SpringCloud Alibaba的依赖



    
        >gulimall
        com.atguigu.gulimall
        0.0.1-SNAPSHOT
    
    4.0.0

    >gulimall-common
    每一个微服务公共的依赖,bean,工具类等

    
    
        
            com.baomidou
            >mybatis-plus-boot-starter
            3.2.0
        

        
            org.projectlombok
            >lombok
            1.18.8
        

   
        
            org.apache.httpcomponents
            >httpcore
            4.4.12
        


        
            commons-lang
            >commons-lang
            2.6
        


        
            mysql
            >mysql-connector-java
            8.0.17
        

        
            javax.servlet
            >servlet-api
            2.5
            provided
        

  
        
            com.alibaba.cloud
            >spring-cloud-starter-alibaba-nacos-discovery
        

 
        
            com.alibaba.cloud
            >spring-cloud-starter-alibaba-nacos-config
        

        
            javax.validation
            >validation-api
            2.0.1.Final
        


    

    
        
            
                com.alibaba.cloud
                >spring-cloud-alibaba-dependencies
                2.1.0.RELEASE
                pom
                import
            
        
    



Nacos

nacos文档
我电脑win7,安装linux失败,只能用windows环境了,下载nacos-server,我这边是nacos-server-2.0.3,然后点击bin目录下的startup.cmd,如果失败的话,可能是因为集群问题,右击startup.cmd,修改里边的

rem set MODE="cluster"
set MODE="standalone"

或者通过启动命令(standalone代表着单机模式运行,非集群模式):

startup.cmd -m standalone

启动起来是这个样子

端口8848,通过 http://localhost:8848/nacos/访问,用户名和密码都是nacos,登录进去

将微服务注册到 nacos 中

在common模块的pom.xml中引用nacos
服务注册/发现

        
            com.alibaba.cloud
            >spring-cloud-starter-alibaba-nacos-discovery
        

配置中心来做配置管理

  
            com.alibaba.cloud
            >spring-cloud-starter-alibaba-nacos-config
        

在需要使用nacos的模块里进行配置,在src/main/resources下新建文件bootstrap.properties

spring.application.name=gulimall-coupon

spring.cloud.nacos.config.server-addr=127.0.0.1:8848
#配置命名空间
spring.cloud.nacos.config.namespace=6f130311-ca32-459c-8a93-f225d0fa5d43
#配置分组
spring.cloud.nacos.config.group=prod
#nacos上添加文件,从nacos上读取配置,本地的可以注释掉
spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=true

spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].refresh=true

spring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[2].refresh=true

这是所有配置,在测试的时候,可以一点点添加配置,同时nacos网页上进行相应配置,才能看出效果
我把我nacos网页上的配置贴一下
配置列表



datasource.yml,mybatis.yml和other.yml对应配置里的

#nacos上添加文件,从nacos上读取配置,本地的可以注释掉
spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
spring.cloud.nacos.config.ext-config[0].group=dev
spring.cloud.nacos.config.ext-config[0].refresh=true

spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
spring.cloud.nacos.config.ext-config[1].group=dev
spring.cloud.nacos.config.ext-config[1].refresh=true

spring.cloud.nacos.config.ext-config[2].data-id=other.yml
spring.cloud.nacos.config.ext-config[2].group=dev
spring.cloud.nacos.config.ext-config[2].refresh=true

内容分别是
datasource.yml:

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/gulimall_sms
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis.yml

mybatis-plus:
  mapper-locations: classpath:/mapper/**
 @RefreshScope
@EnableDiscoveryClient
@SpringBootApplication
@MapperScan("com.atguigu.gulimall.coupon.dao")
public class GulimallCouponApplication {

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

}
feign 远程调用

Feign 是一个声明式的 HTTP 客户端, 它的目的就是让远程调用更加简单。 Feign 提供了 HTTP请求的模板, 通过编写简单的接口和插入注解, 就可以定义好 HTTP 请求的参数、 格式、 地址等信息。
Feign 整合了 Ribbon(负载均衡) 和 Hystrix(服务熔断), 可以让我们不再需要显式地使用这两个组件。
根据以上配置,配置多个服务,然后启动,服务之间进行交互,需要使用到feign,引入open-feign,在gulimall-member模块调用gulimall-coupon中的服务,在gulimall-member的pom.xml引入open-feign,

  
            org.springframework.cloud
            >spring-cloud-starter-openfeign
        

在GulimallMemberApplication文件上,加入注解,EnableFeignClients

@EnableFeignClients(basePackages = "com.atguigu.gulimall.member.feign")
@EnableDiscoveryClient
@SpringBootApplication
@MapperScan("com.atguigu.gulimall.member.dao")
public class GulimallMemberApplication {

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

}

新建feign包,新建CouponFeignService接口

@FeignClient("gulimall-coupon")
public interface CouponFeignService {

    @RequestMapping("/coupon/coupon/member/list")
    public R membercoupons();

}

返回类型和名称与需要调用的方法保持一致。
这个对应的是CouponController里的内容

  @RequestMapping("/member/list")
    public R membercoupons(){
        CouponEntity couponEntity = new CouponEntity();
        couponEntity.setCouponName("满100减10");
        return R.ok().put("coupons",Arrays.asList(couponEntity));
    }

网页访问http://localhost:8000/member/member/coupons,返回

{"msg":"success","code":0,"coupons":[{"id":null,"couponType":null,"couponImg":null,"couponName":"满100减10","num":null,"amount":null,"perLimit":null,"minPoint":null,"startTime":null,"endTime":null,"useType":null,"note":null,"publishCount":null,"useCount":null,"receiveCount":null,"enableStartTime":null,"enableEndTime":null,"code":null,"memberLevel":null,"publish":null}],"member":{"id":null,"levelId":null,"username":null,"password":null,"nickname":"张三","mobile":null,"email":null,"header":null,"gender":null,"birth":null,"city":null,"job":null,"sign":null,"sourceType":null,"integration":null,"growth":null,"status":null,"createTime":null}}

再比如

   @FeignClient("gulimall-coupon")
public interface CouponFeignService {


    
    @PostMapping("/coupon/spubounds/save")
    R saveSpuBounds(@RequestBody SpuBoundTo spuBoundTo);


    @PostMapping("/coupon/skufullreduction/saveinfo")
    R saveSkuReduction(@RequestBody SkuReductionTo skuReductionTo);
}

对应

@RestController
@RequestMapping("coupon/spubounds")
public class SpuBoundsController {
    
    @PostMapping("/save")
    //@RequiresPermissions("coupon:spubounds:save")
    public R save(@RequestBody SpuBoundsEntity spuBounds){
		spuBoundsService.save(spuBounds);

        return R.ok();
    }
@RestController
@RequestMapping("coupon/skufullreduction")
public class SkuFullReductionController {
   @PostMapping("/saveinfo")
    public R saveInfo(@RequestBody SkuReductionTo reductionTo){

        skuFullReductionService.saveSkuReduction(reductionTo);
        return R.ok();
    }
   
跨域问题

使用vue调用后台接口,有可能会出现跨域问题,解决办法有两种,一个简单的就是在controller上添加@CrossOrigin(origins = “*”),另一种就是使用网关,gateway

gateway

Spring Cloud Gateway 旨在提供一种简单而有效的方式来对 API 进行路由, 并为他们提供切面, 例如: 安全性, 监控/指标 和弹性等。
官方文档地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.3.RELEASE/single/spring-cloud-gateway.html

为什么使用 API 网关?
API 网关出现的原因是微服务架构的出现, 不同的微服务一般会有不同的网络地址, 而外部客户端可能需要调用多个服务的接口才能完成一个业务需求, 如果让客户端直接与各个微服务通信, 会有以下的问题:
1 客户端会多次请求不同的微服务, 增加了客户端的复杂性。
2 存在跨域请求, 在一定场景下处理相对复杂。
3认证复杂, 每个服务都需要独立认证。
4难以重构, 随着项目的迭代, 可能需要重新划分微服务。 例如, 可能将多个服务合并成一个或者将一个服务拆分成多个。 如果客户端直接与微服务通信, 那么重构将会很难实施。
5 某些微服务可能使用了防火墙 / 浏览器不友好的协议, 直接访问会有一定的困难。
以上这些问题可以借助 API 网关解决。 API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。 也就是说, API 的实现方面更多的考虑业务逻辑, 而安全、 性能、 监控可以交由 API 网关来做, 这样既提高业务灵活性又不缺安全性:使用 API 网关后的优点如下:1 易于监控。 可以在网关收集监控数据并将其推送到外部系统进行分析。2 易于认证。 可以在网关上进行认证, 然后再将请求转发到后端的微服务, 而无须在每个微服务中进行认证。3 减少了客户端与各个微服务之间的交互次数。

客户端发送请求给网关, 网关 HandlerMapping 判断是否请求满足某个路由, 满足就发给网关的 WebHandler。 这个 WebHandler 将请求交给一个过滤器链, 请求到达目标服务之前, 会执行所有过滤器的 pre 方法。 请求到达目标服务处理之后再依次执行所有过滤器的 post 方法。
一句话: 满足某些断言(predicates) 就路由到指定的地址(uri) , 使用指定的过滤器(filter)

使用

新建gulimall-gateway模块,pom.xml引入gateWay,同样也要注册到nacos中

 
            org.springframework.cloud
            >spring-cloud-starter-gateway
        

项目结构

application.properties

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=gulimall-gateway
server.port=88

application.yml

spring:
  cloud:
    gateway:
      routes:
#        - id: test_route
#          uri: https://www.baidu.com
#          predicates:
#            - Query=url,baidu
#
#        - id: qq_route
#          uri: https://www.qq.com
#          predicates:
#            - Query=url,qq

        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/(?.*),/${segment}

        - id: third_party_route
          uri: lb://gulimall-third-party
          predicates:
            - Path=/api/thirdparty/**
          filters:
            - RewritePath=/api/thirdparty/(?.*),/${segment}

        - id: member_route
          uri: lb://gulimall-member
          predicates:
            - Path=/api/member/**
          filters:
            - RewritePath=/api/(?.*),/${segment}

        - id: ware_route
          uri: lb://gulimall-ware
          predicates:
            - Path=/api/ware/**
          filters:
            - RewritePath=/api/(?.*),/${segment}

        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?.*),/renren-fast/${segment}



  ## 前端项目,/api
## http://localhost:88/api/captcha.jpg   http://localhost:8080/renren-fast/captcha.jpg
## http://localhost:88/api/product/category/list/tree http://localhost:10000/product/category/list/tree

bootstrap.properties

spring.application.name=gulimall-gateway

spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=4065e888-a2bc-4c10-a1dd-8a84773f7e2e


这样,前端只需要访问http://localhost:88/api,网关就可以根据Path跳转到不同的模块


@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class GulimallGatewayApplication {

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

}

解决跨域问题
src/maiin下新建config文件夹,新建GulimallCorsConfiguration

@Configuration
public class GulimallCorsConfiguration {

    @Bean
    public CorsWebFilter corsWebFilter(){
        UrlbasedCorsConfigurationSource source = new UrlbasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration = new CorsConfiguration();

        //1、配置跨域
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);

        source.registerCorsConfiguration("/**",corsConfiguration);
        return new CorsWebFilter(source);
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/322139.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号