Pulsar-Schema 数据结构

news2024/10/5 13:39:14

Pulsar-Schema 数据结构

  • 为什么需要使用Schema?
  • 怎么使用?
  • 生产者端
  • 消费者端
  • 使用用例
  • Schema定义
  • Schema类型
  • 基本类型
  • 复合类型
    • KeyValue schema
    • Struct schema
    • Pulsar提供了以下方法来使用结构模式
      • static
      • generic
  • 自动Schema
  • Schema验证实施
  • Schema演化
  • Schema版本控制
  • Schema兼容性检查
  • Schema兼容性检查策略
  • Schema自动更新
    • 生产者端(producer)
    • 消费端(Consume)
  • 客户端升级顺序

Pulsar消息存储为非结构化字节数组,数据结构(称为模式)仅在读取数据时应用于该数据。因此,生产者和消费者都需要就消息的数据结构(包括字段及其相关类型)达成一致
Pulsar Schema是定义如何将原始消息字节转换为更正式的结构类型的元数据,作为生成消息的应用程序和使用消息的应用程序之间的协议。它在将数据发布到主题之前将数据序列化为原始字节,
并在将原始字节交付给消费者之前将其反序列化
Pulsar使用Schema注册中心作为存储已注册Schema信息的中央存储库,通过代理协调主题消息的Schema
在这里插入图片描述

为什么需要使用Schema?

类型安全在任何围绕消息传递和流系统构建的应用程序中都非常重要,原始字节对于数据传输来说很灵活,但灵活性和中立性是有代价的:
我们必须覆盖数据类型检查,需要序列化和反序列化,确保输入系统的字节可以被读取并成功使用。换句话说,我们需要确保数据对应用程序是可理解的和可用的

Pulsar Schema通过以下功能解决了痛点:

  • 提供用于存储关于组织中使用的Schema的信息的中心位置,从而极大地简化了跨应用程序团队共享这些信息
  • 当主题定义了Schema时,执行数据类型安全。因此消费者和生产者只有在使用“兼容”模式时才允许连接
  • 作为跨所有服务和开发团队使用的所有消息模式的单一真实来源,这使他们更容易协作
  • 保持Schema版本之间的数据兼容性。上传新Schema时,旧用户可以读取新版本
  • 存储在现有的存储层BookKeeper中,无需额外的系统

怎么使用?

Pulsar Schema在主题级别应用和执行。生产者和消费者可以将模式上传到代理,因此Pulsar模式在双方都可以工作

生产者端

该图说明了Pulsar模式如何在生产者端工作:
在这里插入图片描述

  1. 应用程序使用模式实例来构造生产者实例。模式实例为使用生产者实例生成的数据定义模式。以Avro为例,Pulsar从POJO类中提取模式定义并构造SchemaInfo
  2. 生产者请求使用从传入的模式实例中提取的SchemaInfo连接到代理
  3. 代理查找模式注册表,以检查它是否是已注册的模式
    • 如果模式已注册,代理将模式版本返回给生产者
    • 否则,代理检查模式是否可以自动更新
  4. 代理检查模式是否可以自动更新
    • 如果不允许自动更新,则模式不能注册,代理将拒绝生产者
    • 否则,代理执行为主题定义的模式兼容性检查
  5. 代理执行为主题定义的模式兼容性检查
    • 如果模式通过了兼容性检查,代理将其存储在模式注册表中,并将模式版本返回给生产者。此生成器生成的所有消息都使用模式版本进行标记。
    • 否则,代理拒绝生产者

消费者端

该图说明了模式如何在消费者端工作:
在这里插入图片描述

  1. 应用程序使用模式实例来构造使用者实例
  2. 使用者使用从传入的模式实例中提取的SchemaInfo连接到代理
  3. 代理检查主题是否正在使用(至少有一个对象:模式、数据、活动生产者或消费者)
    • 如果主题至少包含上述对象之一,代理执行模式兼容性检查
    • 否则,代理检查模式是否可以自动更新
  4. 代理检查模式是否可以自动更新
    • 如果模式可以自动更新,代理将注册模式并连接使用者
    • 否则,代理拒绝消费者
  5. 代理执行模式兼容性检查
    • 如果模式通过兼容性检查,代理将连接使用者
    • 否则,代理将拒绝使用者

