Spring Cloud Alibaba Sentinel 集成与限流实战(6)

项目的源码地址
Spring Cloud Alibaba 工程搭建(1)
Spring Cloud Alibaba 工程搭建连接数据库(2)
Spring Cloud Alibaba 集成 nacos 以及整合 Ribbon 与 Feign 实现负载调用(3)
Spring Cloud Alibaba Ribbon 负载调用说明(4)
Spring Cloud Alibaba 核心理论 CAP与BASE理论简单理解(5)

目录

什么是Sentinel?

  • 阿里巴巴开源的分布式系统流控工具
  • 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性
  • 丰富的应用场景:消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
  • 完备的实时监控:Sentinel 同时提供实时的监控功能
  • 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合
  • 官网:home | Sentinel (sentinelguard.io)

核心概念:

  • 资源:是 Sentinel 中的核心概念之一,可以是java程序中任何内容,可以是服务或者方法甚至代码,总结起来就是我们要保护的东西
  • 规则:定义怎样的方式保护资源,主要包括流控规则、熔断降级规则等
    官方详细介绍 introduction | Sentinel (sentinelguard.io)

Sentinel 服务

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

Sentinel 控制台搭建

官方文档:https://github.com/alibaba/Sentinel/wiki/控制台
控制台包含如下功能:

  • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
  • 监控 (单机和集群聚合)通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
  • 规则管理和推送:统一管理推送规则。
  • 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
//启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本,
//-Dserver.port=8858 用于指定 Sentinel 控制台端口为 8858 
//默认用户名和密码都是 sentinel
​
java -Dserver.port=8858 -Dcsp.sentinel.dashboard.server=localhost:8858 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar

注意:

  • 如果是在 linux 系统上面,需要记得打开对应的端口防火墙
  • 如果是在 windows 上面,就要注意使用管理员模式运行命令行(另外需要使用 jdk 11),我本地是使用 jdk 17 的时候,启动报错

登录的用户名和密码:默认用户名和密码都是 sentinel
sentinel 控制台

程序集成 Sentinel

在 demo-order、demo-video 的 pom 文件中增加依赖

<!--添加sentinel客户端-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

修改对应的配置文件

#dashboard: 8080 控制台端口
#port: 9999 本地启的端口,随机选个不能被占用的,与dashboard进行数据交互,会在应用对应的机器上启动一个 Http Server,
# 该 Server 会与 Sentinel 控制台做交互, 若被占用,则开始+1一次扫描

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8858 
        port: 9999

微服务注册上去后,由于Sentinel是懒加载模式,所以需要访问微服务后才会在控制台出现
我们访问下: localhost:9000/api/v1/video_order/findById?videoId=30
访问请求

然后就可以看到 sentinel 的控制台上面增加了对应的模块信息了,我们多请求几次,可以看到 实时监控下面是有对应的数据收集
数据收集

基于QPS限流配置实战

我们是初步了解下怎么设置,先找到对应的模块的资源,然后设置流控规则,从这里可以看到,我们可以对指定的接口去设置流控,这个设置的颗粒度还是比较细的
找到资源路径

新增流控规则,这里我们为了方便于查看效果,就给一个单击阈值为:2新增流控规则

新增完了之后,可以在流控规则这里找到
流控规则

再次访问 localhost:9000/api/v1/video_order/findById?videoId=30,这次我们点击刷新的时候点击快一点:
流控报错

Sentinel流量控制功能

有了初步的操作之后,我们来简单的了解下 sentinel 的流控功能,首先我们先了解下什么是流量控制(flow control)?

原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

面板参数

