zookeeper+kafka消息队列集群部署
一.消息队列
1、什么是消息队列
消息(Message)是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。
消息队列(MessageQueue)是一种在软件系统中用于传递消息和实现异步通信的技术。它通常被用来解耦不同组件或服务之间的通信,从而提高系统的可靠性、扩展性和灵活性。消息发布者只管把消息发布到MQ中而不用管谁来取,消息使用者只管从MQ中取消息而不管是谁发布的。这样发布者和使用者都不用知道对方的存在。
2、特征
(1)存储:消息队列作为缓冲层,可以处理生产者和消费者的速度差异,防止消息丢失或处理能力不足的问题。
(2)异步:消息队列实现了生产者和消费者的异步通信,生产者不需要等待消费者处理完消息就可以继续工作。
(3)解藕:消息队列能够解耦生产者和消费者,使它们不需要直接知道彼此的存在,从而降低系统组件之间的耦合度。
3、为什么使用消息队列
(1)解耦
允许你独立的扩展或修改两边的处理过程,只要确保它们遵守相同的接口约束。
(2)冗余
消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。
(3)扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队的处理的频率是很容易的,只要另外增加处理过程即可
(4)实现削峰填谷
在系统的流量剧增时,消息队列能够缓冲请求,平滑处理峰值流量,避免直接将大量请求发送给后端服务导致服务不可用或性能下降。
(5)可恢复性
系统的一部分组件失效后,不会影响整个系统,消息队列降低了进程间的耦合度,所以即时一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理
(6)顺序保证
消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。(kafka保证一个partition内的消息的有序性)
(7)缓冲
有助于控制和优化数据流经过系统的速度,解决生产消息和处理消息速度不一致的问题。
(8)异步通信
提供了异步处理机制,允许用户把一个消息放入队列,但不立即处理它,在需要的时候处理。
二.kafka
1.概念
Kafka 是一个高性能、分布式的消息队列系统,最初由LinkedIn开发并开源。它具有以下几个显著的特点和优势:
-
高吞吐量:Kafka 能够处理非常高的消息吞吐量。它的设计目标是每秒处理数百万条消息。
-
分布式:Kafka 是一个分布式系统,消息被分布存储在多个节点上,支持水平扩展。这使得它能够处理大规模数据和流量。
-
持久性:Kafka 将消息持久化到磁盘,保证了消息在发送和消费过程中的持久性和可靠性。即使消费者离线一段时间,也能确保不丢失消息。
-
多订阅者支持:Kafka 的消息可以被多个消费者组消费,每个消费者组可以独立消费消息,支持发布-订阅和队列模式。
-
可扩展性:Kafka 可以通过增加节点来水平扩展集群,以支持更大的负载和更高的吞吐量。
-
低延迟:Kafka 的设计追求低延迟,适用于需要快速数据传输和处理的场景。
-
消息保留:Kafka 允许消息在一定时间内保留在系统中,消费者可以根据需要重放过去的消息。
-
社区活跃:作为开源项目,Kafka 拥有一个活跃的社区,提供了丰富的文档、示例和支持。
2.kafka角色术语
(1)broker:kafka集群包含一个或多个服务器,每个服务器被称为broker(经纪人)。
(2)Topic:每条发布到kafka集群的消息都有一个分类,这个分类被称为Topic(主题)。
(3)Producer:消息的生产者,负责发布消息到kafka broker。
(4)Consumer:指消息的消费者,从kafka broker拉取数据,并消费这些已发布的消息
(5)partition:partition是物理上的概念,每个Topic包含一个或多个Partition,每个Partition都是一个有序队列,Partition中的每条消息都会被分配一个有序的id(offset)
(6)Consumer Group:消费者组,默认属于group组。
(7)Message:消息,通信的基本单位,每个producer可以向一个topic发布一些信息
三.zookeeper
1、概述
zookeeper是一种分布式协调技术,所谓分布式协调技术主要是用来解决分布式环境当中多个进程之间的同步控制,让它们有序的去访问某个共享资源,防止造成资源竞争(脑裂)的后果。
2、zookeeper工作原理
(1)master启动
在分布式系统中引入Zookeeper以后,就可以配置多个主节点,这里以配置两个主节点为例,假定它们是主节点A和主节点B,当两个主节点都启动后,它们都会向Zookeeper中注册节点信息。我们假设主节点A锁注册的节点信息是master001,主节点B注册的节点信息是master002,注册完以后会进行选举,选举有多种算法,这里以编号最小作为选举算法为例,编号最小的节点将在选举中获胜并获得锁成为主节点,也就是主节点A将会获得锁成为主节点,然后主节点B将被阻塞成为一个备用节点。这样,通过这种方式Zookeeper就完成了对两个Master进程的调度。完成了主、备节点的分配和协作
(2)master故障
如果主节点A发生了故障,这时候它在Zookeeper所注册的节点信息会被自动删除,而Zookeeper会自动感知节点的变化,发现主节点A故障后,会再次发出选举,这时候主节点B将在选举中获胜,替代主节点A成为新的主节点,这样就完成了主、被节点的重新选举
(3)master恢复
如果主节点恢复了,它会再次向zookeeper注册自身的节点信息,只不过这时候它注册的节点信息将会变成master003,而不是原来的信息。zookeeper会感知节点的变化再次发动选举,这时候主节点B在选举过程中再次获胜继续担任主节点,节点A担任备份节点。
3.zookeeper集群架构

