2023最新谷粒商城笔记之Sentinel概述篇(全文总共13万字,超详细)

Sentinel概述

服务流控、熔断和降级

  • 什么是熔断
    • 当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,**进而熔断该节点微服务的调用,快速返回错误的响应信息。**检测到该节点微服务调用响应正常后恢复调用链路。
    • A服务调用B服务的某个功能,由于网络不稳定问题,或者B服务卡机,导致功能时间超长。如果这样的次数很多。我们就可以直接将 B服务短路了(A不再请求 B接口),凡是调用B的请求直接返回降级数据,不必等待 B的超长执行。这样 B的故障问题,就不会级联影响到A服务。
  • 什么是降级
    • 服务降级是指当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理,或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作。说白了,就是尽可能的把系统资源让给优先级高的服务
    • 整个网站处于流量高峰期,服务器压力剧增,根据当前业务情况及流量,对一些服务和页面进行由策略的降级[停止服务,所有的调用直接返回降级数据]。以此缓解服务器资源的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户得到正确的对应。
  • 什么是限流
    • 对打入服务的请求流量进行控制,使服务能够承担不超过自己能力的流量压力

熔断降级异同:

  • 相同点:
    1. 为了保证集群大部分服务的可用性和可靠性,防止崩溃,牺牲小我
    2. 用户最终都是体验到某个功能不可用
  • 不同点:
    1. 熔断是被调用方故障,触发的系统主动规则(调用方调用被调用方的接口被短路了即熔断了)
    2. 降级是基于全局的考虑,通知一些正常服务释放资源

Sentinel 简介

简介:

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来帮助开发者保障微服务的稳定性。

Sentinel分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

img

Sentine和Hystrix对比:

image-20230118202203581

SpringBoot整合Sentinel

官方文档

  • 整合Sentinel
    1. 导入依赖 spring-cloud-starter-alibaba-sentinel
    2. 下载sentinel的控制台
    3. 配置Sentinel
    4. 在控制台调整所有的参数[默认所有的流控设置保存在内存中,重启失效]

第一步、在gulimall-common服务中 导入依赖

<!--Sentinel 服务熔断、降级、限流-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--统计审核信息-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

第二步、去官网下载项目里sentinel对应的版本的控制台官网下载

在这里插入图片描述

1、在路径下执行以下命令开启sentinel的控制台

hgw@HGWdeAir SpringCloudSentinel# java -jar sentinel-dashboard-1.6.3.jar --server.port=8333

在这里插入图片描述

2、访问http://localhost:8333/

  • 用户名:sentinel

    密码:sentinel

在这里插入图片描述

第三步、配置Sentinel

在gulimall-seckill 服务的配置文件中:

#sentinel控制台地址
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8333
#sentinel传输端口,传输后台数据到控制台的端口
spring.cloud.sentinel.transport.port=8713
#暴露的 endpoint 路径为 /actuator/sentinel
#Sentinel Endpoint 里暴露的信息非常有用。包括当前应用的所有规则信息、日志目录、
#当前实例的 IP,Sentinel Dashboard 地址,Block Page,应用与 Sentinel Dashboard 的心跳频率等等信息。
management.endpoints.web.exposure.include=*

流量控制[限流]

在这里插入图片描述

Sentinel-自定义流控响应

Sentinel默认限流页面是它官方设置的,这里我们想自定义成自己的数据,所以需要自定义流控相应的数据。只需要配置一个配置类就可以了。

首先导入依赖actuator依赖,它是一个审计模块,可以统计出我们项目中的应用的健康状况信息,包括请求的调用信息。Sentinel就是通过拿到这些信息来做整个数据实时的监控统计的。

然后我们需要暴露我们的端口信息:

management.endpoints.web.exposure.include=*

将所有的端口都暴露出去,这样Sentinel就可以拿到里面的数据了。

然后自定义配置类:

image-20230120160357317

package com.atguigu.gulimall.seckill.config;

import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import com.atguigu.common.exception.BizCodeEnume;
import com.atguigu.common.utils.R;
import org.springframework.context.annotation.Configuration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * Description: Sentinel-自定义流控响应
 */
@Configuration
public class SeckillSentinelConfig {
    public SeckillSentinelConfig() {
        //给web回调管理器设置一个阻塞的控制器,只要请求阻塞不允许访问就返回以下自定义的数据
        WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
            @Override
            public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
                R error = R.error(BizCodeEnume.TO_MANY_REQUEST.getCode(), BizCodeEnume.TO_MANY_REQUEST.getMsg());
                httpServletResponse.setCharacterEncoding("UTF-8");
                httpServletResponse.setContentType("application/json");
                httpServletResponse.getWriter().write(JSON.toJSONString(error));
            }
        });
    }
}												