面板参数
参数说明

  • 针对来源:Sentinel 可以针对调用者进行限流,填写具体微服务名时,指定对此微服务进行限流 (就是可以指定是哪个来源的进行限流,不是这个来源的不限流),默认值为 default(不区分来源,全部限制)。
  • 阈值类型/单机阈值:用于限制和控制流量的一种度量标准的类型,可以为 QPS(Queries Per Second,每秒请求数)也可以为“并发线程数”。
    • QPS:每秒请求达到此值开始限流。
    • 并发线程数:请求此资源的线程达到某个值时限流。每个请求分配一个线程,当请求执行时间长时,很快就会触发限流,相反如果线程执行速度快,那么限流触发就会概率就会比较小。
  • 流控模式:流量控制模式。
    • 直接:接口达到限流条件时,直接限流。
    • 关联:当关联的资源达到阈值时,就限流自己。
    • 链路:指定资源从入口资源进来的流量,如果达到阈值,就进行限流。
  • 流控效果:流量控制效果。
    • 快速失败:该方式是默认的流量控制方式,比如 QPS 超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
    • 排队等待(也叫匀速通过):排队等待会严格控制请求通过的间隔时间,让请求稳定且匀速的通过,可以用来处理间隔性突发的高流量。例如抢票软件,在某一秒或者一分钟内有大量的请求到来,而接下来的一段时间里处于空闲状态,我们希望系统能够在接下来的空余时间里也能出去这些请求,而不是直接拒绝。在设置排队等待时,需要填写超时时间。
    • Warm Up:此项叫做预热或者冷启动方式,此模式主要是防止流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮,通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。当使用 Warm Up 模式时,我们还需要指定启动时开放的 QPS 比例(DEFAULT_COLD_FACTOR,默认值为 3,代表 30%),以及系统预热所需时长(warmUpPeriodSec,默认值是 10 秒)。

限流页面当“是否集群”选中之后,就会是这样的界面:
集群勾选
其中最后一项“失败退化”中的 Token Server 含义如下:Token Server 是 Sentinel 用于集群流量控制的关键组件,它负责分发令牌并进行流量控制。当 Sentinel 的应用程序配置为集群限流模式时,它会向 Token Server 请求令牌,然后根据令牌情况来进行流量控制。 如果 Token Server 不可用,可能是由于网络故障、Token Server 实例崩溃等原因,这时候无法从 Token Server 获取令牌。Token Server 配置的含义如下:

  • 当配置选项为"是"时:表示当 Token Server 不可用时,Sentinel 会自动切换为单机限流模式。在单机限流模式中,Sentine 会从本地的限流规则进行流量控制,不再依赖 Token Server。这样可以保证即使 Token Server 不可用,也能够继续对流量进行限制。
  • 当配置选项为"否"时:表示当 Token Server 不可用时,Sentinel 不会自动切换为单机限流模式,流量控制会被暂停,即无法进行限流,可能会导致服务负载过高。

基于并发线程数限流

首先,在 OrderController 增加测试代码

@RequestMapping("list")
public Map list() throws InterruptedException {
    TimeUnit.SECONDS.sleep(5);
    return Map.of("title", "互联网架构之JAVA虚拟机JVM零基础到高级实战", "price", 199.00, "createTime", new Date());
}

然后测试访问下:http://localhost:9000/api/v1/video_order/list
测试访问
接着,配置对应的流控规则:
找到对应的资源
这里我们选择线程数,单机阈值为 1
设置阈值
重新请求 http://localhost:9000/api/v1/video_order/list,浏览器刷新两次
线程流控

流控效果-Warm Up 与 排队等待

Warm Up:冷启动/预热,如果系统在此之前⻓期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最⼤值。比如说,我们设置下面的值:就表示经过10s 达到最大阈值 90
流控规则
结合一个图再理解下
warm up

匀速排队
严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法,主要用于处理间隔性突发的流量,如消息队列,想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求
时间轴

注意:

  • 匀速排队等待策略是 Leaky Bucket 算法结合虚拟队列等待机制实现的。
  • 匀速排队模式暂时不支持 QPS > 1000 的场景
    官方文档: 流量控制 · alibaba/Sentinel Wiki (github.com)

熔断与降级

上面我们说了下流控相关的,这里我们开始讲讲面试经常问到的熔断与降级,熔断降级(虽然是两个概念,基本都是互相配合):

  • 对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一
  • 对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩
  • 熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置、

什么是 Sentinel 降级规则 ? 官方文档,点击这里查看 ,总的来说:就是配置一定规则,然后满足之后就对服务进行熔断降级

熔断策略

慢调用比例(响应时间)

选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。
- 比例阈值:
- 熔断时长:超过时间后会尝试恢复
- 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断
降级规则
这里对上面的规则进行说明,熔断触发的最小请求数为 5:

  • 请求数 < 5,即使异常比率超出阈值也不会熔断
  • 请求数 >= 5,就是表示只要有一个请求(比例阈值设置为 0.1 体现)的最大相应时间为 100毫秒(最大 RT 设置100体现),就熔断10s(熔断时长体现)

