微服务开发之理论篇

一、 单体架构与微服务架构

1.单体架构优缺点

优点:
1.部署简单,由于是完整的结构体,可以直接部署在一台服务器
2.技术单一,项目不需要复杂的技术栈,熟悉一套技术栈就可以完成整个项目的开发
缺点:
1.系统启动慢,一个项目包含所有的结构体,涉及的模块多,导致系统启动周期长。
2.系统隔离性、可用性差,任何一个模块错误都有可能导致整个系统宕机
3.可伸缩性差,系统的扩容只能针对整个应用进行扩容,无法结合业务模块的特点进行伸缩。
4.线上问题修复周期长,任何一个线上问题的修复必须对整个系统进行全面升级

2.微服务架构的优缺点

优点
1.易于开发和维护,一个微服务只需要关注一个特定功能的实现,所以他代码较少、结构清晰。开发和维护单个微服务也相对简单
2.单个微服务启动较快,单个微服务代码较少
3.对单个功能的修改容易部署,在单体架构修改某个功能需要重新部署整个项目,微服务架构中只需要针对该服务进行部署即可
4.技术栈不受限,可以结合项目业务和团队特点合理选择技术栈
缺点
1.各微服务之间交错复杂,导致运维成本增加
2.微服务放大了分布式架构的问题

  • 分布式事物(seata)
  • 分布式锁怎么处理(redisson)
  • 服务注册与发现(nacos)
  • 依赖服务不稳定(sentinel)导致服务雪崩怎么办

3.springcloud与微服务

3.1 springcloud为微服务思想提供了完美解决方案,springcloud是一系列框架的集合体(服务注册与发现、服务间远程调用、服务降级、服务熔断、服务降级、服务限流、分布式事物等)

  • springboot的版本查看地址:https://spring.io/projects/spring-boot#learn
  • springcloud的版本查看地址:https://spring.io/projects/spring-cloud#overview
  • 详细版本对应信息查看:https://start.spring.io/actuator/info

**注:**如果使用springBoot和springCloud(springCloud netflix)那么使用以上本版对应就行了,但是如果要使用组件nacos、sentinel、rocketmq、seata就必须使用springcloudAlibaba

3.2 springCloud与springCloudAlibaba
我们说的spingCloud,泛指springCloudNetflix,也是springCloud第一代。springCloudAlibaba是springCloud的子项目,是阿里巴巴结合自身微服务实践。springCloudAlibaba符合springCloud标准,依赖于springCloud

springCloud 第一代状态springCloudAlibaba状态
Eureka2.0孵化失败nacos discovery性能强劲,感知更快
ribbon进入维护状态同左同左
Hytrix/Hystrix Dashboard/Turbine进入维护状态sentinel可视化配置,上手更简单
zuul进入维护状态gateway性能是zuul的1.6倍
springCloudConfig搭建复杂,约定多,设计繁重,没有界面nacos config搭建简单,有可视化界面,配置管理更高效

二、 服务注册与发现

服务注册:将某个微服务的信息注册到一个公用组件上。
服务发现:注册到公共组件的微服务能够即时被其他调用者发现,不管是服务的新增还是删减

1.注册中心的对比

对比项目nacoseurekaconsulzookeeper
一致性协议支持AP和CPAPCPCP
负载均衡策略权重/metadata/selectorribbonFabio
雪崩保护
访问协议HTTP/DNSHTTPHTTP/DNSTCP
跨注册中心同步支持不支持支持不支持
springcloud集成支持支持支持不支持
dubbo集成支持不支持不支持支持
k8s集成支持不支持支持不支持

2.nacos简介

nacos官网地址

https://nacos.io/zh-cn/docs/what-is-nacos.html

2.1 nacos架构图
在这里插入图片描述

3.nacos功能

3.1 命名服务
命名服务是指通过指定的名字来获取资源或者服务的地址,提供者信息

3.2 配置服务
动态配置服务让您能够以中心化、外部化和动态化的方式管理所有环境的配置。动态配置消除
了配置变更时重新部署应用和服务的需要。配置中心化管理让实现无状态服务更简单,也让按
需弹性扩展服务更容易。