在这里插入图片描述

Sentinel全服务引入

1、为每个服务引入 actuator依赖

<!--统计审核信息-->+
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、配置 sentinel

#sentinel控制台地址
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8333
management.endpoints.web.exposure.include=*

熔断降级

1)、调用方的熔断保护开启 feign.sentinel.enabled=true

2)、调用方手动指定远程服务的降级策略。远程服务出现问题时会被降级处理,触发我们的熔断回调方法

3)、超大浏览的时候,必须牺牲一些远程服务。在服务的提供方(远程服务)指定降级策略; 提供方是在运行,但是它不运行自己的业务逻辑,调用它之后返回的是默认的降级数据(限流的数据)

默认情况下,sentinel是不会对feign进行监控的,需要开启配置

在gulimall-product类配置文件添加配置

#sentinel是不会对feign进行监控的,需要开启配置
feign.sentinel.enabled=true

熔断[调用方]

feign的流控和降级

使用Sentinel来保护feign远程调用:熔断。举一个案例:

1、在gulimall-product类配置文件添加配置,默认情况下,Sentinel 是不会对 Feign 进行监控的,需要开启配置

#sentinel是不会对feign进行监控的,需要开启配置
feign.sentinel.enabled=true

2、Feign 的降级:在@FeignClient设置fallback属性。编写熔断回调方法。这里是实现的远程服务调用失败的熔断回调方法,所以实现了那个远程服务的调用类然后重写那个需要熔断回调的远程方法,编写其熔断回调逻辑。

package com.atguigu.gulimall.product.feign.fallback;

@Slf4j
@Component
public class SeckillFeignServiceFallBack implements SeckillFeignService {
    @Override
    public R getSkuSeckillInfo(Long skuId) {
        log.error("熔断方法调用...getSkuSeckillInfo");
        return R.error(BizCodeEnume.TO_MANY_REQUEST.getCode(),BizCodeEnume.TO_MANY_REQUEST.getMsg());
    }
}

3、指定 服务熔断回调方法@FeignClient(fallback = 指定的熔断回调方法)

package com.atguigu.gulimall.product.feign;

@FeignClient(value = "gulimall-seckill", fallback = SeckillFeignServiceFallBack.class)
public interface SeckillFeignService {
    @GetMapping("/sku/seckill/{skuId}")
    R getSkuSeckillInfo(@PathVariable("skuId") Long skuId);
}

降级效果:当远程服务被限流或者不可用时,会触发降级效果:
在这里插入图片描述

降级[服务方]

设置调用降级:

  • 远程服务降级之后,调用请求触发我们的熔断回调方法
  • 服务的提供方(远程服务)指定降级策略; 提供方是在运行。但是不运行自己的业务逻辑。返回的是默认的降级数据(限流的数据)

在这里插入图片描述

这里总结一下:

首先需要监控远程请求调用过程需要开启sentinel和feign的配置。

  • 熔断指的是调用方,调用方根据请求的响应状态,如果不对则自动暂停本次请求,之后也不再调用这个请求(即这个请求短路了),叫做熔断,指的是调用方根据主观判断停止调用请求而去执行我们手动设置过的降级处理,返回的数据叫做熔断数据。
  • 降级指的是服务的提供方根据服务器状态信息,去执行指定的降级处理策略,返回的降级数据。

Sentinel-自定义受保护资源

* 5、自定义受保护资源
*  1、基于代码的自定义受保护资源
*     try(Entry entity = SphU.entry("自定义受保护资源名")) {
*      // 业务逻辑
*      } catch (BlockException e) {
*         //一定要配置被限流以后的默认返回
*      }
*  2、基于注解
*   @SentinelResource(value = "getCurrentSeckillSkusResource",blockHandler = "blockHandler")
*   无论是12方式一定要配置被限流以后的默认返回。
*   url请求可以设置统一返回:WebCallbackManager

基于代码的自定义受保护资源

这种适用于我们要保护的资源是一个对象时,直接在代码中可以将其标注出来其是受保护资源。

try(Entry entity = SphU.entry("自定义受保护资源名")) {
	  // 业务逻辑
} catch (BlockException e) {
  	//一定要配置被限流以后的默认返回
}

1、编写自定义受保护资源

修改“com.atguigu.gulimall.seckill.service.impl.SeckillServiceImpl”类 代码如下:

/**
 * 获取当前参与秒杀的商品
 * @return
 */