异常比例
当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断

  • 比例阈值
  • 熔断时长:超过时间后会尝试恢复。
  • 最小请求数:熔断触发的最小请求数,请求数小于该值时,即使异常比率超出阈值也不会熔断。
    异常比例

异常数
当单位统计时长内的异常数目超过阈值之后会自动进行熔断

  • 异常数:
  • 熔断时长:超过时间后会尝试恢复
  • 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断
    异常数

熔断的状态

服务熔断一般有三种状态

  • 熔断关闭(Closed):服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制
  • 熔断开启(Open):后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法
  • 半熔断(Half-Open):所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率
    熔断的状态

熔断的恢复:

  • 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态)尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。
  • 如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断状态

熔断降级的测试

第一步:增加测试源码
这里我们先修改下源码 OrderController,将 list 接口修改下:

int temp = 0;

/**
 * 用于测试熔断、降级
 *
 * @return map
 */
@RequestMapping("list")
private Map list(HttpServletRequest httpRequest) {

    temp++;

    if (temp % 3 == 0) {
        throw new RuntimeException("服务异常");
    }

    String serverInfo = httpRequest.getServerName() + ":"+ httpRequest.getServerPort();
    return Map.of("title", "测试返回数据", "name", "返回名称", "serverInfo", serverInfo);
}

代码比较简单,这样子就可以模拟出报错的情况,这里我就不贴报错的图片了
修改之后请求
第二步:增加降级规则
增加降级规则
这里我们为了测试方便,就选择异常比例的策略,阈值就选择0.1,点击新增,然后我们开始测试
新增规则

第三步:测试
访问:http://localhost:9000/api/v1/video_order/list ,然后快速刷新,就可以看到发生报错
发生熔断
报错之后,继续刷新的话还是报错,因为我们设置的是 10s 左右,我们等一会,再来请求:
再次请求

自定义流控异常

从上面的图,我们可以知道发生流控报错之后,就在页面上面显示了一个文字信息,但是我们实际生产中,更多的是使用 JSON 格式来传输数据,所以我们需要改造下。

具体的实现方式:

// 需要实现 BlockExceptionHandler 接口,然后在 handle 中写对应的业务逻辑
public class MyUrlBlockHandler implements BlockExceptionHandler {
   
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
    //降级业务处理
    }
}

sentinel 异常的种类

  • FlowException 限流异常
  • DegradeException 降级异常
  • ParamFlowException 参数限流异常
  • SystemBlockException 系统负载异常
  • AuthorityException 授权异常

增加对应的源码

@Component
public class MyUrlBlockHandler implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        Map<String,Object> backMap=new HashMap<>();
        if (e instanceof FlowException){
            backMap.put("code",-1);
            backMap.put("msg","限流-异常啦");
        }else if (e instanceof DegradeException){
            backMap.put("code",-2);
            backMap.put("msg","降级-异常啦");
        }else if (e instanceof ParamFlowException){
            backMap.put("code",-3);
            backMap.put("msg","热点-异常啦");
        }else if (e instanceof SystemBlockException){
            backMap.put("code",-4);
            backMap.put("msg","系统规则-异常啦");
        }else if (e instanceof AuthorityException){
            backMap.put("code",-5);
            backMap.put("msg","认证-异常啦");
        }

        // 设置返回json数据
        httpServletResponse.setStatus(200);
        httpServletResponse.setHeader("content-Type","application/json;charset=UTF-8");
        httpServletResponse.getWriter().write(JSON.toJSONString(backMap));
    }
}

源码结构
这里需要重新配置下限流或者降级的规则,不然是看不到效果的,这里我就随便配置一个降级策略,
新增的降级策略
多刷新几次就可以看到对应的效果了
在这里插入图片描述

Sentinel整合OpenFeign配置

我们这里调用是通过 order 服务 调用 video 服务 如果是说,在我们调用 video 服务的时候报错,或者说 video 服务现在不可用,我们让程序返回固定默认的数据,而不是直接报错返回。

整合的步骤

加入依赖

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

开启Feign对Sentinel的支持

feign:
  sentinel:
    enabled: true

开始Fegin 对 sentinel 的支持

