Kafka-Consumer理论知识
一、上下文
之前的博客我们分析了Kafka的设计思想、Kafka的Producer端、Kafka的Server端的分析,为了完整性,我们接下来分析下Kafka的Consumer。《Kafka-代码示例》中有对应的Consumer示例代码,我们以它为入口进行分析
二、KafkaConsumer是什么?
一个从Kafka集群中消费记录的客户端,KafkaConsumer与broker交互,会随着获取的TopicPartition在集群中因故障迁移而自己调整。
KafkaConsumer允许消费者组使用consumer groups对消费进行负载平衡
三、offset
Kafka为分区中的每条记录维护一个offset,该offset充当该分区内记录的唯一标识符,也表示consumer的消费进度。例如:如果offset=5就表示offset为0-4的记录已经被消费。
consumer的position(TopicPartition)给出了下一条记录的offset,这将比消费者在该分区中看到的最高偏移量大一个。每次consumer在调用poll(Duration) 收到消息时,都会推进offset的增长。
consumer可以交由 kafka 定期自动提交offset 。也可以 调用 commitSync() 手动提交。
如果consumer进程失败并重新启动,会从维护的offset处开始继续消费。
1、自动提交offset
如下的示例依赖于自动提交offset
Properties props = new Properties();
//指定broker列表,用于连接kafka集群,1个或多个都可以,尽量多个
props.setProperty("bootstrap.servers", "localhost:9092");
//定义的组为test
props.setProperty("group.id", "test");
//配置自动提交
props.setProperty("enable.auto.commit", "true");
//自动提交频率,1000表示1秒提交1次
props.setProperty("auto.commit.interval.ms", "1000");
props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
//订阅 foo bar 两个topic的数据
consumer.subscribe(Arrays.asList("foo", "bar"));
while (true) {ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));for (ConsumerRecord<String, String> record : records)System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
}
当程序正常运行,offset会随着consumer的消费自动向前推进,如果consumer发生故障,会出现重复消费或数据丢失的情况。
如果Kafka以auto.commit.interval.ms的频率提交了offset,consumer在下一次自动提交前出现故障,当consumer再次启动后会出现重复消费的现象。
如果consumer刚刚拉回来一批数据准备处理,此刻Kafka正好自动提交offset,但是consumer出现了故障,当consumer再次启动后会出现这批数据丢失的现象。
2、手动提交offset
如下的示例依赖于手动提交offset
Properties props = new Properties();
props.setProperty("bootstrap.servers", "localhost:9092");
props.setProperty("group.id", "test");
//关闭自动提交
props.setProperty("enable.auto.commit", "false");
props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("foo", "bar"));
final int minBatchSize = 200;
List<ConsumerRecord<String, String>> buffer = new ArrayList<>();
while (true) {ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));for (ConsumerRecord<String, String> record : records) {buffer.add(record);}if (buffer.size() >= minBatchSize) {insertIntoDb(buffer);//手动提交consumer.commitSync();buffer.clear();}
}
用户可以根据自己处理数据的逻辑,控制何时提交offset。
在这个例子中,我们需要积累一定数量的数据后再批量插入数据库中。因此只有插入数据库后才需要提交offset。
这里还会发生一个小概率事件:这批数据插入数据库成功,但是再手动提交offset时,consumer发生故障。这会导致consumer重启后发生重复消费现象。因此最好把插入数据和提交offset放入到一个事务中,要么都成功,要么都失败。
上面的示例使用 commitSync() 将所有接收到的记录标记为已提交。在某些情况下,可能希望通过明确指定offset来更好地控制已提交的记录。比如下面示例:
try {while(running) {ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(Long.MAX_VALUE));for (TopicPartition partition : records.partitions()) {List<ConsumerRecord<String, String>> partitionRecords = records.records(partition);for (ConsumerRecord<String, String> record : partitionRecords) {System.out.println(record.offset() + ": " + record.value());}long lastOffset = partitionRecords.get(partitionRecords.size() - 1).offset();//提交的偏移量应始终是应用程序将读取的下一条消息的偏移量//因此这里给的是lastOffset + 1consumer.commitSync(Collections.singletonMap(partition, new OffsetAndMetadata(lastOffset + 1)));}}
} finally {consumer.close();
}
四、consumer groups
Kafka使用consumer groups的概念来允许一个进程池来划分消费和处理记录的工作。这些进程可以在同一台机器上运行,也可以分布在许多机器上,为处理提供可扩展性和容错性。
共享统一 group.id 的所有consumer 都将属于同一消费者组。组中的每个消费者都可以通过其中一个subscribe(Collection, ConsumerRebalanceListener) API动态设置要订阅的topic列表。Kafka会将订阅topic中的每条消息传递给每个消费者组中的一个进程。这是通过平衡消费者组中所有成员之间的分区来实现的,这样每个分区都被分配给组中的一个消费者。
如果一个topic有四个分区,一个消费者组有两个进程,那么每个进程会被分配两个分区来消费。
consumer group中的consumer是动态维护的,如果要给consumer出现故障,分配给它的分区将被重新分配给同一组中的其他consumer。同样,如果新的consumer加入该组,分区将从现有consumer移动到新的consumer。这被称 重新平衡 组。
当topic中的分区增多时也会触发 组的 重新平衡
当组重新分配自动发生时,可以通过ConsumerRebalanceListener通知消费者,这允许他们完成必要的应用程序级逻辑,如状态清理、手动偏移提交等。
消费者也可以使用assign()手动分配特定分区。在这种情况下,动态分区分配和消费者组协调将被禁用。
五、监测consumer故障
consumer订阅了一组topic后,当调用poll(Duration) 时,消费者将自动加入一个组。poll(Duration) 可以让Kafka认为该consumer是活动状态,consumer就会留在组中,并继续从分配给它的分区接收消息。
consumer定期向服务器发送心跳,如果consumer崩溃或在 session.timeout.ms 的持续时间内无法发送心跳,则consumer将被视为已死亡,其分区将被重新分配。
consumer也可能遇到“livelock”情况,即它继续发送心跳,但没有调用poll(Duration)
为了防止consumer在这种情况下无限期地保留其分区,Kafka使用 max.poll.interval.ms 设置提供了一种活性检测机制。如果consumer在max.poll.interval.ms内没有执行poll(Duration)消费数据,那么consumer将主动离开该组,以便另一个consumer可以接管其分区。
当这种情况发生时,可能会看到偏移提交失败(如调用commitSync() 时抛出的CommitFailedException 异常。这是一种安全机制,保证只有组中的活跃成员才能提交偏移。因此,要想留在组中,就必须持续调用 poll(Duration)
consumer提供两个配置来控制轮询循环的行为:
max.poll.interval.ms:
增加轮询之间的间隔,让consumer可以有更多的事件来处理拉取的数据,缺点:增加此值可能会延迟组重新平衡。
max.poll.records:
使用此设置可限制单次轮询调用返回的总记录数,通过调整此值,您可以减少轮询间隔,这将减少组重新平衡的影响
如果拉回的消息处理时间变化不可预测,这两种选项可能都不能完美的解决。处理这种情况的推荐方法是将消息处理转移到另一个线程或者线程池。此consumer只负责拉取数据。如果使用这种方法,需要关闭自动提交offset,当数据处理完成进行手动提交offset。
六、为consumer手动指定分区
一般情况下,consumer只要订阅topic或topic列表,并让Kafka根据组中的活动consumer为这些主题动态分配公平的分区份额。但某些情况下,可能需要对特定分区进行更精细的控制。
1、如果进程正在维护与该分区相关联的某种本地状态(如本地磁盘键值存储),那么它应该只获取它在磁盘上维护的分区的记录。
2、如果进程本身具有高可用性,并且在失败时将重新启动(可能使用YARN、Mesos或AWS设施等集群管理框架,或者作为流处理框架的一部分)。在这种情况下,Kafka不需要检测故障并重新分配分区,因为消费进程将在另一台机器上重新启动。
使用示例:
String topic = "foo";
TopicPartition partition0 = new TopicPartition(topic, 0);
TopicPartition partition1 = new TopicPartition(topic, 1);
consumer.assign(Arrays.asList(partition0, partition1));
手动分区分配不使用组协调,因此消费者故障不会导致分配的分区重新平衡。每个消费者独立行动,即使它与另一个消费者共享一个groupId。为了避免偏移提交冲突,通常应该确保每个消费者实例的groupId都是唯一的。
请注意:不可能将手动分区分配和订阅topic混合使用。
七、将offset维护转移到Kafka外部
Kafka自身会维护一个内部topic,用于存储offset。当然我们也可以选择将offset存储在外部存储系统,例如mysql。也可以将消费结果和offset存放在同一个存储系统,以原子方式存储结果和偏移量(用数据库事务 将 数据消费和offset提交绑定在一起)。这将使消费完全原子化,并给出“恰好一次”的语义,该语义比您使用Kafka的偏移提交功能获得的默认“至少一次”语义更强。
此时的做法是:
1、配置手动提交 enable.auto.commit=false
2、使用每个 ConsumerRecord提供的偏移量来保存您的位置
3、重新启动时,使用seek(TopicPartition, long)恢复消费者的位置
如果consumer手动指定分区,那么将offset维护到外部是简单的,因为指定的这个分区一直都是归属与你这个consumer来消费的。如果consumer消费的分区时Kafka给你自动分配的,则会因为consumer的变化等因素导致你当下的consumer被分到的分区变化。这时,需要通过对subscribe(Collection, ConsumerRebalanceListener)和subscribe(Pattern, ConsumerRebalanceListener)的调用提供一个ConsumerRebalanceListener
例如:当consumer获取分区时,consumer希望通过实现ConsumerRebalanceListener.onPartitionsRevoked(Collection)来提交这些分区的偏移量。当将分区分配给消费者时,消费者将希望查找这些新分区的偏移量,并通过实现ConsumerRebalanceListener.onPartitionsAssigned(Collection)将consumer正确初始化到该位置。
ConsumerRebalanceListener的另一个常见用途是清除应用程序为移动到其他地方的分区维护的任何缓存
八、控制consumer的消费位置
在大多数用例中,consumer只需从头到尾消费记录,定期提交其位置(自动或手动)。然而,Kafka允许consumer手动控制其位置,在分区中随意向前或向后移动。这意味着consumer可以重新消费旧记录,或者跳到最近的记录,而无需实际消费中间记录。
例如对于时间敏感的记录处理,如果数据已经生产了很长时间,对于一个新的consumer来说就很有意义。它可以直接处理最新的数据,或者它只关心中午12点之后的数据。
九、流量控制
如果一个consumer被分配了多个分区来获取数据,它将尝试同时从所有分区中消费,从而有效地赋予这些分区相同的消费优先级。然而,在某些情况下,consumer可能希望首先全速处理某一个分区。当这个分区没有数据时才处理其他分区。
还有一种情况,那就是流处理,一个consumer从两个topic消费数据,并对这两个流进行连接。当其中一个topic远远落后与另一个topic时,consumer会暂停从速度快的topic获取数据,以便让滞后的topic跟上。
Kafka支持消费流的动态控制,在未来的 poll(Duration)调用中,分别使用pause(Collection)和resume()来暂停指定分配分区上的消费和恢复指定暂停分区上的消费。
十、消费事务性消息
Kafka 0.11.0引入了事务,其中producer可以原子地写入多个topic和partition。为了实现这一点,从这些分区读取的consumer应该被配置为只读取已提交的数据。既:isolation.level=read_committed
在read_committed模式下,consumer将只读取已成功提交的事务消息。consumer的分区结束偏移量将是分区中属于打开事务的第一条消息的偏移量。这种偏移被称为“最后稳定偏移”(LSO)
LSO 是 Last Stable Offset 的缩写
consumer只会读取LSO并过滤掉任何已中止的事务消息。LSO还影响consumer的seekToEnd(Collection)和endOffsets(Collection)行为。
带有事务消息的分区将包括表示事务结果的提交或中止标记。这些标记不会返回给consumer,但在日志中有偏移。
因此,从具有事务性消息的topic中读取的应用程序将看到所消耗的偏移量存在缺口。这些缺失的消息将成为事务标记,并在两个隔离级别中为consumer过滤掉。此外,消费者也可能会看到由于事务中止而导致的空白,因为这些消息不会被consumer返回,但会有有效的偏移量。
十一、多线程消费
Kafka消费者不是线程安全的。我们有责任确保多线程访问正确同步。不同步访问将导致ConcurrentModificationException
此规则的唯一例外是 wakeup(),它可以从外部线程安全地用于中断活动操作。在这种情况下,将从操作的线程阻塞中抛出org.apache.kafka.common.errors.WakeupException这可用于从另一个线程关闭消费者。
如下示例:
public class KafkaConsumerRunner implements Runnable {private final AtomicBoolean closed = new AtomicBoolean(false);private final KafkaConsumer consumer;public KafkaConsumerRunner(KafkaConsumer consumer) {this.consumer = consumer;}{@literal}@Overridepublic void run() {try {consumer.subscribe(Arrays.asList("topic"));while (!closed.get()) {ConsumerRecords records = consumer.poll(Duration.ofMillis(10000));// 处理新记录 ......}} catch (WakeupException e) {// 如果关闭,忽略异常if (!closed.get()) throw e;} finally {consumer.close();}}// Shutdown hook which can be called from a separate thread// 关闭钩子,可以从单独的线程调用public void shutdown() {closed.set(true);consumer.wakeup();}
}
然后在一个单独的线程中,可以通过设置closed标志并唤醒消费者来关闭消费者。
closed.set(true);
consumer.wakeup();
我们看以下几种情况:
1、1个consumer一个线程
优点:
1、最容易实施
2、它通常是最快的,因为不需要线程间的协调
3、它使得基于每个分区的按顺序处理非常容易实现(每个线程只按接收消息的顺序处理消息)。
缺点:
1、更多的consumer意味着更多的TCP连接到集群(每个线程一个)。一般来说,Kafka非常有效地处理连接,因此这通常是一个很小的成本。
2、多个consumer意味着向服务器发送的请求更多,数据批处理略有减少,这可能会导致I/O吞吐量下降。
3、所有进程中的线程总数将受到分区总数的限制
2、将消费和处理解耦
consumer只负责接收数据,处理数据的逻辑让另一个线程池来处理
优点:
此选项允许独立扩展consumer和处理器的数量。这使得有可能有一个为多个处理器线程提供数据的单一consumer,从而避免了对分区的任何限制。
缺点:
1、保证处理器之间的顺序需要特别小心,因为线程将独立执行,由于线程执行时间的运气,较早的数据块实际上可能会在较晚的数据块之后被处理。对于没有订购要求的加工,这不是问题。
2、手动提交 offset 变得更加困难,因为它要求所有线程协调以确保该分区的处理完成。
相关文章:
Kafka-Consumer理论知识
一、上下文 之前的博客我们分析了Kafka的设计思想、Kafka的Producer端、Kafka的Server端的分析,为了完整性,我们接下来分析下Kafka的Consumer。《Kafka-代码示例》中有对应的Consumer示例代码,我们以它为入口进行分析 二、KafkaConsumer是什…...
Js-对象-04-Array
重点关注:Array String JSON BOM DOM Array Array对象时用来定义数组的。常用语法格式有如下2种: 方式1: var 变量名 new Array(元素列表); 例如: var arr new Array(1,2,3,4); //1,2,3,4 是存储在数组中的数据࿰…...
React 第八节组件生命周期钩子-类式组件,函数式组件模拟生命周期用法
概述 React组件的生命周期可以分为三个主要阶段: 挂载阶段(Mounting):组件被创建,插入到DOM 树的过程; 更新阶段(Updating):是组件中 props 以及state 发生变化时&#…...
Dubbo源码解析-服务调用(七)
一、服务调用流程 服务在订阅过程中,把notify 过来的urls 都转成了invoker,不知道大家是否还记得前面的rpc 过程,protocol也是在服务端和消费端各连接子一个invoker,如下图: 这张图主要展示rpc 主流程,消费…...
svn 崩溃、 cleanup失败 怎么办
在使用svn的过程中,可能出现整个svn崩溃, 例如cleanup 失败的情况,类似于 这时可以下载本贴资源文件并解压。 或者直接访问网站 SQLite Download Page 进行下载 解压后得到 sqlite3.exe 放到发生问题的svn根目录的.svn路径下 右键呼出pow…...
【Linux系列】NTP时间同步服务器搭建完整指南
在分布式系统和高可用环境中,时间同步是至关重要的。特别是对于银行、金融等关键业务系统,精准的时间同步不仅关系到系统的稳定性,还直接影响交易处理、日志管理、日终结算等功能。本文将介绍NTP(Network Time Protocol࿰…...
go 结构体方法
在 Go 语言中,结构体方法是指附加到结构体类型上的函数。这些方法可以通过结构体的实例来调用。方法的接收者(receiver)指定了该方法属于哪个结构体类型。接收者可以是一个值类型或指针类型。 定义结构体方法 下面是如何为一个结构体定义方…...
DHCP服务(包含配置过程)
目录 一、 DHCP的定义 二、 使用DHCP的好处 三、 DHCP的分配方式 四、 DHCP的租约过程 1. 客户机请求IP 2. 服务器响应 3. 客户机选择IP 4. 服务器确定租约 5. 重新登录 6. 更新租约 五、 DHCP服务配置过程 一、 DHCP的定义 DHCP(Dynamic Host Configur…...
uniapp内嵌的webview H5与应用通信
H5端: 1、找到index.html引入依赖 <script type"text/javascript" src"https://unpkg.com/dcloudio/uni-webview-js0.0.3/index.js"></script> 2、在需要通讯处发送消息 uni.postMessage({data:{code:200,msg:"处理完成&q…...
Android OpenGL ES详解——绘制圆角矩形
1、绘制矩形 代码如下: renderer类: package com.example.roundrectimport android.content.Context import android.opengl.GLES30 import android.opengl.GLSurfaceView.Renderer import com.opengllib.data.VertexArray import com.opengllib.prog…...
网络基础二
文章目录 协议定制,序列化和反序列化应用层网络版计算器协议的定制序列反序列化序列化未复用版 反序列化 TCP是面向字节流的,你怎么保证,你读取上来的数据,是‘’一个“ “完整””的报文呢? 我们没有区分字符串里面有…...
从Full-Text Search全文检索到RAG检索增强
从Full-Text Search全文检索到RAG检索增强 时光飞逝,转眼间六年过去了,六年前铁蛋优化单表千万级数据查询性能的场景依然历历在目,铁蛋也从最开始做CRUD转行去了大数据平台开发,混迹包装开源的业务,机缘巧合下做了实时…...
springMVC 全局异常统一处理
全局异常处理⽅式⼀: 1、配置简单异常处理器 配置 SimpleMappingExceptionResolver 对象: <!-- 配置全局异常统⼀处理的 Bean (简单异常处理器) --> <bean class"org.springframework.web.servlet.handler.SimpleMappingExceptionReso…...
qt ubuntu i386 系统
sudo ln -s cmake-3.31.0-linux-x86_64/bin/* /usr/local/bin 【Ubuntu20.4安装QT6 - CSDN App】Ubuntu20.4安装QT6_ubuntu安装qt6-CSDN博客 sudo ../configure -release -platform linux-g-64 -static -nomake examples -nomake demos -no-qt3support -no-script -no-scriptt…...
BUUCTF—Reverse—helloword(6)
一道安卓逆向的签到题 下载附件 使用JADX-gui反编译工具打开(注意配环境),找到主函数 jadx 本身就是一个开源项目,源代码已经在 Github 上开源了 官方地址:GitHub - skylot/jadx: Dex to Java decompiler 发现flag …...
深入解析下oracle date底层存储方式
之前我们介绍了varchar2和char的数据库底层存储格式,今天我们介绍下date类型的数据存储格式,并通过测试程序快速获取一个日期。 一、环境搭建 1.1,创建表 我们还是创建一个测试表t_code,并插入数据: 1.2,…...
Elasticsearch 开放推理 API 增加了对 IBM watsonx.ai Slate 嵌入模型的支持
作者:来自 Elastic Saikat Sarkar 使用 Elasticsearch 向量数据库构建搜索 AI 体验时如何使用 IBM watsonx™ Slate 文本嵌入。 Elastic 很高兴地宣布,通过集成 IBM watsonx™ Slate 嵌入模型,我们的开放推理 API 功能得以扩展,这…...
如何搭建一个小程序:从零开始的详细指南
在当今数字化时代,小程序以其轻便、无需下载安装即可使用的特点,成为了连接用户与服务的重要桥梁。无论是零售、餐饮、教育还是娱乐行业,小程序都展现了巨大的潜力。如果你正考虑搭建一个小程序,本文将为你提供一个从零开始的详细…...
NFS搭建
NFS搭建 单节点安装配置服务器安装配置启动并使NFS服务开机自启客户端挂载查看是否能发现服务器的共享文件夹创建挂载目录临时挂载自动挂载 双节点安装配置服务器安装配置服务端配置NFS服务端配置Keepalived编辑nfs_check.sh监控脚本安装部署RsyncInofity 客户端 单节点安装配置…...
RNN与LSTM,通过Tensorflow在手写体识别上实战
简介:本文从RNN与LSTM的原理讲起,在手写体识别上进行代码实战。同时列举了优化思路与优化结果,都是基于Tensorflow1.14.0的环境下,希望能给您的神经网络学习带来一定的帮助。如果您觉得我讲的还行,希望可以得到您的点赞…...
Docker部署FastAPI实战
在现代 Web 开发领域,FastAPI 作为一款高性能的 Python 框架,正逐渐崭露头角,它凭借简洁的语法、快速的执行速度以及出色的类型提示功能,深受开发者的喜爱。而 Docker 容器化技术则为 FastAPI 应用的部署提供了便捷、高效且可移植…...
【Python数据分析五十个小案例】电影评分分析:使用Pandas分析电影评分数据,探索评分的分布、热门电影、用户偏好
博客主页:小馒头学python 本文专栏: Python数据分析五十个小案例 专栏简介:分享五十个Python数据分析小案例 在现代电影行业中,数据分析已经成为提升用户体验和电影推荐的关键工具。通过分析电影评分数据,我们可以揭示出用户的…...
Vue2学习记录
前言 这篇笔记,是根据B站尚硅谷的Vue2网课学习整理的,用来学习的 如果有错误,还请大佬指正 Vue核心 Vue简介 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。 它基于标准 HTML、CSS 和 JavaScr…...
TMS FNC UI Pack 5.4.0 for Delphi 12
TMS FNC UI Pack是适用于 Delphi 和 C Builder 的多功能 UI 控件的综合集合,提供跨 VCL、FMX、LCL 和 TMS WEB Core 等平台的强大功能。这个统一的组件集包括基本工具,如网格、规划器、树视图、功能区和丰富的编辑器,确保兼容性和简化的开发。…...
Redis主从架构
Redis(Remote Dictionary Server)是一个开源的、高性能的键值对存储系统,广泛应用于缓存、消息队列、实时分析等场景。为了提高系统的可用性、可靠性和读写性能,Redis提供了主从复制(Master-Slave Replication…...
logback动态获取nacos配置
文章目录 前言一、整体思路二、使用bootstrap.yml三、增加环境变量四、pom文件五、logback-spring.xml更改总结 前言 主要是logback动态获取nacos的配置信息,结尾完整代码 项目springcloudnacosplumelog,使用的时候、特别是部署的时候,需要改环境&#…...
KETTLE安装部署V2.0
一、前置准备工作 JDK:下载JDK (1.8),安装并配置 JAVA_HOME 环境变量,并将其下的 bin 目录追加到 PATH 环境变量中。如果你的环境中已存在,可以跳过这步。KETTLE(8.2)压缩包:LHR提供关闭防火墙…...
[RabbitMQ] 保证消息可靠性的三大机制------消息确认,持久化,发送方确认
🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏: 🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 🍕 Collection与…...
aws服务--机密数据存储AWS Secrets Manager(1)介绍和使用
一、介绍 1、简介 AWS Secrets Manager 是一个完全托管的服务,用于保护应用程序、服务和 IT 资源中的机密信息。它支持安全地存储、管理和访问应用程序所需的机密数据,比如数据库凭证、API 密钥、访问密钥等。通过 Secrets Manager,你可以轻松管理、轮换和访问这些机密信息…...
Java设计模式笔记(一)
Java设计模式笔记(一) (23种设计模式由于篇幅较大分为两篇展示) 一、设计模式介绍 1、设计模式的目的 让程序具有更好的: 代码重用性可读性可扩展性可靠性高内聚,低耦合 2、设计模式的七大原则 单一职…...
微商的自己做网站叫什么名字/网站要怎么创建
如果要获取行,则需要从每个数组中获取值,然后根据值创建新数组。您可以手动分配值,也可以使用for循环,例如...int[][] MyMat {{0,1,2,3,4}, {9,8,7,6,5}};// get your columns... (easy)int[] My0 MyMat[0]; //My0 {0,1,2,3,4}i…...
珠海网站建设方案开发/汽车宣传软文
参考链接: pytorch创建data.DataLoader时,参数pin_memory的理解 参考链接: What is the disadvantage of using pin_memory? 参考链接: 【pytorch】torch.utils.data.DataLoader中的pin_memory属性 pin_memory就是锁页内存,创建DataLoader时࿰…...
现在的官方网站怎么做的/百度网站优化软件
笔记内容整理自mooc上北京理工大学嵩天老师python系列课程数据分析与展示,本人小白一枚,如有不对,多加指正 1.python自带的图像库PIL 1.1常用API Image.open() Image.fromarray() im.save() convert(L) b.astype(uint8)(这个API用于处理后的数…...
网站建设排行公司/seo优化平台
导读Dutree是Durep和Tree的组合。Durep用图表创建磁盘使用情况报告,这使我们能够确定哪些目录使用了最多的空间。尽管durep可以产生类似于du的文本输出,但其真正的功能是能够将报告存储在文件中。Tree是目录显示程序,它以树状结构在终端上递归…...
网站建设难做吗/百度推广的渠道有哪些
一.概念 列表视图;用来显示多个可滑动项列表的ViewGroup;需要适配器Adapter 将集合中数据和每一个Item所对应的布局动态适配到ListView中进行显示。 1 <?xml version"1.0" encoding"utf-8"?>2 <LinearLayout xmlns:andro…...
北京公司网站制作/株洲企业seo优化
https://www.microsoft.com/zh-cn/software-download/windows10 https://blog.csdn.net/mildddd/article/details/79608196转载于:https://www.cnblogs.com/John-2011/p/10287021.html...