@Override
public List<SecKillSkuRedisTo> getCurrentSeckillSkus() {
    try(Entry entity = SphU.entry("seckillSkus")) {
        // 1、确定当前时间属于哪个秒杀场次
        long time = new Date().getTime();
        Set<String> keys = redisTemplate.keys(SESSION_CACHE_PREFIX + "*");
        for (String key : keys) {
            // seckill:sessions:1650153600000_1650160800000
            String replace = key.replace(SESSION_CACHE_PREFIX, "");
            String[] s = replace.split("_");
            long start = Long.parseLong(s[0]);
            long end = Long.parseLong(s[1]);
            if (time >= start && time <= end) {
                // 2、获取指定秒杀场次需要的所有商品信息
                List<String> range = redisTemplate.opsForList().range(key, -100, 100);
                BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);
                List<String> list = hashOps.multiGet(range);
                if (list != null) {
                    List<SecKillSkuRedisTo> collect = list.stream().map(item -> {
                        SecKillSkuRedisTo redis = JSON.parseObject((String) item, SecKillSkuRedisTo.class);
                        redis.setRandomCode(null);  // 当前秒杀开始了需要随机码
                        return redis;
                    }).collect(Collectors.toList());
                    return collect;
                }
                break;
            }
        }
    } catch (BlockException e) {
        log.error("资源被限流{}"+e.getMessage());
    }
    return null;
}

在这里插入图片描述

可以为自定义的受保护资源 加上流控、降级。

基于注解注解的自定义受保护资源

注解适用于要保护的资源是一个方法时,直接注解声明在方法上方。

 @SentinelResource(value = "getCurrentSeckillSkusResource",blockHandler = "blockHandler",fallback = "fallback")
  • blockHandler 函数会在原方法被限流/降级/系统保护的时候调用
  • fallback 会针对所有类型的异常
/**
 * getCurrentSeckillSkus()方法被限流/降级/系统保护的时候调用
 * @return
 */
public List<SecKillSkuRedisTo> blockHandler(BlockException e){
    log.error("getCurrentSeckillSkus()方法被限流/降级/系统保护");
    return null;
}
/**
 * 获取当前参与秒杀的商品
 * blockHandler 函数会在原方法被限流/降级/系统保护的时候调用
 * fallback 会针对所有类型的异常
 * @return
 */
@SentinelResource(value = "getCurrentSeckillSkusResource",blockHandler = "blockHandler")
@Override
public List<SecKillSkuRedisTo> getCurrentSeckillSkus() {
    try(Entry entity = SphU.entry("seckillSkus")) {
        // 1、确定当前时间属于哪个秒杀场次
        long time = new Date().getTime();
        Set<String> keys = redisTemplate.keys(SESSION_CACHE_PREFIX + "*");
        for (String key : keys) {
            // seckill:sessions:1650153600000_1650160800000
            String replace = key.replace(SESSION_CACHE_PREFIX, "");
            String[] s = replace.split("_");
            long start = Long.parseLong(s[0]);
            long end = Long.parseLong(s[1]);
            if (time >= start && time <= end) {
                // 2、获取指定秒杀场次需要的所有商品信息
                List<String> range = redisTemplate.opsForList().range(key, -100, 100);
                BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);
                List<String> list = hashOps.multiGet(range);
                if (list != null) {
                    List<SecKillSkuRedisTo> collect = list.stream().map(item -> {
                        SecKillSkuRedisTo redis = JSON.parseObject((String) item, SecKillSkuRedisTo.class);
                        redis.setRandomCode(null);  // 当前秒杀开始了需要随机码
                        return redis;
                    }).collect(Collectors.toList());
                    return collect;
                }
                break;
            }
        }
    } catch (BlockException e) {
        log.error("资源被限流{}"+e.getMessage());
    }
    return null;
}

还有第三种就是我们之前配置的一个web配置类,对所有url请求进行保护,只要它可以设置统一返回错误数据,而使用代码保护对象和使用注解保护方法都需要我们手动的指明限流之后的默认调用。

网关流控

网关流控

如果能在网关层进行流控,可以避免请求流入业务,减小服务压力

1、gulimall-gateway引入依赖

<!-- 引入sentinel网关限流 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>

注意引入的依赖要和gulimall-common的pom里的SpringCloudAlibaba版本一致

2、配置流控

API名称就是: 网关中配置文件中配置的路由的路由名

比如说指定请求头被限流:

在这里插入图片描述

3、自定义网关流控返回

package com.atguigu.gulimall.gateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.fastjson.JSON;
import com.atguigu.common.exception.BizCodeEnume;
import com.atguigu.common.utils.R;
import com.netflix.loadbalancer.Server;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
 * Data time:2022/4/18 17:21
 * StudentID:2019112118
 * Author:hgw
 * Description:
 */