创建容错类,实现对应的服务接口,记得加注解 @Service

@Service
public class VideoServiceFallback implements VideoService {
    @Override
    public Video findById(int videoId) {
        Video video = new Video();
        video.setTitle("熔断降级数据");
        return video;
    }@Override
    public Video saveVideo(Video video) {
        return null;
    }
}

增加 fallback

配置feign容错类,准备兜底数据

@FeignClient(value = "xdclass-video-service", fallback = VideoServiceFallback.class)

配置 fallBack
这个时候,我们只启动一个服务,就是 Order 服务,然后访问下: http://localhost:9000/api/v1/video_order/findById?videoId=30,好了现在就可以看到效果了
兜底数据

到此,我们就搞完了 sentinel 的基础入门了,我暂时也只学到了这些。 狗头.png,其实整个搭建都不算特别难,因为我们没有说去读源码那些(面试太卷了点),如果是学习使用的,这些应该可以应对很多场景了。

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

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

相关文章

RFID在汽车制造中的应用如何改变行业

随着工业4.0和中国制造2025的推进&#xff0c;企业对于智能化、自动化的需求日益增长&#xff0c;RFID射频技术在制造业中已经相当普遍了。在如今这瞬息万变的行业与时代中&#xff0c;RFID技术可以帮助企业获得竞争优势&#xff0c;简化日益复杂的生产流程&#xff0c;推动企业…

*args和**kwargs的使用

*args传入的是按照顺序的不定长度的参数列表 **kwargs传入的是不定长度的键值对

AI 资料汇总专栏

包含AI资料、大模型资料、AI最新行业发展 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一门研究如何使计算机能够具备智能行为的科学与技术。它致力于开发出能够像人类一样思考、学习、理解和决策的计算机系统。自20世纪50年代以来&#xff…

《第一行代码》第二版学习笔记(11)——最佳的UI体验

文章目录 一、Toolbar二、滑动菜单1、DrawerLayout——抽屉2、NavigationView 三、悬浮按钮和可交互提示1、FloatingActionButton——悬浮按钮2、Snackbar——提示工具3、CoordinatorLayout 四、卡片式布局1、cardView2、AppBarLayout 五、下拉刷新——SwipeRefreshLayout六、可…

栈与递归的实现

1. 栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则&#x…

教你解决PUBG绝地求生登不进去 无法进入游戏 启动很慢的问题

尽管《绝地求生》&#xff08;PUBG&#xff09;以它那扣人心弦的战术竞技和逼真模拟的战场氛围风靡全球&#xff0c;揽获无数玩家的喜爱&#xff0c;但一些玩家在经历了一场血脉喷张的生存较量后&#xff0c;却不得不面对一个不那么愉悦的后续&#xff1a;游戏在结算阶段后出现…

docker学习笔记(五):harbor仓库搭建与简单应用

harbor私有仓库 简介 Docker容器应用的开发和运行离不开可靠的镜像管理&#xff0c;虽然Docker官方也提供了公共的镜像仓库&#xff0c;但是从安全和效率等方面考虑&#xff0c;部署私有环境内的Registry也是非常必要的。Harbor是由VMware公司开源的企业级的Docker Registry管…

文献速递:深度学习医学影像心脏疾病检测与诊断--基于迁移学习的生成对抗网络用于静态和动态心脏PET的衰减校正

Title 题目 Transfer learning‑based attenuation correction for static and dynamic cardiac PET using a generative adversarial network 基于迁移学习的生成对抗网络用于静态和动态心脏PET的衰减校正 01 文献速递介绍 心脏正电子发射断层扫描&#xff08;PET&#xf…

JAVA入门1.1.0

前言&#xff1a; 不一样的编程——基于两个大前提&#xff0c;语言随便选一个&#xff0c;作者选java和c&#xff0c;在后续的内容会有c和java的共同使用 第一大前提&#xff1a;编程语言起源于语言 第二大前提&#xff1a;计算机理解不了语言的含义 这两大前提构成了不一样的…

Word设置代码块格式

前言 Word中无法像Markdown和LaTeX一样插入代码块&#xff0c;若要在Word中插入代码块可以手动设置代码块格式或自动粘贴代码块格式。若不追求完美高亮效果&#xff0c;可使用前者方案&#xff1b;若追求完美的高亮效果&#xff0c;可使用后者方案。下文介绍这2种方案。 手动…

