【大数据学习 | kafka】kafka的偏移量管理

1. 偏移量的概念

消费者在消费数据的时候需要将消费的记录存储到一个位置,防止因为消费者程序宕机而引起断点消费数据丢失问题,下一次可以按照相应的位置从kafka中找寻数据,这个消费位置记录称之为偏移量offset。

kafka0.9以前版本将偏移量信息记录到zookeeper中

新版本中偏移量信息记录在__consumer_offsets中,这个topic是系统生成的,不仅仅帮助管理偏移量信息还能分配consumer给哪个coordinator管理,是一个非常重要的topic

它的记录方式和我们知道的记录方式一样 groupid + topic + partition ==> offset

其中存储到__consumer_offsets中的数据格式也是按照k-v进行存储的,其中k是groupid + topic + partition
value值为offset的偏移量信息。

[hexuan@hadoop106 ~]$ kafka-topics.sh --bootstrap-server hadoop106:9092 --list
__consumer_offsets
topic_a
topic_b
topic_c
topic_e
topic_f
topic_g

可以看到系统生成的topic

因为之前我们消费过很多数据,现在可以查看一下记录在这个topic中的偏移量信息

其中存在一个kafka-consumer-groups.sh 命令

# 查看消费者组信息
kafka-consumer-groups.sh --bootstrap-server hadoop106:9092 --list
# 查询具体信息
kafka-consumer-groups.sh --bootstrap-server hadoop106:9092 --describe --group my-group
# 查看活跃信息
kafka-consumer-groups.sh --bootstrap-server hadoop106:9092 --describe --group my-group --members

查看消费者组信息:

[hexuan@hadoop106 ~]$ kafka-consumer-groups.sh --bootstrap-server hadoop106:9092 --list
hainiu_group
hainiu_group2

当前使用组信息:

[hexuan@hadoop106 ~]$ kafka-consumer-groups.sh --bootstrap-server hadoop106:9092 --describe --group hainiu_groupGROUP           TOPIC           PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG             CONSUMER-ID                                                  HOST            CLIENT-ID
hainiu_group    topic_c         0          0               0               0               consumer-hainiu_group-1-41a9ebd6-99a3-4d83-b1d7-88a2a9295054 /192.168.154.1  consumer-hainiu_group-1
hainiu_group    topic_b         1          1438            1438            0               -                                                            -               -
hainiu_group    topic_b         0          1440            1440            0               -                                                            -               -
hainiu_group    topic_b         3          1417            1417            0               -                                                            -               -
hainiu_group    topic_b         4          1473            1473            0               -                                                            -               -
hainiu_group    topic_b         5          1440            1440            0               -                                                            -               -
hainiu_group    topic_b         2          1407            1407            0               -                                                            -               -
hainiu_group    topic_b         6          1391            1391            0               -  

当前组消费偏移量信息:

GROUP:组名 
TOPIC:topic信息           
PARTITION:分区  
CURRENT-OFFSET:当前消费偏移量  
LOG-END-OFFSET:这个分区总共存在多少数据  
LAG:还差多少没消费             
CONSUMER-ID:随机消费者id                                                  
HOST:主机名            
CLIENT-ID:客户端id

同时我们也可以查询__consumer_offset中的原生数据:

kafka-console-consumer.sh  --bootstrap-server hadoop106:9092 \
--topic __consumer_offsets --from-beginning --formatter \
kafka.coordinator.group.GroupMetadataManager\$OffsetsMessageFormatter

使用元数据格式化方式查看偏移量信息数据

key展示的是groupid,topic,partition ,  value值展示的是当前的偏移量信息

并且在这个topic中是追加形式一致往里面写入的

2. 偏移量的自动管理

那么我们已经看到了偏移量的存储但是偏移量究竟是怎么提交的呢?

首先我们没有设置任何的偏移量提交的代码,这个是默认开启的,其中存在两个参数

pro.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
//开启自动提交偏移量信息
pro.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 5000);
//默认提交间隔5s

官网的设置参数为两个true和5000。

所以我们在没有开启默认提交的时候已经自动提交了

为了演示自动提交的效果我们引入一个参数

auto.offset.reset

这个参数用于控制没有偏移量存储的时候,应该从什么位置进行消费数据

(因为偏移量自动提交默认是5秒一次,如果数据在5秒内消费完毕,则会造成偏移量并没有存储的情况)