使用用例

在构造和处理从简单数据类型(如字符串)到更复杂的特定于应用程序类型的消息时,可以使用特定于语言的数据类型

创建一个user对象:

public class User {
   public String name;
   public int age;
   
   User() {}
   
   User(String name, int age) {
      this.name = name;
      this.age = age;
   }
}

不使用Schema:

Producer<byte[]> producer = client.newProducer()
        .topic(topic)
        .create();
User user = new User("Tom", 28);
byte[] message =// 这里就需要自己实现序列化;   
producer.send(message);

使用Schema:

// send with json schema
Producer<User> producer = client.newProducer(JSONSchema.of(User.class))
        .topic(topic)
        .create();
User user = new User("Tom", 28);
producer.send(user);

// receive with json schema
Consumer<User> consumer = client.newConsumer(JSONSchema.of(User.class))
   .topic(schemaTopic)
   .subscriptionInitialPosition(SubscriptionInitialPosition.Earliest)
   .subscriptionName("schema-sub")
   .subscribe();
Message<User> message = consumer.receive();
User user = message.getValue();
assert user.age == 28 && user.name.equals("Tom");

Schema定义

Pulsar模式定义在名为SchemaInfo的数据结构中。它是在每个主题的基础上存储和执行的,不能存储在名称空间或租户级别

这是SchemaInfo的一个字符串示例:

{
    "name": "test-string-schema",
    "type": "STRING",
    "schema": "",
    "properties": {}
}
  1. name: schema名称
  2. type:schema类型,它决定如何序列化和反序列化模式数据
  3. schema:模式数据,这是一个8位无符号字节序列和特定的模式类型
  4. properties:用户定义的属性是String/String的键值对,应用程序可以使用它来承载任何特定于应用程序的逻辑

Schema类型

Pulsar支持多种模式类型,主要分为两类:

  • Primitive type(基本类型)
  • Complex type(复合类型)

基本类型

概述了Pulsar模式支持的基本类型,以及模式类型和特定于语言的基本类型之间的转换
类型描述对应java类型
BOOLEAN二进制值boolean
INT88 位有符号整数int
INT1616 位有符号整数int
INT3232 位有符号整数int
INT6464 位有符号整数int
FLOAT一个单精度(32位)IEEE 754浮点数float
DOUBLE一个双精度(64位)IEEE 754浮点数double
BYTES8位无符号字节序列byte[], ByteBuffer, ByteBuf
STRINGUnicode字符序列string
TIMESTAMP (DATE, TIME)逻辑类型表示具有毫秒精度的特定时刻。它将自1970年1月1日00:00:00 GMT以来的毫秒数存储为INT64值java.sql.Timestamp (java.sql.Time, java.util.Date)
INSTANT时间轴上的一个瞬间点,精确到纳秒java.time.Instant
LOCAL_DATE表示日期的不可变日期-时间对象,通常视为年-月-日java.time.LocalDate
LOCAL_TIME表示时间的不可变日期-时间对象,通常视为小时-分钟-秒。时间以纳秒精度表示java.time.LocalDateTime
LOCAL_DATE_TIME一个表示日期-时间的不可变日期-时间对象,通常被视为年-月-日-小时-分-秒java.time.LocalTime
Pulsar在SchemaInfo中不为基本类型存储任何模式数据。一些基本模式实现可以使用属性参数来存储特定于实现的可调设置。
例如,字符串模式可以使用属性存储编码字符集,以序列化和反序列化字符串

复合类型

  • KeyValue:表示复合体key/value键值对
  • Struct:结构体,表示结构化数据,包括AvroBaseStructSchema, ProtobufNativeSchema和NativeAvroBytesSchema

