详解如何保证消息队列不丢失消息(以kafka为例)

news2024/12/25 13:05:07

✨✨祝屏幕前的小伙伴们每天都有好运相伴左右,一定要天天开心!✨✨ 
🎈🎈作者主页: 喔的嘛呀🎈🎈

目录

一、引言

二. 持久化存储

2.1持久化存储原理:

2.2使用示例:

1. 安装 Kafka:

2. 生产者代码:

3. 消费者代码:

三. 消息确认机制

3.1消息确认机制原理:

3.2使用示例:

1. 生产者代码:

2. 消费者代码:

四. 事务机制

4.1事务机制原理:

4.2使用示例:

1. 生产者代码:

2. 消费者代码:

五. 数据备份与复制

5.1数据备份与复制原理

5.2使用示例:

1. Kafka Broker配置:

2. 生产者代码

3. 消费者代码

六. 消息过期机制

总结


一、引言

消息队列(Message Queue)是一种用于在不同组件、服务或系统之间传递消息的通信方式。在分布式系统中,消息队列起到了缓冲和解耦的作用,但在使用过程中,如何保证消息不丢失是一个重要的问题。下面详细探讨一下消息队列如何保证消息不丢失的方法。Apache Kafka是一个分布式消息系统,设计和实现了一套机制来保证消息队列中的消息不丢失。以下是一些关键的配置和实践方法。

二. 持久化存储

为了防止消息在队列中丢失,消息队列系统通常会提供持久化存储的机制。这意味着一旦消息被接收,它会被存储在持久化存储中,即使系统崩溃或重启,消息仍然可以被恢复。这种机制通常使用文件系统或数据库来实现。

在Java中使用消息队列的持久化存储,我们以Apache Kafka为例进行演示。Kafka是一个分布式的、可持久化的消息队列系统,适用于大规模的数据流处理。

2.1持久化存储原理:

Kafka通过将消息写入磁盘上的日志文件(日志段)来实现持久化存储。每个消息都会被追加到日志文件的末尾,确保消息在写入后不会被修改,从而保证了消息的持久性。

2.2使用示例:

1. 安装 Kafka:

首先,确保你已经安装并启动了 Kafka。你可以从 Kafka官方网站 下载并按照官方文档进行安装和启动。

2. 生产者代码:

import org.apache.kafka.clients.producer.*;

import java.util.Properties;

public class KafkaProducerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        // 创建生产者
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        // 发送消息,将消息设置为持久化
        ProducerRecord<String, String> record = new ProducerRecord<>("example_topic", "Hello, Kafka!");
        producer.send(record, new Callback() {
            @Override
            public void onCompletion(RecordMetadata metadata, Exception exception) {
                if (exception == null) {
                    System.out.println("Message sent successfully. Offset: " + metadata.offset());
                } else {
                    exception.printStackTrace();
                }
            }
        });

        producer.close();
    }
}

3. 消费者代码:

import org.apache.kafka.clients.consumer.*;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("group.id", "example_group");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        // 创建消费者
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // 订阅主题
        consumer.subscribe(Collections.singletonList("example_topic"));

        // 拉取消息,将消息设置为持久化
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
            for (ConsumerRecord<String, String> record : records) {
                System.out.printf("Received message: offset = %d, key = %s, value = %s%n",
                        record.offset(), record.key(), record.value());
            }
        }
    }
}

在上述代码中,通过将生产者和消费者配置中的acks属性设置为all(默认值),Kafka会等待消息被所有同步副本接收确认后再继续发送。这确保了消息在发送和接收时都会被持久化存储。

请注意,Kafka的配置和使用可能因版本而异,确保查阅相应版本的文档以获取准确的配置信息。

三. 消息确认机制

消息队列系统通常支持消息确认机制,确保消息在被消费者成功处理后才被标记为已处理。消费者在成功处理消息后发送确认给消息队列,然后消息队列才会将该消息从队列中移除。如果消费者处理失败,消息队列可以将消息重新投递给队列或者按照配置进行其他处理。

消息确认机制是确保消息在被消费者成功处理后才被标记为已处理的关键机制。在这里,我们将使用Apache Kafka作为示例进行演示,展示消息确认机制的实现。

3.1消息确认机制原理:

在Kafka中,消息确认机制主要通过Producer的acks参数和Consumer的手动确认来实现。acks参数表示生产者要求服务器确认消息的级别,而手动确认则是消费者在成功处理消息后通过调用特定的API来通知服务器。

3.2使用示例:

1. 生产者代码:

import org.apache.kafka.clients.producer.*;

import java.util.Properties;

public class KafkaProducerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("acks", "all");  // 设置为all表示等待所有副本确认

        // 创建生产者
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        // 发送消息,等待确认
        ProducerRecord<String, String> record = new ProducerRecord<>("example_topic", "Hello, Kafka!");
        producer.send(record, new Callback() {
            @Override
            public void onCompletion(RecordMetadata metadata, Exception exception) {
                if (exception == null) {
                    System.out.println("Message sent successfully. Offset: " + metadata.offset());
                } else {
                    exception.printStackTrace();
                }
            }
        });

        producer.close();
    }
}

2. 消费者代码:

import org.apache.kafka.clients.consumer.*;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("group.id", "example_group");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        // 创建消费者
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // 订阅主题
        consumer.subscribe(Collections.singletonList("example_topic"));

        // 拉取消息
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
            for (ConsumerRecord<String, String> record : records) {
                System.out.printf("Received message: offset = %d, key = %s, value = %s%n",
                        record.offset(), record.key(), record.value());

                // 手动确认消息
                consumer.commitSync();
            }
        }
    }
}

在上述代码中,生产者的acks属性设置为all,表示等待所有副本确认。而消费者在处理完消息后,通过调用consumer.commitSync()手动确认消息。这确保了消息在被成功处理后才被标记为已处理。

请注意,Kafka的确认机制可能因版本而异,确保查阅相应版本的文档以获取准确的配置信息。

四. 事务机制

一些消息队列系统支持事务机制,允许生产者发送一组消息,并且只有在这组消息都成功写入队列后才被提交。如果有任何一个消息写入失败,整个事务会被回滚,从而确保消息的一致性。

事务机制是确保消息队列中一组消息要么全部成功处理,要么全部回滚的重要机制。在这里,我们以Apache Kafka为例进行演示,展示事务机制的实现。

4.1事务机制原理:

Kafka的事务机制主要涉及Producer API的事务支持。生产者可以在一组消息的发送过程中开启事务,然后要么全部提交(所有消息发送成功),要么全部回滚(任何一个消息发送失败)。

4.2使用示例:

1. 生产者代码:

import org.apache.kafka.clients.producer.*;

import java.util.Properties;

public class KafkaTransactionalProducerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("acks", "all");  // 设置为all表示等待所有副本确认
        props.put("enable.idempotence", "true");  // 开启幂等性
        props.put("transactional.id", "my-transactional-id");  // 设置事务ID

        // 创建生产者
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        // 开启事务
        producer.initTransactions();

        try {
            producer.beginTransaction();

            // 发送消息
            ProducerRecord<String, String> record1 = new ProducerRecord<>("example_topic", "Message 1");
            ProducerRecord<String, String> record2 = new ProducerRecord<>("example_topic", "Message 2");

            producer.send(record1);
            producer.send(record2);

            // 提交事务
            producer.commitTransaction();
        } catch (ProducerFencedException | OutOfOrderSequenceException | AuthorizationException e) {
            // 处理异常,中止事务
            producer.close();
        } catch (KafkaException e) {
            // 处理其他Kafka异常,回滚事务
            producer.abortTransaction();
        }

        producer.close();
    }
}

在上述代码中,通过设置enable.idempotencetrue和配置transactional.id为唯一的事务ID,生产者开启了事务。然后,通过beginTransactioncommitTransactionabortTransaction来控制事务的提交和回滚。

请注意,生产者中使用了enable.idempotence开启幂等性,这对于确保消息不会被重复发送也是非常重要的。同时,确保事务ID是唯一的,以避免与其他事务冲突。

2. 消费者代码:

消费者的代码相对简单,与普通的消费者代码基本相同。消费者不直接参与生产者的事务,而是通过消费消息来处理相关业务逻辑。

import org.apache.kafka.clients.consumer.*;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("group.id", "example_group");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        // 创建消费者
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // 订阅主题
        consumer.subscribe(Collections.singletonList("example_topic"));

        // 拉取消息
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
            for (ConsumerRecord<String, String> record : records) {
                System.out.printf("Received message: offset = %d, key = %s, value = %s%n",
                        record.offset(), record.key(), record.value());
            }
        }
    }
}