@Configuration
public class SentinelGatewayConfig {
    public SentinelGatewayConfig() {
        GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
           // 网关限制了请求,就会调用此回调 Mono Flux
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                R error = R.error(BizCodeEnume.TO_MANY_REQUEST.getCode(), BizCodeEnume.TO_MANY_REQUEST.getMsg());
                String errJson = JSON.toJSONString(error);
                Mono<ServerResponse> body = ServerResponse.ok().body(Mono.just(errJson), String.class);
                return body;
            }
        });
    }
}

在这里插入图片描述

Zipkin链路追踪

  • 由于微服务项目模块众多,相互之间的调用关系十分复杂;
  • 为了分析工作过程中的调用关系,需要使用 Zipkin 来进行链路追踪

Sleuth 是 Spring Cloud 的组件之一,它为Spring Cloud实现了一种分布式追踪解决方案,兼容Zipkin基于日志的追踪系统。

相关术语

① Span ---- 基本的工作单元。无论是发送一个RPC(Remote Procedure Call)或是向RPC发送一个响应都是一个Span。每一个Span通过一个64位ID来进行唯一标识,并通过另一个64位ID对Span所在的Trace进行唯一标识。

Span能够启动和停止,他们不断地追踪自身的时间信息,当你创建了一个Span,你必须在未来的某个时刻停止它。

提示:启动一个Trace的初始化Span被叫作 Root Span ,它的 Span ID 和 Trace Id 相同。

② Trace ---- 由一系列 Span 组成的一个树状结构。例如,如果你要执行一个分布式大数据的存储操作,这个Trace也许会由你的PUT请求来形成。


感谢耐心看到这里的同学,觉得文章对您有帮助的话希望同学们不要吝啬您手中的赞,动动您智慧的小手,您的认可就是我创作的动力!
之后还会勤更自己的学习笔记,感兴趣的朋友点点关注哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/43945.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Security 身份验证的基本类/架构

目录 1、SecurityContextHolder 核心类 2、SecurityContext 接口 3、Authentication 用户认证信息接口 4、GrantedAuthority 拥有权限接口 5、AuthenticationManager 身份认证管理器接口 6、ProviderManager 身份认证管理器的实现 7、AuthenticationProvider 特定类型的…

数字孪生管控系统,智慧园区楼宇合集

智慧园区是指将物联网、大数据、人工智能等技术应用于传统建筑和基础设施&#xff0c;以实现对园区的全面监控、管理和服务的一种建筑形态。通过将园区内设备、设施和系统联网&#xff0c;实现数据的传输、共享和响应&#xff0c;提高园区的管理效率和运营效益&#xff0c;为居…

【Spring Cloud Gateway 新一代网关】—— 每天一点小知识

&#x1f4a7; S p r i n g C l o u d G a t e w a y 新一代网关 \color{#FF1493}{Spring Cloud Gateway 新一代网关} SpringCloudGateway新一代网关&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&a…

中医药行业如何进行数字化转型?看天津同仁堂谈“有道有术有零代码”

张伯礼院士曾指出&#xff0c;中药制造的现代化水平&#xff0c;还停留在10%左右的阶段。中医药行业&#xff0c;老字号企业&#xff0c;该如何通过数字化焕发新活力&#xff1f; 天津同仁堂通过与伙伴云合作&#xff0c;零代码构建数字化系统&#xff0c;让技术与思维共同成长…

html,css初学

安装VSCODE ,插件&#xff1a;live server &#xff0c;html support html 然后为了更好地理解&#xff0c;请逐步输入&#xff0c;并及时查看效果 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>D…

PCB封装设计指导(十一)画出脚标,极性标识和特殊器件标识

PCB封装设计指导(十一)画出脚标,极性标识,特殊器件标识 定义完pin number之后,就需要画出器件的脚标,极性标识,特殊标识等丝印相关的信息了,这些说明对辅助PCB布局有很好的作用,当然对后续贴片也很有帮助。 如何添加,具体见如下说明 1.脚标一般都用数字表示,silks…

力扣热门100题之和为k的子数组【中等】

题目描述 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的连续子数组的个数 。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2 示例 2&#xff1a; 输入&#xff1a;nums [1,2,3], k 3 输出&#xff1a;2 …

Acwing.898 数字三角形(动态规划)

题目 给定一个如下图所示的数字三角形&#xff0c;从顶部出发&#xff0c;在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点&#xff0c;一直走到底层&#xff0c;要求找出─条路径&#xff0c;使路径上的数字的和最大。 输入格式 第一行包含整数n&#xff0…

MES管理系统给汽配企业带来了哪些效益