KeyValue schema

  KeyValue模式帮助应用程序定义键和值的模式。Pulsar将键模式和值模式的SchemaInfo存储在一起

Pulsar提供了以下方法来编码单个key/value键值对消息:

  • INLINE:key/value键值对在消息有效负载中一起编码
  • SEPARATED:Key存储为消息键,而值存储为消息有效负载

Struct schema

下表概述了Pulsar模式支持的结构类型:

类型描述
AvroBaseStructSchemaPulsar使用Avro规范声明AvroBaseStructSchema的模式定义,AvroBaseStructSchema支持AvroSchema、JsonSchema和ProtobufSchema
ProtobufNativeSchemaProtobufNativeSchema是基于protobuf本机描述符的
NativeAvroBytesSchemaNativeAvroBytesSchema包装了原生Avro模式类型org.apache.avro.Schema。结果是一个模式实例接受序列化的Avro有效负载,而不根据包装的Avro模式验证它.当我们从外部系统(如Kafka和Cassandra)迁移或摄取事件或消息数据时,数据通常已经以Avro格式序列化。生成数据的应用程序通常已经根据其模式验证了数据(包括兼容性检查),并将其存储在数据库或专用服务(如模式注册中心)中。每个序列化数据记录的模式通常可以通过附加到该记录的元数据进行检索.在这种情况下,Pulsar生成器在将摄入的事件发送到主题时不需要重复模式验证。它所需要做的就是将每个消息或事件及其模式传递给Pulsar

Pulsar提供了以下方法来使用结构模式

  • static:我们可以预定义结构模式,它可以是Java中的POJO, Go中的结构,或者由Avro或Protobuf工具生成的类。
  • generic:有时应用程序没有预定义的结构,我们可以使用此方法定义模式和访问数据。我们可以使用GenericSchemaBuilder定义结构模式,使用GenericRecordBuilder生成泛型结构,并将消息消费到GenericRecord中。
  • SchemaDefinition:我们可以定义schemaDefinition来生成一个结构模式

static

  1. 创建pojo对象
# If you use Lombok

@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class User {
    public String name;
    public int age;
}

# If you DON'T use Lombok you will need to add the constructor like this
# 
#   public static class User {
#    String name;
#    int age;
#    public User() { } 
#    public User(String name, int age) { this.name = name; this.age = age; } }
#}

  1. 使用结构模式创建生产者并发送消息
Producer<User> producer = client.newProducer(Schema.AVRO(User.class)).create();
producer.newMessage().value(new User("pulsar-user", 1)).send();
  1. 使用结构模式创建消费者并接收消息
Consumer<User> consumer = client.newConsumer(Schema.AVRO(User.class)).subscribe();
User user = consumer.receive().getValue();

generic

  1. 使用RecordSchemaBuilder构建模式
RecordSchemaBuilder recordSchemaBuilder = SchemaBuilder.record("schemaName");
        recordSchemaBuilder.field("intField").type(SchemaType.INT32);
        SchemaInfo schemaInfo = recordSchemaBuilder.build(SchemaType.AVRO);

        Consumer<GenericRecord> consumer = client.newConsumer(Schema.generic(schemaInfo))
        .topic(topicName)
        .subscriptionName(subscriptionName)
        .subscribe();
        Producer<GenericRecord> producer = client.newProducer(Schema.generic(schemaInfo))
        .topic(topicName)
        .create();
  1. 使用RecordBuilder构建结构记录
GenericSchemaImpl schema = GenericAvroSchema.of(schemaInfo);
// send message
GenericRecord record = schema.newRecordBuilder().set("intField", 32).build();
producer.newMessage().value(record).send();
// receive message
Message<GenericRecord> msg = consumer.receive();

Assert.assertEquals(msg.getValue().getField("intField"), 32);

自动Schema

如果没有机会提前知道Pulsar主题的模式类型,我们可以使用自动的模式进行消息的传递