3.3 nacos注册中心工作流程

  • 服务注册:Nacos Client会通过发送rest请求的方式向Nacos Server注册自己的服务,提供自身的元数据,比如IP地址、端口信息。nacos server接收到注册请求后,就会把这些元数据信息存储在一个双层的内存MAP中
  • 服务心跳:在服务注册后,nacos client会维护一个定时心跳来持续通知nacos server,说明服务一直处于可用状态,防止被剔除。默认5s发送一次心跳。
  • 服务同步:nacos server集群之间会互相同步服务实例,用来保证服务信息的一致性。
  • 服务发现:服务消费者在调用服务提供者的服务时,会放一个请求给nacos server,获取上面注册的服务清单,并且缓存在nacos client本地,同时会在nacos client本地开启一个定时任务拉取服务端最新的注册表信息更新到本地缓存
  • 服务健康检查:nacos server会开启一个定时任务用来检查注册服务实例的健康状况,对于超过15秒没有接收到客户端心跳的实例会将它的healthy属性设置为false,如果某个实例超过30s没有收到心跳,直接剔除该实例

4.naocs的领域模型

nacos的服务由三元组唯一确定(namespace、group、serviceName)
naocs的配置由三元组唯一确定(namespace、group、dataId)
不同的namespace是互相隔离的,相同的namespace但是不同的group也是相互隔离的
默认的namespace是public,不能删除,配置namespace时为""
默认的group是DEFAULT-GROUP

三、配置中心

1.常见的配置中心

市面上用的较多的配置中心对比

对比项目spring cloud configAppolonacos
配置实时推送支持(springCloudBus)支持(HTTP长轮询1s内)支持(HTTP长轮询1s内)
版本管理支持(git)支持支持
配置回滚支持(git)支持支持
灰度发布支持支持不支持
权限管理支持(依赖git)支持不支持
多集群支持支持支持
多环境支持支持支持
监听查询支持支持支持
多语言只支持java主流语言,提供了openApi主流语言,提供了openApi
配置格式校验不支持支持支持
单机读(QPS)7(限流所致)900015000
单机写(QPS)5(限流所致)11001800
3节点读21(限流所致)2700045000
3节点写(QPS)5(限流所致)33005600
  • 从配置中心⻆度来看,性能方面Nacos的读写性能最高,Apollo次之,Spring Cloud Config
    依赖Git场景不适合开放的大规模自动化运维API。
  • 功能方面Apollo最为完善,nacos具有Apollo大部分配置管理功能,而Spring CloudConfig
    不带运维管理界面,需要自行开发
  • Nacos的一大优势是整合了注册中心、配置中心功能,部署和操作相比Apollo都要直观简单,因
    此它简化了架构复杂度,并减轻运维及部署工作

要在项目中使用nacos作为配置中心,必须使用bootstrap.properties配置文件来配置nacos server地址

spring.application.name=SERVICE01
#不配置则默认为spring.application.name
spring.cloud.nacos.config.prefix=product
#nacos的地址
spring.cloud.nacos.config.server-addr=localhost:8848
#命名空间,必须填写ID
spring.cloud.nacos.config.namespace=e01ae608-449a-4464-bd12-8926fc6f3cfa
spring.cloud.nacos.config.group=DEFAULT_GROUP
#文件拓展名
spring.cloud.nacos.config.file-extension=yml
spring.profiles.active=dev

2.dataId命名规则

nacos中的dataId命名规则如下,根据bootstrap.properties的配置取值

${spring.cloud.nacos.config.prefix}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

3.动态刷新配置

我们可以在类加上@RefreshScope注解达到动态刷新的效果

@RestController
@RequestMapping("/product")
@Api(tags = "(Product)")
@RefreshScope
public class ProductController {
    @Value("${user.name}")
    private String name;
}

4.加载共享配置

通过配置shared-configs的方式来支持多个data id

# 配置支持共享的 Data Id
spring.cloud.nacos.config.shared-configs[0].data-id=common.yaml

# 配置 Data Id 所在分组,缺省默认 DEFAULT_GROUP
spring.cloud.nacos.config.shared-configs[0].group=GROUP_APP1

# 配置Data Id 在配置变更时,是否动态刷新,缺省默认 false
spring.cloud.nacos.config.shared-configs[0].refresh=true

详情可以查看官方文档

地址:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config

在这里插入图片描述

四、RestTemplate

