0
点赞
收藏
分享

微信扫一扫

微服务笔记03

Mezereon 2022-03-11 阅读 68

01. Nacos

1. 简介


2. 安装

安装

docker pull nacos/nacos-server:1.1.4

运行

docker run -d -p 8848:8848 -e MODE=standalone -e PREFER_HOST_MODE=hostname --restart always --name nacos nacos/nacos-server:1.1.4

3. 整合nacos

1. 创建项目

版本限制

<dependencyManagement>
    <!--spring cloud alibaba 2.1.0.RELEASE-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.1.0.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
</dependencyManagement>

2. 引依赖

<!--SpringCloud alibaba nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

3. 写yml

server:
  port: 9001

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: 47.98.251.199:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

4. 主启动

@EnableDiscoveryClient //nacos发现
@SpringBootApplication
public class PaymentMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9001.class,args);
    }
}

一个项目多个实例


4. 负载均衡

为什么Nacos可以负载均衡,看包结构就能看到这个netflix.ribbon

5. nacos和CPA


nacos支持AP和CP模式切换


6. 配置中心-基础配置




7. 配置中心-分类配置


1. 是什么
类似Java里面的package名和类名
最外层的namespace是可以用于区分部署环境的,Group和DataID逻辑上区分两个目标对象。
2. 三者情况

image-20220125195209273

NameSpace,Group,Service

3. 默认情况:
Namespace=public,Group=DEFAULT_GROUP, 默认Cluster是DEFAULT

Nacos默认的命名空间是public,Namespace主要用来实现隔离
比方说我们现在有三个环境:开发、测试、生产环境,我们就可以创建三个Namespace,不同的Namespace之间是隔离的。

Group默认是DEFAULT_GROUP,Group可以把不同的微服务划分到同一个分组里面去

Service就是微服务;一个Service可以包含多个Cluster(集群),Nacos默认Cluster是DEFAULT,Cluster是对指定微服务的一个虚拟划分。
比方说为了容灾,将Service微服务分别部署在了杭州机房和广州机房
这时就可以给杭州机房的Service微服务起一个集群名称(HZ),
给广州机房的Service微服务起一个集群名称(GZ),还可以尽量让同一个机房的微服务互相调用,以提升性能。

最后是Instance,就是微服务的实例

8. 集群搭建

02. Sentinel

1. 简介

image-20220129181030380


2. 环境搭建

环境搭建:

这里我采用docker安装环境,

docker pull bladex/sentinel-dashboard:1.7.0
docker run --restart=always \
--name sentinel \
-d -p 8858:8858 -d bladex/sentinel-dashboard:1.7.0

非常快捷就可以安装成功了

访问方式:http://47.98.251.199:8858

上面会出现,实时监控页面为空白的情况

哪怕自己已经按照视频思路来也还是出现一样的情况,所有最后我妥协了,选择在本地运行jar包开启

这个时候,访问页面为:http:localhost:8080

3. 初始化演示工程

  • 依赖
<dependencies>
    <!--SpringCloud ailibaba nacos -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
    <dependency>
        <groupId>com.alibaba.csp</groupId>
        <artifactId>sentinel-datasource-nacos</artifactId>
    </dependency>
    <!--SpringCloud ailibaba sentinel -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <!--openfeign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!-- SpringBoot整合Web组件+actuator -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!--日常通用jar包配置-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>4.6.3</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
  • 一些配置:sentinel一些配置

4. 流控规则

1. 基本介绍

  • 资源名:唯一名称,默认请求路径
  • 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default
  • 阀值类型/单机阈值:
    • QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流。
    • 线程数:当调用该api的线程达到阈值的时候,进行限流
  • 是否集群:不需要集群
  • 流控模式:
    • 直接:api达到限流条件时,直接限流
    • 关联:当关联的资源达到阈值时,就限流自己
    • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流[api级别的针对来源])
  • 流控效果:
    • 快速失败:直接失败,抛异常
    • Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值。
    • 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效。

自我尝试例子:

  • 可以在簇点链路那里点击配置
  • 当然也可在流控规则那里配置,建议就是在簇点链路那里配置。

测试结果:

image-20220201210214695


关于QPS与线程数的区别

  • 简单粗暴的说:QPS是挡在家门外,线程数是关门打狗

QPS会在请求进入时有一道门,给多少个进就多少个进,多了就报异常

线程数是,全部请求全部涌入,配了多少个线程就只有多少个线程。处理不过来了就直接报错。

我们可以试一试就是在请求那里休眠个几秒,多发几个请求就直接崩盘了。


2. 流控模式

关联

设置效果(认真细读,不要搞反主次了)
当关联资源/testB的qps阀值超过1时,就限流/testA的Rest访问地址,当关联资源到阈值后限制配置好的资源名