自动模式包含两个类别:

  1. AUTO_PRODUCE:将数据从生产者传输到具有模式的Pulsar主题,并帮助生产者验证出站字节是否与主题的模式兼容
  2. AUTO_CONSUME:将具有模式的Pulsar主题的数据传输给使用者,并帮助该主题验证出站字节是否与使用者兼容。换句话说,主题使用从代理检索的SchemaInfo将消息反序列化为特定于语言的对象GenericRecord

Schema验证实施

  模式验证强制允许代理拒绝没有Schema的生产者和消费者

默认情况下,模式验证强制只对生产者禁用(isSchemaValidationEnforced =false),这意味着:

  • 没有模式的生产者可以向具有模式的主题生成任何消息,这可能导致向主题生成垃圾数据
  • 不支持模式的客户端允许向具有模式的主题生成消息

Schema演化

  Schema存储属性和类型的详细信息。为了满足新的业务需求,Schema会随着时间的推移进行版本控制

注意:Schema演化只适用于Avro、JSON、Protobuf和ProtobufNative Schema

Schema演变可能会影响现有消费者。设计了以下控制措施来服务于Schema演变,并确保下游消费者能够无缝地处理Schema演变:

  • Schema兼容性检查
  • Schema自动更新

Schema版本控制

  与主题一起存储的每个SchemaInfo都有一个版本。模式版本管理主题中发生的模式更改

使用SchemaInfo生成的消息被标记为Schema版本。当Pulsar客户端使用消息时,客户端可以使用Schema版本检索相应的SchemaInfo,并使用正确的模式反序列化数据。
一旦一个版本被分配给一个Schema或从一个Schema获取,该生产者产生的所有后续消息都被标记为适当的版本

假设我们正在使用Pulsar Java客户端创建一个生产者并发送消息:

PulsarClient client = PulsarClient.builder()
        .serviceUrl("pulsar://localhost:6650")
        .build();

Producer<SensorReading> producer = client.newProducer(JSONSchema.of(SensorReading.class))
        .topic("sensor-data")
        .sendTimeout(3, TimeUnit.SECONDS)
        .create();

下表概述了发生此连接尝试时的可能场景以及每个场景的结果:

  • 主题不存在Schema:(1)生产者是用给定的Schema创建的。(2)Schema被传输到代理并存储,因为没有现有的Schema(3)使用相同Schema或主题创建的任何消费者都可以消费来自传感器数据主题的消息
  • Schema已经存在。生产者使用已经存储的相同Schema进行连接:1)Schema被传输到代理(2)代理确定Schema是兼容的(3)代理试图将Schema存储在BookKeeper中,但随后确定它已经被存储,因此它被用于标记生成的消息
  • Schema已经存在。生产者使用兼容的新Schema进行连接:(1)Schema被传输到代理。代理确定Schema是兼容的,并将新Schema存储为当前版本(带有新的版本号)

Schema兼容性检查

  Schema兼容性检查的目的是确保现有的使用者可以处理引入的消息

当从生产者接收SchemaInfo时,代理识别模式类型,并为该模式类型部署模式兼容性检查器(schemaRegistryCompatibilityCheckers),通过应用配置的兼容性检查策略来检查SchemaInfo是否与主题的模式兼容

schemaRegistryCompatibilityCheckers的默认值,conf/broker.conf配置文件中:

schemaRegistryCompatibilityCheckers=org.apache.pulsar.broker.service.schema.JsonSchemaCompatibilityCheck,org.apache.pulsar.broker.service.schema.AvroSchemaCompatibilityCheck,org.apache.pulsar.broker.service.schema.ProtobufNativeSchemaCompatibilityCheck

每种模式类型都对应于模式兼容性检查器的一个实例。Avro、JSON和Protobuf模式有它们自己的兼容性检查器,而所有其他模式类型共享默认的兼容性检查器,这将禁用模式演化

Schema兼容性检查策略

假设您有一个包含三个模式(V1、V2和V3)的主题。V1是最古老的,V3是最新的。下表概述了8种模式兼容性策略及其工作原理:

兼容检查策略定义允许的更改根据哪个模式检查
ALWAYS_COMPATIBLE禁用Schema兼容性检查允许所有更改所有以前的版本
ALWAYS_INCOMPATIBLE禁用Schema演化,即拒绝任何模式更改不允许更改N/A
BACKWARD使用模式V3的消费者可以处理使用上一个模式版本V2的生产者写入的数据允许添加可选字段 允许删除字段最新版本
BACKWARD_TRANSITIVE使用模式V3的消费者可以处理使用所有以前的模式版本V2和V1的生产者写入的数据允许添加可选字段 允许删除字段所有以前的版本
FORWARD使用上一个模式版本V2的消费者可以处理使用新模式V3的生产者写入的数据,尽管他们可能无法使用新模式的全部功能允许添加字段 允许删除可选字段最新版本
FORWARD_TRANSITIVE使用所有以前的模式版本V2或V1的消费者可以处理使用新模式V3的生产者写入的数据允许添加字段 允许删除可选字段所有以前的版本
FULL模式既向后兼容,也向前兼容。使用上一个模式V2的消费者可以处理使用新模式V3的生产者写入的数据。使用新模式V3的消费者可以处理使用上一个模式V2的生产者写入的数据修改可选字段最新版本
FULL_TRANSITIVE模式V3、V2和V1之间的向后和向前兼容性。使用模式V3的消费者可以处理使用模式V2和V1的生产者写入的数据。使用模式V2或V1的消费者可以处理使用模式V3的生产者写入的数据修改可选字段所有以前的版本

Schema自动更新

  默认情况下,Schema AutoUpdate是启用的。当Schema通过Schema兼容性检查时,生产者自动将该Schema更新为它所生成的主题

生产者端(producer)

对于生产者,在以下情况下发生AutoUpdate:

  • 如果主题没有模式(意味着数据是原始字节),Pulsar会自动注册模式
  • 如果一个主题有一个模式,而生产者不携带任何模式(意味着它产生原始字节):
    • 如果在主题所属的名称空间中禁用模式验证强制(schemaValidationEnforced=false),则允许生产者连接到主题并生成数据
    • 否则,将拒绝生产者
    • 如果一个主题有一个模式,生产者也携带一个模式

消费端(Consume)

对于消费者,在以下情况下发生AutoUpdate:

  • 如果使用者连接到一个没有模式的主题(意味着它消耗原始字节),则使用者可以成功连接到主题,而无需进行任何兼容性检查
  • 如果使用者使用模式连接到主题

客户端升级顺序

  为了适应模式演变和自动更新,我们需要相应地升级客户端应用程序。根据配置的模式兼容性检查策略不同,升级顺序可能不同

模式兼容性检查策略与客户端升级顺序的对应关系如下表所示:

兼容检查策略升级顺序描述
ALWAYS_COMPATIBLE任何顺序禁用兼容性检查。因此,我们可以以任何顺序升级生产者和消费者
ALWAYS_INCOMPATIBLEN/ASchema演变已禁用
BACKWARD / BACKWARD_TRANSITIVE消费者优先不能保证使用旧模式的消费者可以读取使用新模式产生的数据。因此,首先升级所有消费者,然后开始生成新数据
FORWARD / FORWARD_TRANSITIVE生产者优先不能保证使用新模式的消费者可以读取使用旧模式产生的数据。因此,首先升级所有生产者以使用新模式,并确保已经使用旧模式生成的数据对消费者不可用,然后升级消费者
FULL / FULL_TRANSITIVE任何顺序可以保证使用旧模式的消费者可以读取使用新模式产生的数据,使用新模式的消费者可以读取使用旧模式产生的数据。因此,我们可以以任何顺序升级生产者和消费者

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

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

相关文章

DAY05_瑞吉外卖——新增套餐套餐分页查询删除套餐短信发送手机验证码登录