Leader:领导者角色,主要负责投票的发起和决议,以及更新系统状态。
follower:跟随着角色,用于接收客户端的请求并返回结果给客户端,在选举过程中参与投票。
observer:观察者角色,用户接收客户端的请求,并将写请求转发给leader,同时同步leader状态,但是不参与投票。bserver日的是扩展系统,提高伸缩性。
client:客户端角色,用于向zookeeper发起请求 。
4.zookeeper工作流程
Zookeeper修改数据的流程:Zookeeper集群中每个Server在内存中存储了一份数据,在Zookeeper启动时,将从实例中选举一个Server作为1eader,Leader负责处理数据更新等操作,当且仅当大多数Server在内存中成功修改数据,才认为数据修改成功。
Zookeeper写的流程为:客户端Client首先和一个Server或者bserve通信,发起写请求,然后Server将写请求转发给Leader,Leader再将写请求转发给其它Server,其它Server在接收到写请求后写入数据并响应Leader,Leader在接收到大多数写成功回应后,认为数据写成功,最后响应client,完成一次写操作过程。
四、zookeeper在kafka中的作用
1.Broker注册
Broker是分布式部署并且相互之间相互独立,但是需要有一个注册系统能够将整个集群中的Broker管理起来,此时就使用到了Zookeeper。在Zookeeper上会有一个专门用来进行Broker服务器列表记录的节点:
/brokers/ids
每个Broker在启动时,都会到Zookeeper上进行注册,即到/brokers/ids下创建属于自己的节点,如/brokers/ids/[0……N]
Kafka使用了全局唯一的数字来指代每个Broker服务器,不同的Broker必须使用不同的BrokerID进行注册,创建完节点后,每个Broker就会将自己的IP地址和端口信息记录到该节点中去。其中,Broker创建的节点类型是临时节点,一旦Broker岩机,则对应的临时节点也会被自动删除。
2.Topic注册
在Kafka中,同一个Topic的消息会被分成多个分区并将其分布在多个Broker上,这些分区信息及与Broker的对应关系也都是由Zookeeper在维护,由专门的节点来记录。
3.生产者负载均衡
由于同一个Topic消息会被分区并将其分布在多个Broker上,因此,生产者需要将消息合理地发送到这些分布式的Broker上,那么如何实现生产者的负载均衡,Kafka支持传统的四层负载均衡,也支持Zookeeper方式实现负载均衡
(1)四层负载均衡
根据生产者的IP地址和端口来为其确定一个相关联的Broker。通常,一个生产者只会对应单个Broker,然后该生产者产生的消息都发往该Broker。这种方式逻辑简单,每个生产者不需要同其他系统建立额外的TCP连接,只需要和Broker维护单个TCP连接即可。但是,其无法做到真正的负载均衡,因为实际系统中的每个生产者产生的消息量及每个Broker的消息存储量都是不一样的,如果有些生产者产生的消息远多于其他生产者的话,那么会导致不同的Broker接收到的消息总数差异巨大,同时,生产者也无法实时感知到Broker的新增和删除
(2)使用Zookeeper进行负载均衡
由于每个Broker启动时,都会完成Broker注册过程,生产者会通过该节点的变化来动态地感知到Broker服务器列表的变更,这样就可以实现动态的负载均衡机制
4.消费者负载均衡
与生产者类似,Kafka中的消费者同样需要进行负载均衡来实现多个消费者合理地从对应的Broker服务器上接收消息,每个消费者分组包含若干消费者,每条消息都只会发送给分组中的个消费者,不同的消费者分组消费白己特定的Topic下面的消息,互不干扰
5.记录信息分区与消费者关系
消费组(ConsumerGroup)下有多个Consumer(消费者)。对于每个消费者组(ConsumerGroup),Kafka都会为其分配一个全局唯一的GroupID,Group内部的所有消费者共享该ID。订阅的topic下的每个分区只能分配给某个group下的一个consumer(当然该分区还可以被分配给其他group)。
同时,Kafka为每个消费者分配一个ConsumerID,通常采用Hostname:UUID形式表示
在Kafka中,规定了每个消总分区只能被同组的一个消费者进行消费,因此,需要在
Zookeeper上记录消息分区与consumer之间的关系,每个消费者一旦确定了对一个消息分区的消费权力,需要将其consumer ID写入到Zookeeper对应消息分区的临时节点上,例如:
/consumers/[group_id]/owners/[topic]/[broker_id-partition_id]
其中,[broker_id-partition_id]就是一个消息分区的标识,节点内容就是该消息分区上消费者的ConsumerID。
6、消息消费进度Offset记录
在消费者对指定消分区进行消息消费的过程中,需要定时地将分区消息的消费进度Offset记录到zookeeper上,以便在该消费者进行重启或者其他消费者重新接管该消息分区的消息消费后,能够从之前的进度开始继续进行消息消费。ffset在Zookeeper中由一个专门节点进行记录,其节点路径为:/consumers/[group_id]/offsets/[topic]/[broker_id-partition_id]
节点内容就是Offset的值
7.消费者注册
消费者服务器在初始化启动时加入消费者分组的步骤如下:
(1)注册到消费者分组
每个消费者服务器启动时,都会到zookeeper的指定节点下创建一个属于自己的消费者节点,例如/consumers/[group_id]/ids/[consumer_id],完成节点创建后,消费者就会将自己订阅的Topic信息写入该临时节点。
(2)对消费者分组中的消费者的变化注册监听
每个消费者都需要关注所属消费者分组中其他消费者服务器的变化情况,即对/consumers/[group_id]/ids节点注册子节点变化的Watcher监听,一旦发现消费者新增或减少就触发消费者的负载均衡。
(3)对Broker服务器变化注册监听
消费者需要对/broker/ids/[-N]中的节点进行监听,如果发现Broker服务器列表发生变化,那么就根据具体情况来决定是否需要进行消费者负载均衡
(4)进行消费者负载均衡
为了让同一个Topic下不同分区的消息尽量均衡地被多个消费者消费而进行消费者与消
息分区分配的过程,通常,对于一个消费者分组,如果组内的消费者服务器发生变更或Broker服务器发生变更,会发出消费者负载均衡
五.集群部署kafka
1:修改主机hosts文件(所有主机都配置)
[root@kafka1 ~]# vim /etc/hosts
192.168.10.101 kafka1
192.168.10.102 kafka2
192.168.10.103 kafka3
2:zookeeper的部署
(1)安装zookeeper(三个节点的配置相同)
[root@kafka1 ~]# systemctl stop firewalld
[root@kafka1 ~]# setenforce 0
[root@kafka1 ~]# yum -y install java
[root@kafka1 ~]# tar zxvf apache-zookeeper-3.6.0-bin.tar.gz
[root@kafka1 ~]# mv apache-zookeeper-3.6.0-bin /etc/zookeeper
(2)创建数据保存目录(三个节点的配置相同)
[root@kafka1 ~]# cd /etc/zookeeper/
[root@kafka1 zookeeper]# mkdir zookeeper-data
(3)修改配置文件(三个节点的配置相同)
[root@kafka1 zookeeper]# cd /etc/zookeeper/conf
[root@kafka1 ~]# mv zoo_sample.cfg zoo.cfg
[root@kafka1 ~]# vim zoo.cfg
dataDir=/etc/zookeeper/zookeeper-data
clientPort=2181
server.1=192.168.10.101:2888:3888
server.2=192.168.10.102:2888:3888
server.3=192.168.10.103:2888:3888
注释:zookeeper只用的端口
2181:对cline端提供服务
3888:选举leader使用
2888:集群内机器通讯使用(Leader监听此端口)
(4)创建节点id文件(按server编号设置这个id,三个机器不同)
节点1:
[root@kafka1 conf]# echo '1' > /etc/zookeeper/zookeeper-data/myid
节点2:
[root@kafka2 conf]# echo '2' > /etc/zookeeper/zookeeper-data/myid
节点3:
[root@kafka3 conf]# echo '3' > /etc/zookeeper/zookeeper-data/myid
(5)三个节点启动zookeeper进程
[root@kafka1 conf]# cd /etc/zookeeper/
[root@kafka1 zookeeper]# ./bin/zkServer.sh start
[root@kafka1 zookeeper]# ./bin/zkServer.sh status
3:kafka的部署
(1)kafka的安装(三个节点的配置相同)
[root@kafka1 ~]# tar zxvf kafka_2.13-2.4.1.tgz[root@kafka1 ~]# mv kafka_2.13-2.4.1 /etc/kafka
(2)修改配置文件
[root@kafka1 ~]# cd /etc/kafka/[root@kafka2 kafka]# vim config/server.propertiesbroker.id=1##21行 修改,注意其他两个的id分别是2和3listeners=PLAINTEXT://192.168.10.101:9092#31行 修改,其他节点改成各自的IP地址log.dirs=/etc/kafka/kafka-logs## 60行 修改num.partitions=1##65行 分片数量,不能超过节点数zookeeper.connect=192.168.10.101:2181,192.168.10.102:2181,192.168.10.103:218##123行,填写集群中各节点的地址和端口
注释:
9092是kafka的监听端口
(3)创建日志目录(三个节点的配置相同)
[root@kafka1 kafka]# mkdir /etc/kafka/kafka-logs
(4)在所有kafka节点上执行开启命令,生成kafka群集(三个节点的配置相同)
[root@kafka1 kafka]# ./bin/kafka-server-start.sh config/server.properties &
如果启动不了,可以将/etc/kafka/kafka-logs中的数据清除再试试
4:测试
创建topic(任意一个节点)
bin/kafka-topics.sh --create --zookeeper kafka1:2181 --replication-factor 1 --partitions 1 --topic test
列出topic(任意一个节点)
bin/kafka-topics.sh --list --zookeeper kafka1:2181bin/kafka-topics.sh --list --zookeeper kafka2:2181bin/kafka-topics.sh --list --zookeeper kafka3:2181
生产消息
bin/kafka-console-producer.sh --broker-list kafka1:9092 -topic test
消费消息
bin/kafka-console-consumer.sh --bootstrap-server kafka1:9092 --topic test
输入完成会可以去生产者方测试输入,看消费者方有无信息
删除topic
bin/kafka-topics.sh --delete --zookeeper kafka1:2181 --topic test
相关文章:
zookeeper+kafka消息队列集群部署
一.消息队列 1、什么是消息队列 消息(Message)是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。 消息队列(MessageQueue)是一种在软件系统中用…...
LLM_入门指南(零基础搭建大模型)
本文主要介绍大模型的prompt,并且给出实战教程。即使零基础也可以实现大模型的搭建。 内容:初级阶段的修炼心法,帮助凝聚和提升内力,为后续修炼打下基础。 1、prompt 1.1含义和作用 prompt就是提示工程的意思。在大型语言模型中…...
Element Plus 与 Vue 3:构建现代化 Web 应用的完美搭档
引言 Element Plus是基于Vue 3的组件库,它继承了Element UI的优秀基因,为Vue 3应用提供了丰富的界面组件。Element Plus不仅拥有与Element UI相同的高质量组件,还针对Vue 3进行了优化和更新,确保了与Vue 3的无缝集成。 环境准备…...
线程间通信与变量修改感知:几种常用方法
线程间通信与变量修改感知:几种常用方法 1. 使用volatile关键字2. 使用synchronized关键字3. 使用wait/notify/notifyAll机制4. 使用轮询(Polling) 💖The Begin💖点点关注,收藏不迷路💖 在Java…...
前后端通信 —— HTTP/HTTPS
目录 一、HTTP/HTTPS 简介 1、HTTP 2、HTTPS 二、HTTP 工作过程 三、HTTP 消息 1、HTTP消息结构 2、HTTP消息示例 四、HTTP 方法(常用) 1、GET 2、POST 3、PUT 4、DELETE 5、GET与POST对比 五、HTTP 状态码(常用) …...
人工智能 (AI) 应用:一个高精度ASD 诊断和照护支持系统
自闭症谱系障碍(ASD)是一种多方面的神经发育状况,影响全球大约1/100的儿童,而在中国,这一比例高达1.8%(引用自《中国0~6岁儿童孤独症谱系障碍筛查患病现状》),男童为2.6%…...
C# 1.方法
方法组成: 1.修饰符:public一般定义共有的 2.方法返回值:void 无返回值; 非void,可以写成其他类型例如int,float,string,string[]等 3.方法名:Add 大驼峰命名法,每一个首字符大写。…...
【C++进阶学习】第七弹——AVL树——树形结构存储数据的经典模块
二叉搜索树:【C进阶学习】第五弹——二叉搜索树——二叉树进阶及set和map的铺垫-CSDN博客 目录 一、AVL树的概念 二、AVL树的原理与实现 AVL树的节点 AVL树的插入 AVL树的旋转 AVL树的打印 AVL树的检查 三、实现AVL树的完整代码 四、总结 前言:…...
px,em,rem之间的关系换算
px,em,rem之间的换算 px:普通大小 em:相对单位,相对于父元素的字体大小 rem:相对单位,相对于根元素(html)的字体大小 <!DOCTYPE html> <html lang"en"> <head>…...
HTTP——POST请求详情
POST请求 【传输实体文本】向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在POST请求体中。POST 请求可能会导致新的资源的建立或已有资源的修改。 场景: 1. 提交用户注册信息。 2. 提交修改的用户信息。 常见的…...
外包干了1个月,技术明显退步。。。
有一种打工人的羡慕,叫做“大厂”。 真是年少不知大厂香,错把青春插稻秧。 但是,在深圳有一群比大厂员工更庞大的群体,他们顶着大厂的“名”,做着大厂的工作,还可以享受大厂的伙食,却没有大厂…...
LeetCode加油站(贪心算法/暴力,分析其时间和空间复杂度)
题目描述 一.原本暴力算法 最初的想法是:先比较gas数组和cost数组的大小,找到可以作为起始点的站点(因为如果你起始点的油还不能到达下一个站点,就不能作为起始点)。当找到过后,再去依次顺序跑一圈,如果剩余的油为负数…...
5.1 软件工程基础知识-软件工程概述
软件工程诞生原因 软件工程基本原理(容易被考到) 软件生存周期 能力成熟度模型 - CMM 能力成熟度模型 - CMMI 真题...
HttpUtil工具
http工具 用到的依赖 <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version></dependency><dependency><groupId>org.apache.httpcomponent…...
并发编程-锁的分类
锁的分类 可重入锁&不可重入锁 可重入:当一个线程获取某个锁后,再次获取这个锁的时候是可以直接拿到的。不可重入:当一个线程获取某个锁之后,再次获取这个锁的时候拿不到,必须等自己先释放锁再获取。synchronized…...
K8S系列-Kubernetes基本概念及Pod、Deployment、Service的使用
一、Kubernetes 的基本概念和术语 一、资源对象 Kubernetes 的基本概念和术语大多是围绕资源对象 Resource Object 来说的,而资源对象在总体上可分为以下两类: 1、某种资源的对象 例如节点 Node) Pod 服务 (Service) 、存储卷 (Volume)。 2、…...
在VSCode上创建Vue项目详细教程
1.前期环境准备 搭建Vue项目使用的是Vue-cli 脚手架。前期环境需要准备Node.js环境,就像Java开发要依赖JDK环境一样。 1.1 Node.js环境配置 1)具体安装步骤操作即可: npm 安装教程_如何安装npm-CSDN博客文章浏览阅读836次。本文主要在Win…...
Go语言入门之流程控制简述
Go语言入门之流程控制简述 1.if语句 if语句和其他语言一样,只不过go语言的if不需要用括号包裹 if 语句的分支代码块的左大括号与 if 关键字在同一行上,这是 go 代码风格的统一要求 简单实例: func main() {// 猜数字a : 2if a > 0 {if a…...
接口测试框架基于模板自动生成测试用例!
引言 在接口自动化测试中,生成高质量、易维护的测试用例是一个重要挑战。基于模板自动生成测试用例,可以有效减少手工编写测试用例的工作量,提高测试的效率和准确性。 自动生成测试用例的原理 为了实现测试用例数据和测试用例代码的解耦&a…...
C++ STL stable_sort用法
一:功能 对区间内元素进行排序,保证相等元素的顺序(稳定排序) 二:用法 #include <iostream>struct Record {std::string label;int rank; };int main() {std::vector<Record> data {{"q", 1},…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