在实际应用中,消费者的业务逻辑可能会与生产者的事务有关,例如在接收到特定消息时触发某些操作。在这种情况下,需要谨慎处理事务间的协调。

五. 数据备份与复制

数据备份与复制是确保消息队列系统可靠性和容错性的关键机制之一。在这里,我们以Apache Kafka为例进行演示,展示数据备份与复制的实现。

5.1数据备份与复制原理

Kafka通过数据备份与复制来防止因节点故障或灾难性事件导致的数据丢失。每个分区的数据会被复制到多个副本,这些副本分布在不同的节点上。这样即使一个节点发生故障,仍然可以从其他节点的副本中恢复数据。

5.2使用示例:

1. Kafka Broker配置:

在Kafka的server.properties配置文件中,可以配置副本的数量和复制策略。

# server.properties

# 设置每个分区的副本数量
default.replication.factor=3

# 设置副本的分布策略,可以选择不同的策略
# 可选值为: "rack-aware", "broker-aware", "0-1" (default)
# 具体策略的选择根据实际需求和环境
replica.selector.class=org.apache.kafka.common.replica.RackAwareReplicaSelector

2. 生产者代码

import org.apache.kafka.clients.producer.*;

import java.util.Properties;

public class KafkaProducerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        // 创建生产者
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        // 发送消息
        ProducerRecord<String, String> record = new ProducerRecord<>("example_topic", "Hello, Kafka!");
        producer.send(record, new Callback() {
            @Override
            public void onCompletion(RecordMetadata metadata, Exception exception) {
                if (exception == null) {
                    System.out.println("Message sent successfully. Offset: " + metadata.offset());
                } else {
                    exception.printStackTrace();
                }
            }
        });

        producer.close();
    }
}

3. 消费者代码

import org.apache.kafka.clients.consumer.*;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("group.id", "example_group");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        // 创建消费者
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // 订阅主题
        consumer.subscribe(Collections.singletonList("example_topic"));

        // 拉取消息
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
            for (ConsumerRecord<String, String> record : records) {
                System.out.printf("Received message: offset = %d, key = %s, value = %s%n",
                        record.offset(), record.key(), record.value());
            }
        }
    }
}

在上述代码中,通过设置default.replication.factor来指定每个分区的副本数量,这里设置为3。副本的分布策略由replica.selector.class指定,这里选择了RackAwareReplicaSelector,可根据实际需求选择其他策略。

请注意,这里的代码示例主要是演示Kafka的配置和使用,实际上,Kafka会自动处理数据的备份和复制,你无需手动编写代码来执行这些操作。

六. 消息过期机制

消息过期机制是一种保证消息不会永远存在于消息队列中的重要机制。在消息队列系统中,可以设置消息的过期时间,一旦消息过期,系统会自动将其删除或标记为无效。消息过期机制有助于确保系统中的消息不会占用过多的资源并且能够及时清理不再需要的消息。

在Apache Kafka中,消息的过期机制并不是直接支持的特性,而是通过消费者在处理消息时判断消息的时间戳或其他属性来实现的。以下是一个简单的示例,展示了如何在消费者端处理消息的过期逻辑。

import org.apache.kafka.clients.consumer.*;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

public class KafkaConsumerWithExpirationExample {
    public static void main(String[] args) {
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("group.id", "example_group");
        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

        // 创建消费者
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // 订阅主题
        consumer.subscribe(Collections.singletonList("example_topic"));

        // 拉取消息
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
            for (ConsumerRecord<String, String> record : records) {
                // 判断消息是否过期(假设消息中包含时间戳字段)
                long timestamp = Long.parseLong(record.value());
                long currentTimestamp = System.currentTimeMillis();

                // 设置消息过期时间为10分钟
                long expirationTime = 10 * 60 * 1000;

                if (currentTimestamp - timestamp < expirationTime) {
                    // 处理消息
                    System.out.printf("Received message: offset = %d, key = %s, value = %s%n",
                            record.offset(), record.key(), record.value());
                } else {
                    // 消息过期,可以进行相应的处理,例如记录日志或丢弃消息
                    System.out.printf("Expired message: offset = %d, key = %s, value = %s%n",
                            record.offset(), record.key(), record.value());
                }
            }
        }
    }
}