目录 1. 新增套餐1.1 需求分析1.2 数据模型1.3 准备工作1.4 前端页面分析1.5 代码开发1.5.1 根据分类查询菜品1.5.1.1 功能实现1.5.1.2 功能测试 1.5.2 保存套餐1.5.2.1 功能实现1.5.2.2 功能测试 2. 套餐分页查询2.1 需求分析2.2 前端页面分析2.3 代码开发2.3.1 基本信息查询2…

GMS地下水数值模拟及溶质(包含反应性溶质)运移模拟技术

地下水数值模拟软件GMS操作为主&#xff0c;在教学中强调模块化教学&#xff0c;分为前期数据收集与处理&#xff1b;三维地质结构建模&#xff1b;地下水流动模型构建&#xff1b;地下水溶质运移模型构建和反应性溶质运移构建5个模块&#xff1b;采用全流程模式将地下水数值模…

Dtop环球嘉年华全新支付渠道接入,带来更便捷全球化购物体验

随着全球互联网的快速发展和数字化时代的来临&#xff0c;Dtop环球嘉年华逐渐成为全球消费者购物的主要方式之一。作为一家跨境电商平台&#xff0c;伴随着全球用户量不断攀升&#xff0c;用户体验以及应用升级已经成为平台未来发展的重要因素。Dtop环球嘉年华致力于满足用户多…

源码规则引擎(Jvs-rules):10月新增功能介绍

JVS-rules是JAVA语言下开发的规则引擎&#xff0c;是jvs企业级数字化解决方案中的重要配置化工具&#xff0c;核心解决业务判断的配置化&#xff0c;常见的使用场景&#xff1a;金融信贷风控判断、商品优惠折扣计算、对员工考核评分等各种变化的规则判断情景。 规则引擎本次更…

【vue快速入门】很适合JAVA后端看

目录 1.概述 2.环境 3.创建项目 4.指令 4.1.数据域、方法域 4.2.绑定变量 4.3.绑定事件 ​编辑 4.4.隐藏和显示 4.5.设置属性 4.6.循环 ​编辑 5.组件 6.路由 7.网络请求 1.概述 前端最核心的操作是写业务逻辑以及操作DOM元素&#xff0c;操作DOM元素是很繁琐的…

【【萌新的SOC学习之AXI-DMA环路测试】】