其中参数值官网中给出三个

[latest, earliest, none]latest:从最新位置消费earliest:最早位置消费数据none:如果不指定消费的偏移量直接报错

一定要记得一点,如果有偏移量信息那么以上的设置是无效的.

官方文档显示给出的该参数的默认值为lastest,即从最新位置开始消费。

现在我们设置读取位置为最早位置,并且消费数据,看看可不可以记录偏移量,断点续传

思路:

首先修改组id为一个新的组,然后从最早位置消费数据,如果记录了偏移量,那么重新启动消费者会看到,没有任何数据,因为之前记录了消费数据的位置

整体代码如下:

package com.hainiu.kafka;import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringDeserializer;import java.time.Duration;
import java.util.*;public class Consumer1 {public static void main(String[] args) {Properties pro = new Properties();pro.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"nn1:9092");pro.put(ConsumerConfig.GROUP_ID_CONFIG,"new_group");pro.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());pro.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());pro.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);pro.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");pro.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 5000);KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(pro);List<String> topics = Arrays.asList("topic_d","topic_e");consumer.subscribe(topics);while (true){ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(1));Iterator<ConsumerRecord<String, String>> it = records.iterator();while(it.hasNext()){ConsumerRecord<String, String> record = it.next();System.out.println(record.topic()+"->"+record.partition()+"->"+ record.offset()+"->"+record.key()+"->"+record.value());}}}
}

运行完毕打印数据

这个时候我们需要在5s之内关闭应用,然后重新启动,因为提交的间隔时间是5s

再次启动

我们发现数据依旧被消费出来了,证明之前的偏移量存储没有任何效果和作用,因为间隔时间是5s

现在我们等待5s后在关闭应用

发现没有任何数据产生,因为偏移量已经提交了

3. 偏移量的手动提交

如上的案例我们发现偏移量的管理如果交给系统自己管理,我们没有办法及时的修改和管理偏移量信息,这个时候我们需要手动来提交给管理偏移量,更加及时和方便

这个时候引入两个方法

consumer.commitAsync();
consumer.commitSync();

commitAsync 异步提交方式:只提交一次,不管成功与否不会重试

commitSync 同步提交方式:同步提交方式会一直提交到成功为止

一般我们都会选择异步提交方式,他们的功能都是将拉取到的一整批数据的最大偏移量直接提交到__consumer_offsets中,但是同步方式会很浪费资源,异步方式虽然不能保证稳定性但是我们的偏移量是一直递增存储的,所以偶尔提交不成功一个两个不影响我们的使用

 pro.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);
//设定自动提交为false
consumer.commitSync();
consumer.commitAsync();
//设定提交方式为手动提交

整体代码如下:

package com.hainiu.kafka.consumer;/*** ClassName : consumer_offsets* Package : com.hainiu.kafka.consumer* Description** @Author HeXua* @Create 2024/11/5 21:30* Version 1.0*/import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringDeserializer;import java.time.Duration;
import java.util.*;public class Consumer_CommitSync {public static void main(String[] args) {Properties pro = new Properties();pro.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop106:9092");pro.put(ConsumerConfig.GROUP_ID_CONFIG,"hainiu_group2");pro.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());pro.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());pro.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);pro.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
//        pro.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, 5000);KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(pro);List<String> topics = Arrays.asList("topic_h");consumer.subscribe(topics);while (true){ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(1));Iterator<ConsumerRecord<String, String>> it = records.iterator();while(it.hasNext()){ConsumerRecord<String, String> record = it.next();System.out.println(record.topic()+"->"+record.partition()+"->"+ record.offset()+"->"+record.key()+"->"+record.value());}consumer.commitAsync();
//            consumer.commitSync();}}
}

现在先在topic中输入部分数据

然后启动消费者,当存在数据打印的时候马上关闭掉应用,在此启动会发现数据不会重新消费

topic_h->5->12->null->1
topic_h->5->13->null->2
topic_h->5->14->null->3
topic_h->5->15->null->4
topic_h->5->16->null->5
topic_h->5->17->null->6

偏移量已经提交不会重复消费数据

4. 断点消费数据

在没有偏移量的时候我们可以设定

auto.offset.reset进行数据的消费

可选参数有 latest earliest none等位置

但是如果存在偏移量以上的设定就不在好用了,我们需要根据偏移量的位置进行断点消费数据

但是有的时候我们需要指定位置消费相应的数据

这个时候我们需要使用到

consumer.seek();
//可以指定位置进行数据的检索

但是我们不能随意的指定消费者消费数据的位置,因为在启动消费者的时候,一个组中会存在多个消费者,每个人拿到的对应分区是不同的,所以我们需要知道这个消费者能够获取的分区是哪个,然后再指定相应的断点位置

这里我们就需要监控分区的方法展示出来所有订阅的分区信息

 consumer.subscribe(topics, new ConsumerRebalanceListener() {@Overridepublic void onPartitionsRevoked(Collection<TopicPartition> partitions) {}@Overridepublic void onPartitionsAssigned(Collection<TopicPartition> partitions) {}});

为了演示效果我们使用生产者在topic_d中增加多个消息

package com.hainiu.kafka.consumer;/*** ClassName : Producer2* Package : com.hainiu.kafka.consumer* Description** @Author HeXua* @Create 2024/11/5 23:01* Version 1.0*/
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;import java.util.Properties;public class Producer2 {public static void main(String[] args) {Properties pro = new Properties();pro.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop106:9092");pro.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());pro.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());KafkaProducer<String, String> producer = new KafkaProducer<String, String>(pro);for (int i = 0; i < 1000; i++) {ProducerRecord<String, String> record = new ProducerRecord<String, String>("topic_d", "" + i, "message"+i);producer.send(record);}producer.close();}
}

随机发送数据到不同的节点,使用随机key

然后使用断点消费数据

不设置任何的偏移量提交操作和断点位置

package com.hainiu.kafka.consumer;/*** ClassName : ConsumerWithUDOffset* Package : com.hainiu.kafka.consumer* Description** @Author HeXua* @Create 2024/11/5 23:03* Version 1.0*/
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringDeserializer;import java.time.Duration;
import java.util.*;public class ConsumerWithUDOffset {public static void main(String[] args) {Properties pro = new Properties();pro.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"hadoop106:9092");pro.put(ConsumerConfig.GROUP_ID_CONFIG,"new1");pro.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());pro.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());pro.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");pro.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG,6000);pro.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,false);KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(pro);List<String> topics = Arrays.asList("topic_h");// range roundRobin sticky cooperativeStickyconsumer.subscribe(topics, new ConsumerRebalanceListener() {@Overridepublic void onPartitionsRevoked(Collection<TopicPartition> collection) {}@Overridepublic void onPartitionsAssigned(Collection<TopicPartition> collection) {for (TopicPartition topicPartition : collection) {consumer.seek(topicPartition,195);}}});while (true){ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(1));Iterator<ConsumerRecord<String, String>> it = records.iterator();while(it.hasNext()){ConsumerRecord<String, String> record = it.next();System.out.println(record.topic()+"->"+record.partition()+"->"+ record.offset()+"->"+record.key()+"->"+record.value());}consumer.commitAsync();}}
}

5. 时间断点

kafka没有给大家提供直接根据时间找到断点位置的方法,我们需要根据时间找到偏移量,然后根据偏移量进行数据消费

consumer.offsetsForTimes();
//通过这个方法找到对应时间的偏移量位置
consumer.seek();
//然后在通过这个方法根据断点进行消费数据

整体代码如下