restTemplate基于Apache的httpClient实现,是java模拟浏览器发送http请求的工具类

1.get请求

1.1 getForObject
返回的是响应结果

String res = restTemplate.getForObject(url, String.class);

1.2 getForEntity
返回的是响应体

ResponseEntity<Map> entity = restTemplate.getForEntity(url, Map.class);
Map body = entity.getBody();

1.3 get请求携带请求头

HttpHeaders headers = new HttpHeaders();
headers.add("Cookie","abc");
HttpEntity<Object> entity = new HttpEntity<>(headers);
ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
String res = exchange.getBody()

1.4 携带参数的get请求

String url = "http://localhost:4003/service01/product/{id}";
RestTemplate restTemplate = new RestTemplate();
Map<String, Object> map = new HashMap<>(2);
map.put("id",1);
ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class, map);
String data = responseEntity.getBody();

2.post请求

2.1 postForEntity携带body参数

String url = "http://localhost:4003/service01/product";
RestTemplate restTemplate = new RestTemplate();
JSONObject json = new JSONObject();
json.put("productName","苹果13");
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, json, String.class);
String data = responseEntity.getBody();

2.2 postForObject

String res = restTemplate.postForObject(url, json, String.class);

五、Ribbon

Ribbon是Netflix公司开源的一个负载均衡的项目,客户端的负载均衡器,解决的是服务列表的负载均衡问题

    /**
     *  通过@LoadBalanced注解实现负载均衡
     * @return 
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

IRule是Ribbon的一个核心接口,会根据特定的算法从服务列表中选取一个需要访问的服务,IRule有七个自带的落地实现类,可以实现不同的负载均衡算法,默认是ZoneAvoidanceRule

策略声明策略描述
public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule选择一个最小的并发请求
public class AvailabilityFilteringRule extends PredicateBasedRule先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数超过阈值的服务,然后对剩余服务进行轮询
public class WeightedResponseTimeRule extends RoundRobinRule根据平均的响应时间计算服务的权重,统计信息不足时会按照轮询,统计信息足够会按照响应的时间选择服务
public class RetryRule extends AbstractLoadBalancerRule正常时按照轮询选择服务,若过程中有服务出现故障,在轮询一定次数后依旧故障,则会跳过故障的服务继续轮询
public class RoundRobinRule extends AbstractLoadBalancerRule轮询规则
public class RandomRule extends AbstractLoadBalancerRule随机
public class ZoneAvoidanceRule extends PredicateBasedRuleZoneAvoidanceRule 中的过滤条件是以ZoneAvoidancePredicate类为主过滤条件和以AvailabilityPredicate类为次过滤条条件组成的一个叫做CompositePredicate类的组合过滤条件,过滤成功后继续采用线性轮询的方式从过滤结果中选择一个出来

六、openfeign

openfein是一种声明式的、模板化的http客户端,在springCloud中使用openfeign可以做到http请求远程服务时能与调用本地方法一样的编码体验,同时openFeign通过继承Ribbon实现客户端的负载均衡。

1.开启openfeign

通过@EnableFeignClients开启openFeign

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class Service01Application {

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

}

2.接口声明

@FeignClient("SERVICE02")
@RequestMapping("/productDetail")
public interface ProductDetailFeign {

    @GetMapping("/detail/{productId}")
    ResponseEntity<ProductDetailVO> selectByproductId(@PathVariable(name = "productId") Integer productId);

    /**
     * 新增
     * @param productDetail
     * @return
     */
    @PostMapping
    ResponseEntity<Integer> insertSelective(@RequestBody ProductDetailQuery productDetail);

}

3.openfign常用配置

ribbon:
  eager-load:
    enabled: true
    clients:
      - SERVICE01
      - SERVICE03
feign:
  client:
    config:
      SERVICE01:
        connect-timeout: 1000
        read-timeout: 1000  #设置相应的超时时间为1毫秒
      default: #设置默认的超时时间
        connect-timeout: 1000
        read-timeout: 1000

4.feign与openfeign的区别

一句话直观体现区别:openfeign支持springMVC注解,fegin不支持springMVC注解

七、网关gateway