渲染农场评测:6大热门云渲染平台全面比较

在3D行业中&#xff0c;选择一个合适的云渲染平台可能会令许多专业人士感到难以抉择。为此&#xff0c;我们精心准备了6家流行云渲染平台的详尽评测&#xff0c;旨在为您的决策过程提供实用的参考和支持。 目前&#xff0c;市面上主要的3D网络渲染平台包括六大服务商&#xff0…

SQL编程

用户变量的语法使用 #MySQL变量的定义与使用 #一、标识符命名规范 #1、字母加数字&#xff0c;但不允许使用数字开头 #2、不允许使用关键字或保留字 #3、符号只可以使用“_”或“$" #二、变量的声明 #set用于声明变量&#xff0c;update声明修改的表&#xff0c;set是声明…

OpenGL入门第三步:矩阵变换、坐标系统

1、矩阵变换 这里矩阵变换,使用4*4的矩阵,既可以表示位移,也可以表示缩放。 原因: 添加4维矩阵变量 initializeGL()函数:在着色器里面添加变换矩阵,改变坐标位置 设计一个随时间变换 ,所有重写TimerEvent 调用update触发paintGL()函数: 2、坐标系统

NSSCTF中的web学习(md5())

目录 MD5的学习 [BJDCTF 2020]easy_md5 [LitCTF 2023]Follow me and hack me [LitCTF 2023]Ping [SWPUCTF 2021 新生赛]easyupload3.0 [NSSCTF 2022 Spring Recruit]babyphp MD5的学习 md5()函数&#xff1a; md5($a)&#xff1a;返回a字符串的散列值 md5($a,TRUE)&…

C#中字典Dictionary与自定义类型CustomType之间的转换

C#中字典Dictionary与自定义类型CustomType之间的转换 思路&#xff1a; 可以使用反射System.Reflection来获取类的具体属性&#xff0c; 属性名称就映射字典的键Key。 新建控制台程序DictionaryCustomClassConversionDemo 第一步、新建关键转换类ConversionUtil。 类Con…

GB2312发码测试

编码表&#xff1a;https://www.toolhelper.cn/Encoding/GB2312 GB2312 编码表 GB 2312 标准由中国国家标准总局 1980 年发布&#xff0c;GB 即国标&#xff0c;共收录 6763 个汉字&#xff0c;其中一级汉字 3755 个&#xff0c;二级汉字 3008 个。 GB 2312 的出现&#xff0…

领导关怀 | 西湖区委常委韩斌等一行领导调研创邻科技

5月8日&#xff0c;西湖区委常委韩斌、紫金港科技城管委会党委委员、副主任陈杰、西湖区委办副主任韩鹰等一行领导走访创邻科技&#xff0c;关心企业发展近况。创邻科技COO吴菁、CTO周研陪同参观交流。 韩斌常委一行首先参观了企业荣誉展示区和办公区。参观过程中&#xff0c;…

3D Gaussian Splatting for Real-Time Radiance Field Rendering 论文阅读

如此热门的项目&#xff0c;网络上有很多大牛分析了这篇文章的做法&#xff0c;在这里简单记录一下个人粗浅的理解。 关于各种数学表达式的推导&#xff0c;论文和参考资料中都提供了较为详细的解读&#xff0c;本人能力有限&#xff0c;这一部分理解不够深刻&#xff0c;先不做…

Git 如何管理标签命令(tag)

1.查看本地仓库tag --1.查看本地仓库tag UserDESKTOP-2NRT2ST MINGW64 /e/GITROOT/STARiBOSS/STARiBOSS-5GCA (gw_frontend_master) $ git tag 1stBossUpgrade V10.0.1_20220224_test V10.0.1_20220301_test tag-gwfrontend-V1.0.12-230625 tag-gw_frontend-23.08.29 tag-gw_f…

【python基础】python经典题目100题

文章目录 前言初阶题目1.字符串2.列表3.元组4.字典5.运算6.random 模块7.open函数8.time模块时间9.其他 进阶题目 前言 本文主要是python经典题目100题&#xff0c;适合入门的新手。仅作自己学习的记录。 初阶题目 1.字符串 题目1&#xff1a;怎么找出序列中的最⼤最⼩值&am…
最新文章