萌新的SOC学习之AXI-DMA环路测试 AXI DMA环路测试 DMA(Direct Memory Access&#xff0c;直接存储器访问)是计算机科学中的一种内存访问技术。它允许某些计算机内部的硬件子系统可以独立地直接读写系统内存&#xff0c;而不需中央处理器&#xff08;CPU&#xff09;介入处理。…

NewStarCTF2023week2-include 0。0

简单审一下代码&#xff1a; 1、flag在flag.php 2、使用get请求方式给file传参 3、存在正则匹配&#xff0c;会过滤掉base和rot&#xff08;i表示不区分大小写&#xff0c;也就是我们无法使用大小写绕过&#xff09; 正则匹配详细知识请参考我之前的博客 http://t.csdnimg.…

springboot中如何在测试环境下进行web环境模拟测试

web环境模拟测试 模拟端口 SpringBootTest(webEnvironment SpringBootTest.WebEnvironment.RANDOM_PORT) public class WebTest {Testvoid testRandomPort () {} }

凉鞋的 Godot 笔记 109. 专题一 小结

109. 专题一 小结 在这一篇&#xff0c;我们来对第一个专题做一个小的总结。 到目前为止&#xff0c;大家应该能够感受到此教程的基调。 内容的难度非常简单&#xff0c;接近于零基础的程度&#xff0c;不过通过这些零基础内容所介绍的通识内容其实是笔者好多年的时间一点点…

程序员没有工作经验怎么办?能不能找到工作?

本人一般本科&#xff0c;软件专业。工作8年&#xff0c;目前任一家中型公司技术主管&#xff08;履技术总监的工作&#xff0c;但不敢以总监自居&#xff09; 没经验的同学找工作&#xff0c;面试官看的不是你已经积累了多少&#xff0c;而是看你的态度和学习能力&#xff0c…

springBoot 条件注解

springBoot 条件注解 前言常用的条件注解用例场景用例打印结果 前言 ConditionalOnXxx 如果指定条件成立则指定条件触发 常用的条件注解 ConditionalOnClass: 如果类路径存在这个类&#xff0c;则触发了个行为 ConditionalMissingClass: 如果类路径中不存这个类&#xff0c;…

2023年中国改性聚乙烯产能、产量及市场规模现状分析[图]

聚乙烯&#xff08;PE&#xff09;是五大合成树脂之一&#xff0c;其产量占世界通用树脂总产量的40%以上&#xff0c;是我国合成树脂中产能第三大、进口量最多的品种。2022年中国聚乙烯年产量共计2532万吨万吨&#xff0c;较2021年增幅8.7%。初级形状的聚乙烯进口量895.8万吨&a…

[12 种安卓数据恢复方案] 最佳免费 Android 照片恢复工具榜单

我们用 Android 手机的相机捕捉我们难忘的时刻&#xff0c;并将它们存储在画廊中。但是由于各种原因&#xff0c;照片可能会从 Android 手机中删除。一次丢失所有令人难忘的重要照片对任何人来说都是非常令人沮丧的。但是&#xff0c;可以使用适用于 Android 手机的免费照片恢复…

农场养殖农产品商城小程序搭建

鸡鸭羊牛鱼养殖用户不少&#xff0c;其规模也有大有小&#xff0c;尤其对一些生态养殖企业&#xff0c;其产品需求度更高&#xff0c;同时他们也有实际的销售需求。 由于具备较为稳定的货源&#xff0c;因此大规模多规格销售属性很足。 通过【雨科】平台搭建农场养殖商城&…

APT攻击

1.1 APT攻击简介 1.1.1APT攻击概念 网络安全&#xff0c;尤其是Internet互联网安全正在面临前所未有的挑战&#xff0c;这主要就来自于有组织、有特定目标、持续时间极长的新型攻击和威胁&#xff0c;国际上有的称之为APT&#xff08;Advanced Persistent Threat&#xff09;攻…

Docker学习_存储篇

当以默认的方式创建容器时&#xff0c;容器中的数据无法直接和其他容器或宿主机共享。为了解决这个问题需要学习一些Docker 存储卷的知识。 Docker提供了三种存储的方式。 bind mount共享宿主机文件目录volume共享docker存储卷tmpfs mount共享内存 volume* volume方式是容器…

【数据结构初阶】八、非线性表里的二叉树(二叉树的实现 -- C语言链式结构)

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 【数据结构初阶】七、非线性表里的二叉树&#xff08;堆的实现 -- C语言顺序结构&#xff09;-CSDN博客 回顾 二叉树的概念及结构&#xff1a; 二叉树的概念 一棵二叉树是节点的一…

sql 常用命令-----增删查改

创建表格 CREATE TABLE table_name(字段一,字段,.......);删除表格 DROP TABLE table_name; 增 INSERT INTO table_name VALUES(字段一值,字段一值,.......); 查 查找字段 SELECT 字段 FROM 表名; 查找表格所有内容 SELECT * FROM 表名; 按条件查找 SELECT * FROM…

【python海洋专题二十】subplots_adjust布局调整

上期读取soda&#xff0c;并subplot 但是存在一些不完美&#xff0c;本期修饰 本期内容 subplots_adjust布局调整 1&#xff1a;未调整布局的 2&#xff1a;调整布局 往期推荐 【python海洋专题一】查看数据nc文件的属性并输出属性到txt文件 【python海洋专题二】读取水深…

一种针对嵌入式KEIL工程的版本管理和跟踪的python脚本

这是去年写的一个python脚本&#xff0c;和KEIL V5配套使用的&#xff0c;借助git对工程文件进行版本管理和跟踪。打包后的exe和源文件整理到网盘了&#xff0c;有需要的可以自取&#xff0c;链接&#xff1a;https://pan.quark.cn/s/6c28fb43e8dc 提取码&#xff1a;R17N 关于…