在上述代码中,假设消息中包含一个时间戳字段,消费者在处理消息时通过比较时间戳判断消息是否过期。如果消息过期,可以根据实际需求进行相应的处理,例如记录日志或丢弃消息。

请注意,这只是一个简单的示例,实际上,消息的过期机制可能需要根据具体的业务逻辑和消息队列系统的特性进行更复杂的处理。

总结

综上所述,消息队列通过持久化存储、消息确认机制、事务机制、数据备份与复制以及消息过期机制等手段,保证了消息在传递过程中不丢失。在设计分布式系统时,合理选择并配置这些机制可以有效地提高消息队列的可靠性和稳定性。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

递归法解决多重背包问题

多重背包问题同样是01背包问题的变种&#xff0c;同样可以通过修改01背包部分代码来求解。 方法一&#xff1a;修改递归函数&#xff0c;根据题目新的限制条件——使用次数扩充状态参数个数&#xff0c;将同一个物品选用的次数同样作为参数传递到栈空间中&#xff0c;同时也对…

赖迪思软件 lattice Diamond

问题1&#xff1a;工程编译好后&#xff0c;git上传&#xff0c;变更分支又切换回来&#xff0c;再次编译有时候失败&#xff0c;所以配置好的管脚变成默认的&#xff0c;生成的IP核变成名变粗&#xff08;顶部文件&#xff0c;管脚配置显示IP核输入输出信号配置&#xff09;。…

PHP设计模式初探 以前写的完整PPT!!!!!

幻灯片 1: 初探PHP设计模式 copyright CSDN 白毛大侠 幻灯片 2: 我们说别人代码写的烂&#xff0c;烂在哪&#xff1f; 反思我们平时是怎么写代码的&#xff1f; 非开发者如何转开发&#xff08;业务&#xff09; &#xff1f; 一.过程与对象 幻灯片 3: <?…

17.来自Sora的夺舍妄想——享元模式详解

OpenAI 的 Sora 模型面世之后&#xff0c;可以说人类抵御AI的最后阵地也沦陷了。 在此之前&#xff0c;人们面对AI交互式对话&#xff0c;AI制图&#xff0c;AI建模之类的奇迹时&#xff0c;还可以略微放肆的说&#xff1a;“的确很神奇&#xff0c;这毕竟还是比人类世界低了一…

抖音视频评论数据挖掘软件|视频批量下载工具

这款基于C#开发的抖音视频评论数据挖掘软件是一款功能强大、易于使用的工具。它不仅支持通过关键词进行搜索抓取&#xff0c;还能够通过分享链接进行单个视频的抓取和下载。主要功能模块如下&#xff1a; 批量视频提取 操作模块&#xff1a;用户可以输入要搜索的关键词&#…

python:pyecharts 画基金净值 月K线图

pip install pyecharts1.9.1 pyecharts-1.9.1-py3-none-any.whl 我想在本地&#xff08;PC) 画出 基金净值 月K线图&#xff0c;不想每次看图都需联网。 cd my_dir mkdir echarts cd echarts curl -O https://assets.pyecharts.org/assets/echarts.min.js 修改一下开源代码 …

【飞桨EasyDL】飞桨EasyDL发布的模型转换onnx(附工程代码)

一个愿意伫立在巨人肩膀上的农民...... 一、paddle转onnx转rknn环境搭建 paddle转onnx和onnx转rknn两个环境可以分开搭建&#xff0c;也可以搭建在一起。这里选择分开搭建&#xff0c;先搭建paddle转onnx。 1.1、创建环境 选择python3.8.13包进行创建环境 conda create --nam…

Ubuntu22.04下在Spark2.4.0中采用Local模式配置并启动pyspark

目录 一、前言 二、版本信息 三、配置相关文件 1.修改spark-env.sh文件 2.修改.bashrc文件 四、安装Python3.5.2并更改默认Python版本 1.查看当前默认Python版本 2.安装Python3.5.2 2.1 下载Python源码 2.2 解压源码 2.3 配置安装路径 2.4 编译和安装 2.5 验证安装…

走进SQL审计视图——《OceanBase诊断系列》之二

1. 前言 在SQL性能诊断上&#xff0c;OceanBase有一个非常实用的功能 —— SQL审计视图(gv$sql_audit)。在OceanBase 4.0.0及更高版本中&#xff0c;该功能是 gv$ob_sql_audit。它可以使开发和运维人员更方便地排查在OceanBase上运行过的任意一条SQL&#xff0c;无论这些SQL是成…