为微服务架构系统提供高性能,且简单易用的api路由管理方式,基于spring5、springBoot2.0和project Reactor等技术开发的网关

  1. 性能强劲,是第一代网关zuul的1.6倍
  2. 功能强大,内置很多实用功能:路由、过滤、限流、监控等

官网地址:https://spring.io/projects/spring-cloud-gateway

1.gateway的核心概念

  • route:路由是构建网关的脚本模块,他由ID、目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
  • predicate:可以匹配http请求重的所有内容(例如请求头、请求参数),如果请求与断言相匹配则进行路由
  • filter:指的是spring中的gatewayFilter实例,使用过滤器可以在请求被路由前或者之后对请求进行修改

2.gateway的工作流程

  1. 由客户端向SpringCloudGateway发出请求,然后再gatewayHandlerMapping中找到与请求相匹配的路由
  2. 将其发送到gateway web handler
  3. handler 再通过指定的过滤的过滤连来将我们的请求发送到实际的服务处理业务逻辑,然后返回。过滤器之前用虚线分开是因为过滤器可能会在发送代理请求之前(Pre)或者之后(Post)执行业务逻辑
    在这里插入图片描述

3.路由配置

spring:
  application:
    name: GATEWAY
  cloud:
    gateway:
      routes:
        - id: SERVICE01
          uri: lb://SERVICE01
          predicates:
            - Path=/service01/**
          filters:
            - StripPrefix=1
        - id: SERVICE02
          uri: lb://SERVICE02
          predicates:
            - Path=/service02/**
          filters:
            - StripPrefix=1

当我们访问/service01/product时网关会将我们的请求转发到SERVICR01服务的/product路径,当我们访问/service02/productDetail时,网关会将我们的请求转发到SERVICE02服务的/productDetail路径,StripPrefix=1代表去掉一个前缀。其中配置的ID必须是唯一,uri建议配置服务名,若是配置ip端口无法负载均衡。

4.谓词工厂

Spring Cloud Gateway将路由作为Spring WebFlux HandlerMapping基础设施的一部分进行匹配。Spring Cloud Gateway包括许多内置的路由谓词工厂。所有这些谓词都匹配HTTP请求的不同属性。您可以将多个路由谓词工厂与逻辑和语句组合在一起。
在这里插入图片描述

谓词工厂说明
AfterRoutePredicateFactory匹配任何在配置时间之后的请求
BeforeRoutePredicateFactory匹配任何在配置时间之前的请求
BetweenRoutePredicateFactory匹配任何在配置时间之内的请求
CookieRoutePredicateFactory匹配指定Cookie,正则匹配指定值的请求
HeaderRoutePredicateFactory匹配指定Header,正则匹配指定值的请求
HostRoutePredicateFactory请求Host匹配指定值
MethodRoutePredicateFactory请求menthol匹配配置的method,例如发送GET请求匹配GET请求
PathRoutePredicateFactory例如路径正则匹配指定值,例如上面的路由配置例子
QueryRoutePredicateFactory请查询参数匹配指定值
RemoteAddrRoutePredicateFactory请求远程地址匹配配置指定值
WeightRoutePredicateFactory分组计算权重,按权重转发请求

5.过滤器工厂

gateway内置有二三十个过滤器,这里就不全列出来了,有兴趣可以前往官网查看

1.StripPrefixGatewayFilterFactory

StripPrefix GatewayFilter工厂有一个参数,即parts。parts参数指示在向下游发送请求之前从请求中剥离的路径中的部件数量。
例如StripPrefix=2,那么通过网关发送到/name/blue/red的请求时,发送到服务的请求为/red。

spring:
  cloud:
    gateway:
      routes:
      - id: nameRoot
        uri: https://nameservice
        predicates:
        - Path=/name/**
        filters:
        - StripPrefix=2

2.PrefixPathGatewayFilterFactory
PrefixPath GatewayFilter工厂接受单个前缀参数。

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - PrefixPath=/mypath

这将为所有匹配请求的路径添加/mypath前缀。所以对/hello的请求会被发送到/mypath/hello

八、Sleuth链路追踪

springCloudSleuth提供的分布式系统中链路追踪解决方案。

  • skyWalking是本土开源的基于字节码注入的调用链分析,以及应用监控分析工具,特点是支持多种插件,UI功能较强,接入端无代码侵入,目前已加入Apache孵化器
  • cat由大众点评开源,基于java开发的实时应用监控平台,包括实时应用监控,业务监控。集成方案是通过代码埋点的方式来实现监控

1.Sleuth术语

span:代表了一组基本的工作单元。为了统计各处理单元的延迟,当请求到达各个服务组件的时候,也通过一个唯一标识(SpanId)来标记它的开始、具体过程和结束。通过SpanId的开始和结束时间戳,就能统计该span的调用时间,除此之外,我们还可以获取如事件的名称。请求信息等元数据。
Trace:由一组Trace Id相同的Span串联形成一个树状结构。为了实现请求跟踪,当请求到达分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的标识(即TraceId),同时在分布式系统内部流转的时候,框架始终保持传递该唯一值,直到整个请求的返回。那么我们就可以使用该唯一标识将所有的请求串联起来,形成一条完整的请求链路。
Annotation:用它记录一个完成请求的4个事件。
cs(Client Send):客户端发出请求,开始一个请求的生命
sr(Server Received):服务端接受到请求开始进行处理, sr-cs = 网络延迟(服务调用的时间)
ss(Server Send):服务端处理完毕准备发送到客户端,ss - sr = 服务器上的请求处理时间
cr(Client Reveived):客户端接受到服务端的响应,请求结束。 cr - sr = 请求的总时间

2.Sleuth+Zipkin架构

Zipkin 是Twitter开放源代码分布式的跟踪系统,每个服务向zipkin报告计时数据,zipkin会根据调用关系通过Zipkin UI生成依赖关系图。

下载地址:https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/

3.集成依赖

<!--链路追踪场景依赖-->
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
spring:
  zipkin:
    base-url: http://localhost:9999
    discovery-client-enabled: false
  sleuth:
    sampler:
      rate: 100

九、服务哨兵Sentinel

随着分布式系统越来越流行,服务之间的可靠性比以往任何时候都更加重要。Sentinel是以“流量”为切入点的强大流量控制组件,涵盖了流量控制、并发限制、断路、自适应系统保护等多个领域,保证了微服务可靠性。

官方地址:https://github.com/alibaba/Sentinel/wiki

sentinel主要分为两部分

  • 核心库(java客户端) 不依赖任何框架/库,能够运行所有java运行环境,同时对dubbo/springCloud等框架有较好的支持
  • 控制台(dashboard) 基于springBoot开发,打包后直接运行,不需要额外的tomcat等应用容器

1.sentinel与hystrix

sentinelhystrix
隔离策略信号隔离(并发线程数)线程池隔离/信号量隔离
熔断降级策略慢调用比例、异常比例、异常数异常比例
实时指标实现滑动窗口滑动窗口(基于RxJava)
规则配置(rule)支持多种数据源支持多种数据源
拓展性多个拓展点插件的形式
基于注解的支持支持支持
调用链路信息支持同步调用不支持
限流QPS基于QPS/并发数,支持基于调用关系的限流不支持
流量整形支持慢启动、匀速器模式不支持
系统负载保护支持不支持
实时监控API各式各样较为简单
控制台开箱即用,可配置规则,查看秒级监控、机器发现等不完善
常见框架适配servlet、springCloud、dubboservlet、springCloud、Netflix

2.Sentinel控制台安装

通过控制台,设置流控规则(qps、线程数)、还可以设置熔断降级的规则(慢调用比例、异常比例、异常数),可以实时观看每个资源的访问情况。

下载地址:https://github.com/alibaba/Sentinel/tags

下载下来是个jar包,直接通过java -jar 命令运行就可以了

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080。从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel

在这里插入图片描述

3.项目集成sentinel

pom依赖

<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

yml配置

#默认是8719,如果8719被占用 +1,一直到没有被占用
spring.cloud.sentinel.transport.port=8719
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080

开启饥额加载,当项目启动立即完成初始化,默认是懒加载

spring.cloud.sentinel.eager=true

如果是懒加载的方式需要先请求一下后台接口
在这里插入图片描述

在这里插入图片描述

4.QPS超过阈值

QPS(Query Per Second)即每秒处理请求数,是用来衡量服务性能的一个重要指标。当被访问资源的QPS大于设定值时触发流控规则

5.线程数超过阈值

正在工作的线程数大于设定值触发流控规则

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值