package com.hainiu.kafka;import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.serialization.StringDeserializer;import java.time.Duration;
import java.util.*;public class Consumer1 {public static void main(String[] args) {Properties pro = new Properties();pro.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"nn1:9092");pro.put(ConsumerConfig.GROUP_ID_CONFIG,"new_group221");pro.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());pro.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());pro.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,false);KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(pro);List<String> topics = Arrays.asList("topic_e");consumer.subscribe(topics, new ConsumerRebalanceListener() {@Overridepublic void onPartitionsRevoked(Collection<TopicPartition> partitions) {// no op}@Overridepublic void onPartitionsAssigned(Collection<TopicPartition> partitions) {HashMap<TopicPartition, Long> map = new HashMap<>();for (TopicPartition partition : partitions) {map.put(partition,1675076400000L);//将时间和分区绑定在一起,然后合并在一起放入到检索方法中}Map<TopicPartition, OffsetAndTimestamp> offsets = consumer.offsetsForTimes(map);//根据时间获取时间对应的偏移量位置for (Map.Entry<TopicPartition, OffsetAndTimestamp> en : offsets.entrySet()) {System.out.println(en.getKey()+"-->"+en.getValue());if(en.getValue() != null){consumer.seek(en.getKey(),en.getValue().offset());//获取每个分区的偏移量的位置,使用seek进行找寻数据}}}});while (true){ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(1));Iterator<ConsumerRecord<String, String>> it = records.iterator();while(it.hasNext()){ConsumerRecord<String, String> record = it.next();System.out.println(record.topic()+"->"+record.partition()+"->"+ record.offset()+"->"+record.key()+"->"+record.value());}
//            consumer.commitAsync();}}
}

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

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

相关文章

RabbitMQ 管理平台(控制中心)的介绍

文章目录 一、RabbitMQ 管理平台整体介绍二、Overview 总览三、Connections 连接四、Channels 通道五、Exchanges 交换机六、Queues 队列查看队列详细信息查看队列的消息内容 七、Admin 用户给用户分配虚拟主机 一、RabbitMQ 管理平台整体介绍 RabbitMQ 管理平台内有六个模块&…

推荐一款强大的图像处理软件:Adobe Photoshop2025

AdobePhotoShop赛博日落版是一款强大的图像处理软件&#xff0c;专为用户提供多种先进的图像编辑功能。该版本包含了最新的AI移除工具、AI查找干扰功能以及Neural Filters神经滤镜插件&#xff0c;旨在提升用户的创作效率和成品效果。 主要功能 - AI创意填充&#xff1a;该功能…

PC模块静电放电测试中的宕机黑屏

静电放电(ESD)是电子设备中常见且难以避免的干扰源之一,尤其是在复杂的电子系统中,它对系统的稳定性和可靠性影响极大。近期,在进行静电放电(6KV接触放电、15KV空气放电)测试时,某P C模块在多个端子(如USB、RJ45、HDMI及耳机端子)遭遇了显示黑屏、图像异常及系统宕机…

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)4.7-4.8

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第四周 特殊应用&#xff1a;人脸识别和神经风格转换&#xff08;Special applications: Face recognition &Neural style transfer&#xff09;4.7 深度卷积网络学习什么&#xff1f;&am…

适用于个人或团队的文档管理和知识库系统,NAS快速部署『BookStack』

适用于个人或团队的文档管理和知识库系统&#xff0c;NAS快速部署『BookStack』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 知识库对于很多需要和文字打交道的个人或者团队都不陌生对吧&#xff1f;对于我们个人来说&#xff0c;它可以将常用的学习资料、工作笔记、项目计划和…

并发编程的基础:深入理解内存屏障(Memory Barriers)

内存屏障是一种基础语言&#xff0c;在不同的计算机架构下有不同的实现细节。本文主要在x86_64处理器下&#xff0c;通过Linux及其内核代码来分析和使用内存屏障 对大多数应用层开发者来说&#xff0c;“内存屏障”&#xff08;memory Barrier&#xff09;是一种陌生&#xff…

Windows转Mac过渡指南

最近由于工作原因开始使用mac电脑&#xff0c;说实话刚拿到手的时候&#xff0c;window党表示真的用不惯。坚持用一下午之后&#xff0c;发现真的yyds&#xff0c;这篇文章说说mac电脑的基本入门指南。 1. 不会使用mac的触摸板&#xff0c;接上鼠标发现滚轮和windows是反的。 …

poi excel数据统计导出

##poi excel导出案例 1.ajxa导出请求没有任何反应&#xff0c;打断点看了workBook中也有数据&#xff0c;网上查阅说ajax请求导出无法接收流&#xff0c;换成location.href,果然可以了 2.控制器代码 response.setCharacterEncoding("UTF-8");response.setContentTyp…

昆仑通态触摸屏-如何完成几个窗口的切换

一、启动窗口 想要哪一个窗口是启动时第一个显示的&#xff0c;就把谁设置为启动窗口就可以。 二、公共窗口 给一个窗口命名为公共窗口 然后选择一个窗口&#xff0c;将他的公共窗口设置为我们刚才命名的那个窗口 三、页面切换 页面切换&#xff0c;是通过在公共窗口内设置按…

dns服务器配置

主服务器 1.挂载点 mount /dev/sr0 /mnt 2.防火墙关闭 systemctl stop firewalld setenforce 0 3.下载bind软件 dnf install bind -y 4.进行正向解析配置 vim /etc/named.conf options { listen-on port 53 { 192.168.92.128; }; directo…

GraphRAG本地部署使用及兼容千帆通义

文章目录 前言一、GraphRAG本地安装1.创建环境并安装2.准备demo数据3.初始化demo目录 二、GraphRAG兼容千帆通义等大模型1.安装 graphrag-more2.准备Demo数据3.初始化demo目录4.移动和修改 settings.yaml 文件 三、知识库构建与使用1.知识库构建2.执行查询 前言 GraphRAG是一种…

揭秘2024年最火的5个科技趋势,你准备好迎接了吗?

在这个信息化飞速发展的时代&#xff0c;科技正以前所未有的速度改变着我们的生活。2024年&#xff0c;科技行业将迎来哪些新的突破与趋势&#xff1f;从人工智能到量子计算&#xff0c;从数字货币到智能家居&#xff0c;未来已来&#xff0c;而我们正站在一个巨变的风口浪尖上…

Python实例:爱心代码

前言 在编程的奇妙世界里,代码不仅仅是冰冷的指令集合,它还可以成为表达情感、传递温暖的独特方式。今天,我们将一同探索用 Python 语言绘制爱心的神奇之旅。 爱心,这个象征着爱与温暖的符号,一直以来都在人类的情感世界中占据着特殊的地位。而通过 Python 的强大功能,…

scala学习记录,Set,Map

set&#xff1a;集合&#xff0c;表示没有重复元素的集合&#xff0c;特点&#xff1a;唯一 语法格式&#xff1a;val 变量名 Set [类型]&#xff08;元素1&#xff0c;元素2...&#xff09; 可变不可变 可变&#xff08;mutable&#xff09;可对元素进行添加&#xff0c;删…

基于SpringBoot的免税商品优选购物商城的设计与实现

一、项目背景 从古至今&#xff0c;通过书本获取知识信息的方式完全被互联网络信息化&#xff0c;但是免税商品优选购物商城&#xff0c;对于购物商城工作来说&#xff0c;仍然是一项非常重要的工作。尤其是免税商品优选购物商城&#xff0c;传统人工记录模式已不符合当前社会…

从零开始的c++之旅——多态

1. 多态的概念 通俗来说就是多种形态。 多态分为编译时多态&#xff08;静态多态&#xff09;和运行时多态&#xff08;动态多态&#xff09;。 编译时多态主要就是我们之前提过的函数重载和函数模板&#xff0c;同名提高传不同的参数就可以调 用不同的函数&#xff0c…

火山引擎VeDI数据服务平台:在电商场景中,如何解决API编排问题?

01 平台介绍 数据服务平台可以在保证服务高可靠性和高安全性的同时&#xff0c;为各业务线搭建数据服务统一出口&#xff0c;促进数据共享&#xff0c;为数据和应用之间建立了一座“沟通桥梁”。 同时&#xff0c;解决数据理解困难、异构、重复建设、审计运维困难等问题&#x…

Object 内部类 异常

Objbect类 java提供了Object,它是所有类的父类,每个类都直接或间接的继承了Object类,因此Object类通常被称为超类 当定义一个类时,如果没有使用extends关键字直接去指定父类继承,只要没有被继承的类,都是会默认的去继承Object类,超类中定义了一些方法 方法名称方法说明boole…

Linux 高级IO

学习任务&#xff1a; 高级 I/O&#xff1a;select、poll、epoll、mmap、munmap 要求&#xff1a; 学习高级 I/O 的用法&#xff0c;并实操 1、高级 I/O&#xff1a; 前置知识&#xff1a; 阻塞、I/O 多路复用 PS: 非阻塞 I/O ------ 非阻塞 I/O 阻塞其实就是进入了休眠状态&am…

JAVA WEB — HTML CSS 入门学习

本文为JAVAWEB 关于HTML 的基础学习 一 概述 HTML 超文本标记语言 超文本 超越文本的限制 比普通文本更强大 除了文字信息 还可以存储图片 音频 视频等标记语言 由标签构成的语言HTML标签都是预定义的 HTML直接在浏览器中运行 在浏览器解析 CSS 是一种用来表现HTML或XML等文…