最近半年博客产出的反思

最近完善boss资料的时候&#xff0c;我认为自己在大学期间学习过程中经常用博客记录学习内容以及在学习过程中写博客笔记是个不错的好习惯&#xff0c;在询问了师傅的意见之后决定把CSDN的主页也挂上去。 非常荣幸平台上今天有一位老师看见我的简历之后主动和我交流。对我的博客…

Sora来袭!机器人+Sora落地性如何?

2022年底&#xff0c;OpenAI正式推出ChatGPT&#xff0c;这款由人工智能技术驱动的自然语言处理工具能够通过学习和理解人类的语言来进行对话 。ChatGPT是OpenAI迈出的第一步&#xff0c;这款让所有人都能体会到人工智能潜力的现象级产品&#xff0c;展现出了文字对于过去人工智…

Xcode15与苹果ios17适配以及遇到的问题

大家好&#xff0c;我是你们的好朋友咕噜铁蛋&#xff01;最近&#xff0c;苹果发布了全新的iOS17系统&#xff0c;而作为开发者&#xff0c;我们需要确保我们的应用程序能够与这个新系统完美适配。因此&#xff0c;今天我将和大家分享一些关于Xcode15与苹果17系统适配的经验&a…

手写 Attention 迷你LLaMa2——LLM实战

https://github.com/Yuezhengrong/Implement-Attention-TinyLLaMa-from-scratch 1. Attention 1.1 Attention 灵魂10问 你怎么理解Attention&#xff1f; Scaled Dot-Product Attention中的Scaled&#xff1a; 1 d k \frac{1}{\sqrt{d_k}} dk​ ​1​ 的目的是调节内积&…

Parallel Computing - 一文讲懂并行计算

目录 Throughput/LatencySerial ComputingParallel ComputingTypes of parallel computersSimple 4-width SIMDAmdahls lawTypes of parallelism**Data Parallel Model**Task parallel PartitioningDomain DecompositionFunctional Decomposition CommunicationsExample that d…

Android 基础入门 基础简介

1. 观察App运行日志 2.Android 开发设计的编程语言 koltin Java c c 3.工程目录结构 4.Gradle 5.build.gradle 文件解析 plugins {id("com.android.application")//用了哪些插件 主配置文件版本控制 所以这里不用写版本 }android {namespace "com.tiger.myap…

unity学习(44)——选择角色菜单——顺利收到服务器的数据

本节的思路参考自&#xff0c;内容并不相同&#xff1a;13ARPG网络游戏编程实践&#xff08;十三&#xff09;&#xff1a;角色选择UI及创建面板制作&#xff08;四&#xff09;_哔哩哔哩_bilibili 现在的代码写在MessageManager.cs中&#xff0c;函数名UserHandler(是从OnMess…

mongodb 图形界面工具 -- Studio 3T(下载、安装、连接mongodb数据库)

目录 mongodb 图形界面工具 -- Studio 3T下载安装第一次使用&#xff1a;注册添加一个连接&#xff08;连接 mongodb 数据库&#xff09;1、点击【添加新连接】&#xff0c;选择【手动配置我的连接设置】2、对 Server 设置连接数据3、连接的用户认证设置&#xff08;创建数据库…

【系统分析师】-需求工程

一、需求工程 需求工程分为需求开发和需求管理。 需求开发&#xff1a;需求获取&#xff0c;需求分析&#xff0c;需求定义、需求验证。 需求管理&#xff1a;变更控制、版本控制、需求跟踪&#xff0c;需求状态跟踪。&#xff08;对需求基线的管理&#xff09; 1.1需求获取…

BUGKU 网站被黑

打开环境&#xff0c;什么都没发现&#xff0c;使用蚁剑扫描一下&#xff0c;发现shell.php&#xff0c;打开 使用BP抓包&#xff0c;进行爆破 得到密码&#xff1a;hack 进去得到flag

【python】1.python3.12.2和pycharm社区版的安装指南

欢迎来CILMY23的博客喔&#xff0c;本篇为【python】1.python3.12.2和pycharm社区版的安装指南&#xff0c;感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 目录 一、python3.12.2的下载与安装 1.1下载 1.2安装 二、pycharm的安装 2.1下载安装 2…