汽车工业是一个庞大的社会经济系统工程&#xff0c;不同于普通产品&#xff0c;汽车产品是一个高度综合的最终产品&#xff0c;需要组织专业化协作的社会化大生产&#xff0c;需要相关工业产品与之配套。如何提高生产效率和产品质量成为了一个关键问题&#xff0c;而汽配企业ME…

EtherCAT转TCP/IP网关EtherCAT解决方案

你是否曾经为生产管理系统的数据互联互通问题烦恼过&#xff1f;曾经因为协议不同导致通讯问题而感到困惑&#xff1f;现在&#xff0c;我们迎来了突破性的进展&#xff01; 介绍捷米特JM-TCPIP-ECT&#xff0c;一款自主研发的Ethercat从站功能的通讯网关。它能够连接到Etherc…

RDIFramework.NET CS敏捷开发框架 V6.0发布(支持.NET6+、Framework双引擎,全网唯一)

全新RDIFramework.NET V6.0 CS敏捷开发框架发布&#xff0c;全网唯一支持.NET6&#xff0c;Framework双引擎&#xff0c;降低开发成本&#xff0c;提高产品质量&#xff0c;提升用户体验与开发团队稳定性&#xff0c;做软件就选RDIFramework.NET开发框架。 1、RDIFramework.NET…

毓恬冠佳冲刺上市:打破汽车天窗外商垄断,长安汽车为其主要客户

撰稿|行星 来源|贝多财经 7月23日&#xff0c;上海毓恬冠佳科技股份有限公司&#xff08;以下简称“毓恬冠佳”&#xff09;在深圳证券交易所的审核状态变更为“已问询”。据贝多财经了解&#xff0c;毓恬冠佳于2023年6月27日递交招股书&#xff0c;准备在创业板上市。 本次冲…

Linux---详解进程信号

进程信号 &#x1f373;信号理解&#x1f9c8;什么是信号&#xff1f;&#x1f95e;进程信号&#x1f953;查看系统信号&#x1f969;在技术角度理解信号&#x1f357;注意 &#x1f356;信号处理&#x1f9c7;信号异步机制 &#x1f354;信号产生&#x1f35f;通过终端按键产生…

vue中使用jsMind生成思维导图 截图功能踩坑

npm i jsmind先安装&#xff0c;再引入 import jsmind/style/jsmind.css import jsMind from jsmind/js/jsmind.js require(jsmind/js/jsmind.draggable.js) require(jsmind/js/jsmind.screenshot.js)正常引入是这样的&#xff0c;然后渲染也没问题 <template><div …

如何打开工业相机(海康)与halcon方式打开

使用海康相机&#xff0c;下载对应的客户端软件 地址&#xff1a;https://www.hikrobotics.com/cn/machinevision/service/download 界面如下&#xff1a; 使用 halcon 读取相机&#xff0c;需要将对应的动态链接库dll文件放入halcon的安装目录中&#xff0c;如下&#xff0c;…

全志F1C200S嵌入式驱动开发(spi-nor驱动)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 和v3s一样,f1c200s本身也支持spi-nor flash。当然,不管是norflash,还是nandflash,都是为了能够让程序脱离sd卡,直接依靠板子上面的flash,就可以完成正常地加载和运行工作。tf…

MySQL数据库优化

MySQL数据库优化 1.1 SQL及索引优化1.2 数据库表结构优化1.3 系统配置优化1.4 硬件配置优化 2 SQL及索引优化2.1 慢查日志2.1.1 检查慢查日志是否开启2.1.2 MySQL慢查日志的存储格式 2.2 MySQL慢查日志分析工具&#xff08;mysqldumpslow&#xff09;2.2.1 介绍2.2.2 用法 2.3 …

二进制子集题解

样例输入&#xff1a; 13样例输入&#xff1a; 0 1 4 5 8 9 12 13思路分析&#xff1a; 这道题大体就是进制转换然后按位 d f s dfs dfs。进制转换比较好理解&#xff0c;不懂得可以自行 b d f s ( 百度优先搜索 ) bdfs(百度优先搜索) bdfs(百度优先搜索)一下。 代码&#…

索引的数据结构

索引的数据结构 部分资料来自B站尚硅谷-宋红康老师 1. 为什么使用索引 使用索引是为了加快数据库的查询速度和提高数据库的性能。索引是数据库表中的一种数据结构&#xff0c;它可以帮助数据库快速定位并检索所需的数据。 当数据库表中的数据量较大时&#xff0c;如果没有索…

C#中简单Winform程序编译(待验证)

1、文件架构 2、MainWindow.xaml <Window x:Class"WpfApp1.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.…