链路

只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流[api级别的针对来源])

image-20220202182930278

3. 流控效果

预热


默认 coldFactor 为 3,即请求QPS从(threshold / 3) 开始,经多少预热时长才逐渐升至设定的 QPS 阈值。


案例,阀值为10+预热时长设置5秒。
系统初始化的阀值为10 / 3 约等于3,即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10



应用场景


排队等待

匀速排队,让请求以均匀的速度通过,阀值类型必须设成QPS,否则无效。
设置含义:/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。

一开始理解错了超时等待的作用,现在我感觉这个的作用就是,当出现需要等待20秒的就报错。

image-20220203130312893

5. 降级规则

RT


异常比例

image-20220203165514522

异常数

image-20220203171322778


时间窗口一定要大于等于60秒。


image-20220203171334282

6. 热点key限流

是什么


配置与测试

@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false)String p1
        , @RequestParam(value = "p2",required = false)String p2) {
    return "testHotKey,"+"p1: "+p1+",p2: "+p2;
}

public String deal_testHotKey(String p1, String p2, BlockException blockException) {
    return "testHotKey,"+"p1: "+p1+",p2: "+p2+",error!!!!";
}

参数例外项

7. 系统规则

是什么

规则介绍


8. @SentinelResource

1. 客户自定义限流处理逻辑

  • 创建CustomerBlockHandler类用于自定义限流处理逻辑

  • 自定义限流处理类

  • import com.alibaba.csp.sentinel.slots.block.BlockException;
    import com.lin.entities.CommonResult;
    
    public class CustomerBlockHandler {
        public static CommonResult handleException(BlockException exception){
            return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler");
        }
    }
    
  • @GetMapping("/rateLimit/customerBlockHandler")
        @SentinelResource(value = "customerBlockHandler"
                ,blockHandlerClass = CustomerBlockHandler.class
                ,blockHandler = "handleException")
        public CommonResult customerBlockHandler() {
            return new CommonResult(200, "按客户自定义限流处理逻辑");
        }
    

9. 服务熔断功能

兜底方法:fallback

合上服务降级方法

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.lin.entities.CommonResult;
import com.lin.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    /**
     * 这里我们最先演示就是配fallback的情况
     * 前面我们配的是:blockHandler
     * */
    @GetMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback"
            , fallback = "handlerFallback"
            ,blockHandler = "blockHandler"
            ,exceptionsToIgnore = {IllegalArgumentException.class}) //fallback负责业务异常
    public CommonResult<Payment> fallback(@PathVariable Long id) {
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);

        if (id == 4) {
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        } else if (result.getData() == null) {
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }

    public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
    }

    public CommonResult blockHandler(@PathVariable("id") Long id, BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
    }
}

image-20220205200532891

10. 规则持久化

1. 是什么


2. 怎么玩

3. 配置

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址
        server-addr: 47.98.251.199:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719
      datasource:
        ds1:
          nacos:
            server-addr: 47.98.251.199:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
  • 看那个datasource那里就行了。

Nacos配置一下:

[
    {
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]
resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。

03. Seata

是什么:

官网

能干嘛:

一个典型的分布式事务过程

  • 分布式事务处理过程的一ID+三组件模型

Transaction ID XID:全局唯一的事务ID

三个组件概念

  • Transaction Coordinator(TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局的提交或回滚
  • Transaction Manager™:控制全局事务的边界,负责开启全局事务,并最终发起全局提交或全局回滚的协议。
  • Resource Manager(RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚

处理过程

小项目分析能力

分析数据库,理清思路。

  • 想象它们是在不同机器上面的,所有什么联表就不需要想了

config下面的

import com.alibaba.druid.pool.DruidDataSource;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.transaction.SpringManagedTransactionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;

@Configuration
public class DataSourceProxyConfig {
    @Value("${mybatis.mapperLocations}")
    private String mapperLocations;

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource druidDataSource() {
        return new DruidDataSource();
    }

    @Bean
    public DataSourceProxy dataSourceProxy(DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }

    @Bean
    public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSourceProxy);
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
        sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
        return sqlSessionFactoryBean.getObject();
    }
}

cations}")
private String mapperLocations;

@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource druidDataSource() {
    return new DruidDataSource();
}

@Bean
public DataSourceProxy dataSourceProxy(DataSource dataSource) {
    return new DataSourceProxy(dataSource);
}

@Bean
public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception {
    SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    sqlSessionFactoryBean.setDataSource(dataSourceProxy);
    sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
    sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
    return sqlSessionFactoryBean.getObject();
}

}


举报

相关推荐

0 条评论