Apache Pulsar 云原生消息中间件之王
一、简介
pulsar,消息中间件,是一个用于服务器到服务器的消息系统,具有多租户、高性能等优势。
pulsar采用发布-订阅的设计模式,producer发布消息到topic,consumer订阅这些topic处理流入的消息,并当处理完成之后发送一个确认。
一旦创建订阅,即使consumer断开连接,pulsar仍然可以保存所有消息,在consumer确认消息已处理成功之后才会删除消息。
Pulsar 的关键特性如下:
-
Pulsar 的单个实例原生支持多个集群,可跨机房在集群间无缝地完成消息复制。
-
极低的发布延迟和端到端延迟。
-
可无缝扩展到超过一百万个 topic。
-
简单的客户端 API,支持 Java、Go、Python 和 C++。
-
Topic 支持多种订阅模式(独占订阅、共享订阅、故障转移订阅)。
-
通过 Apache BookKeeper 提供的持久化消息存储机制保证消息传递 。
-
由轻量级的 serverless 计算框架 Pulsar Functions 实现流原生的数据处理。
-
基于 Pulsar Functions 的 serverless connector 框架 Pulsar IO 使得数据更易移入、移出 Apache Pulsar。
-
分层式存储可在数据陈旧时,将数据从热存储卸载到冷/长期存储(如S3、GCS)中。
二、安装部署
pulsar支持在多种环境下以多种安装模式进行安装。
环境:裸金属、Docker、kubernetes、AWS、DC/OS
模式:单机模式、单集群、多集群
1,本地单机安装
2,本地单集群安装
三、目录结构
Pulsar 二进制包目录:
目录 | 内容 |
---|---|
bin | Pulsar的命令行工具,比如 pulsar 和 pulsar-admin. |
conf | Pulsar 的配置文件,包含 broker 配置、ZooKeeper 配置等。 |
examples | Java JAR 包,包含 Pulsar Functions 的示例。 |
lib | Pulsar使用到的 JAR 文件 |
licenses | 开源许可文件,.txt 格式,用于规范 Pulsar 代码库的各个组件。 |
运行 Pulsar 会立即生成的目录:
目录 | 内容 |
---|---|
data | ZooKeeper和BookKeeper使用的数据存储目录 |
instances | 为 Pulsar Functions 创建的组件。 |
logs | 安装时生成的日志文件 |
四、重要概念
1、消息
消息是pulsar的基础单元。从生产者、到消费者、在pulsar中被传递保存的东西。由以下成分组成:
成分 | 描述 |
---|---|
Value / data payload | 消息携带的数据。 |
Key | 消息可选择用key标记,有利于topic压缩等。 |
Properties | 用户定义属性的可选键/值映射。 |
Producer name | 产生消息的生产者的名称。如果不指定生产者名称,则使用默认名称。 |
Topic name | 消息发布到的topic的名称。 |
Schema version | 用于生成消息的模式的版本号。 |
Sequence ID | 每条消息都属于其topic的有序序列。消息的序列ID由生产者分配,表示其在该序列ID中的顺序,也可自定义。 可用于重复消息删除等。 |
Message ID | 消息ID表示消息在ledger中指定位置,在pulsar是唯一的。在持久层存储时由bookies分配。 |
Publish time | 发布消息的时间戳。由生产者自动应用。 |
Event time | 应用程序附加到消息的可选时间戳。例如,当消息被处理时应用程序为其附加一个时间戳。如果没有事件事件,则为0. |
消息默认大小时5M。可在broker.conf和bookeeper.conf配置文件中配置:
2、生产者
producer是一个进程,它依附于一个topic把消息发布给brokers。pulsar borker处理消息。
(1)发送模式
生产者可以以同步(sync)或异步(async)的方式向brokers发送消息。
模式 | 描述 |
---|---|
Sync send | producer发布每条消息后都等待broker的确认。如果没有收到确认,生产者将认为发送失败。 |
Async send | producer将消息放入阻塞队列并立即返回,客户端在后端将消息发送到broker。如果队列已满,则在调用API时,producer将阻塞或立即失败(根据producer的配置参数决定)。 |
(2)访问模式
producer访问topic时,有不同类型的访问模式。
访问模式 | 描述 |
---|---|
Shared | 多着producer能向一个topic发布消息。(默认的模式) |
Exclusive | 只有一个producer能向一个topic发布消息
|
WaitForExclusive | 如果一个topic已经连接了一个生产者,那么其他生产者的创建将被挂起,而不是超时。 |
一旦应用程序成功地创建了具有Exclusive或WaitForExclusive访问模式的生产者,该应用程序的实例就保证是该主题的唯一写入者。任何试图生成关于此主题的消息的其他生产者要么立即得到错误,要么必须等到获得独占访问权。
(3)压缩
可以压缩在传输过程中的消息。支持这几种压缩方式:
- LZ4
- ZLIB
- ZSTD
- SNAPPY
(4)分批
启用batching时,producer将在单个请求中累积并发送一批消息。批处理大小由消息的最大数量和最大发布延迟定义。因此,backlog大小表示批的总数,而不是消息的总数。
此时,批是跟踪和存储的基本单元而不是单个消息了。
消费者将一批消息解压为单个消息。
对于scheduled messages,是否启用批处理,始终作为单个消息发送。
当消费者确认批处理的所有消息时,批处理被确认。这意味着,当不是所有批消息都得到确认时,某个消息的失败、否定确认或者确认超时都可能导致重新交付这批中的所有消息。
pulsar从2.6.0开始引入了批索引确认,来避免将已确认的消息以批方式重新传递给consumer。当开启批索引确认,consumer过滤已确认的批索引,并将确认请求发送给broker(broker维护并跟踪批索引的确认状态,从而避免将确认的消息发送给consumer,当批中的所有索引都被确认时,该批将被删除)。
默认情况下,批处理索引确认时禁用的,可在broker中设置acknowledgmentAtBatchIndexLevelEnabled
。
启用批处理索引确认会导致更多的内存开销。
(5)分块
Message chunking使Pulsar能够通过在producer端将消息分割成块并在consumer端聚合分块消息来处理大型有效负载消息。
启用消息分块后,当消息的大小超过允许的最大有效负载大小(代理的maxMessageSize参数)时,消息传递的工作流程如下:
- producer将原始消息拆分为分块消息,并将它们与分块元数据一起按顺序单独的发布给broker。
- broker以与普通消息相同的方式将分块消息存储在一个managed-ledger中,并使用chunkedMessageRate参数记录topic上的分块消息速率。
- 消费者在接收到消息时,对分块的消息进行缓冲,并接收到时所有块将它们聚合到接收队列中。
- 客户端消费来自接收队列的聚合消息。
限制:
- 分块只适用于persisted topic;
- 分块只对 exclusive 和 failover 订阅类型可用;
- 分块不能与批处理同时使用(启动分块前应禁用批处理)。
consumer为每个大型消息保留一个单独的缓冲区,以便将其所有块聚合到一条消息中。
可以通过配置maxPendingChunkedMessage参数来限制消费者同时维护的分块消息的最大数量。
当达到阈值时,使用者通过静默确认或请求代理稍后重新交付来丢弃挂起的消息,从而优化内存利用率。
如果使用者在指定的时间内未能收到消息的所有块,则消息块将不完整地过期。缺省值为1分钟(由expireTimeOfIncompleteChunkedMessage
配置)。
3、消费者
consumer是一个进程,它通过订阅附加到主题,然后接收消息。
consumer向broker发送 flow permit request去获取消息。在consumer端有一个队列(通过receiverQueueSize参数配置,默认是1000)用于接收从broker推送的消息。每次调用consumer.receive()时,都会从缓冲区中取出一条消息。
(1)接收模式
消息以同步(sync)或异步(async)的方式从broker接收。
Mode | Description |
---|---|
Sync receive | 同步接收被阻塞,直到有消息为止。 |
Async receive | 异步接收立即返回一个future值—比如,在java中为CompletableFuture—一旦有新消息可用,这个过程就完成了。 |
(2)监听
客户端库为consumer提供侦听器实现。例如,Java客户机提供了MesssageListener接口。在此接口中,每当接收到新消息时,都会调用received方法。
(3)Acknowledgement
consumer在成功消费消息后向broker发送确认请求。
然后,这个消费的消息将被永久存储,只有在所有的订阅都确认后才会删除。
可配置 message retention policy使被consumer确认的消息继续保存。
消息可以通过以下两种方式确认:
- 逐个确认(individual acknowledged ),consumer确认每条消息并向borker发送确认请求;
//逐个确认API: consumer.acknowledge(msg);
- 累积确认(cumulative acknowledged ),consumer只确认它收到的最后一条消息。
//累积确认API: consumer.acknowledgeCumulative(msg);
注意:Cumulative acknowledgement不能用在Shared订阅类型中,因为Shared订阅类型涉及多个可以访问同一订阅的consumer。在Shared订阅类型中,消息是单独确认的。
(4)Negative acknowledgement
否定确认,允许程序向broker发送通知,指示consumer没有处理消息。
当consumer没有使用消息,并需要重新使用它时,consumer可以向broker发送否定确认(nack),触发broker将此消息重新发送给consumer。
可单独或累积的否定确认消息。
注意:
- 在Exclusive 和 Failover订阅模式中,消费者仅能否定确认它们收到的最后一条消息。
- 在 Shared 和 Key_Shared订阅模式中,消费者能逐个否定确认消息。
- 对排序订阅类型(比如 Exclusive, Failover and Key_Shared)的否定确认可能导致消息乱序。
- 如果要对消息使用否定确认,要在确认超时之前对消息进行否定确认。
- 如果启用了批处理,则将一个批处理中的所有消息重新交付给使用者。
Consumer<byte[]> consumer = pulsarClient.newConsumer().topic(topic).subscriptionName("sub-negative-ack").subscriptionInitialPosition(SubscriptionInitialPosition.Earliest).negativeAckRedeliveryDelay(2, TimeUnit.SECONDS) // the default value is 1 min.subscribe();Message<byte[]> message = consumer.receive();// call the API to send negative acknowledgement
consumer.negativeAcknowledge(message);message = consumer.receive();
consumer.acknowledge(message);
(5)Acknowledgement timeout
(6)Retry letter topic
(7)Dead letter topic
4、topic
从生产者到消费者传输信息的通道。
结构:
{persistent|non-persistent}://tenant/namespace/topic
Topic name 组成 | 描述 |
---|---|
persistent / non-persistent | topic类型。pulsar支持持久和非持久两种主题,没有指定时默认是持久的。 持久主题:所有消息都持久的保存在磁盘上 非持久主题:数据不持久的保存在磁盘上 |
tenant | 实例中的topic租户。 租户对于Pulsar的多租户至关重要,并且分布在多个集群中。 |
namespace | topic管理单元,主要是提供了一个相关主题的分组机制。大多数topic配置都是在namespace级别执行的。每个租户有一个或多个名称空间。 |
topic | topic名。topic名在pulsar实例中没有特殊含义。 |
提示:
不需要显式的提前的创建主题。
如果客户端向一个不存在的topic写入或接收消息,pulsar自动在主题名称中提供的namespace创建该主题;
如果客户端创建主题时没有指定租户和命名空间,则pulsar在默认租户和命名空间中创建主题。
5、名称空间(namespace)
命名空间是topic的管理单元,主要是提供了一个相关主题的分组机制,将不同类型的topic放到同一个命名空间管理。
不同租户可创建多个命名空间,一个命名空间中可创建多个topic。
6、订阅(subscription)
订阅是一个配置规则,决定如何将消息发送给consumer。
pulsar中有四种订阅类型:
- exclusive
- shared
- failover
- key_shared
(1)订阅类型
订阅类型是在consumer连接到订阅时确定的;
可以通过重启consumer来更改类型;
当订阅没有连接consumer时,其订阅类型是hi未定义的。
Ⅰ、Exclusive(独占类型)
在独占类型中,只允许将单个consumer附加到订阅。默认的订阅模式。
如果多个consumer使用同一个订阅订阅了一个topic,就会发生错误。
Ⅱ、Failover(灾备类型)
在灾备类型中,多个consumer可以附加到同一个订阅;
非分区主题或分区主题的每个分区都选择一个主consumer去接收消息;
当主consumer断开连接时,未确认的和后续的消息都被传递到consumer等待队列中的下一个consumer中。
对于分区topic:broker根据优先级和消费者名称字典序对消费者排序。
对于非分区topic:broker将根据它们订阅非分区topic的顺序选择消费者。
Ⅲ、Shared(共享类型,round robin)
在共享类型中,多个consumer可以附加到同一个订阅。
消息循环分发订阅的consumer,每个消息都只传递给一个consumer。
当某个consumer断开连接时,所有发送给它但没有被确认的消息将被重新发送个剩余的某个消费者 。
注意:
- 共享类型不能保证消息的顺序;
- 不能在共享类型中使用累积确认。
Ⅳ、 Key_Shared
在key_shared类型中,多个consumer可以附加到同一个订阅;
具有相同key的消息仅传递给一个消费者,无论消息被重传多少次都会只传递给同一个消费者;
当有消费者连接或者断开连接时,
注意:
- 使用key_shared订阅类型时,需要禁用批处理或使用基于key的批处理。
- broker根据消息的key分发消息,但默认批处理方式可能无法将相同key的消息打包到同一批中;
- 因为时consumer从批中获取获取单条消息,而一个批中第一个消息的key被视为批中的所有消息的key。
基于key的批处理:
确保生产者将具有相同key的消息打包到同一批中,没有key的消息被打包到同一批中(broker从这个批分发消息时以NON_KEY作为key)。
//开启基于key的批处理的示例
Producer<byte[]> producer = client.newProducer().topic("my-topic").batcherBuilder(BatcherBuilder.KEY_BASED).create();
注意:
- 使用key_shared类型,需要为消息指定key或者排序key;
- 不能在key_shared类型中用累积确认。
(2)订阅模式
创建订阅时会创建一个关联游标来记录消息最后消耗的位置,当订阅的consumer重新启动时可以继续从它消费的最后一条消息开始消费,订阅模式主要为了指定游标类型。
订阅模式 | 描述 | 备注 |
---|---|---|
Durable | 游标是持久的。保留消息并保持当前消耗位置。 如果broker重启,可从持久存储(bookkeeper)中恢复游标。 | 默认的订阅模式。 |
NonDurable | 游标是非持久的。 broker停止,游标就会丢失,无法恢复。 | Reader的订阅模式本质上是非持久的,它不阻止主题中的数据被删除。Reader订阅模式蹦年被更改。 |
注意:
- 一个订阅可以有一个或多个consumer;
- 当consumer订阅主题时,必须指定订阅名称;
- 持久订阅和非持久订阅可以使用相同的名称,它们彼此独立;
- 如果consumer指定的订阅不存在,则自动创建该订阅。
7、多主题订阅
从pulsar 1.23.0-incubating版本开始,支持pulsar消费者可同时订阅多个topic。
两种订阅方式:
- 正则表达式(所有topic必须在同一名称空间),例如:persistent://public/default/finance-.*
- topic列表
当订阅多个主题时,pulsar客户端自动调用pulsar api以发现与正则表达式/topic列表匹配的topic并订阅,如果任何主题不存在,则在主题创建后,consumer自动订阅它们。
多个topic之间没有顺序保证,当生产者向多个topic发送消息时,不能保证从这些主题读取消息的顺序相同。
8、分区topic
分区topic是由多个broker处理的一种特殊类型的topic,因此可以实现更高的吞吐量(普通topic由一个broker服务,限制了topic的最大吞吐量)。
分区topic实现:为N个内部主题(其中N是分区的数量),当向分区topic发布消息时,每条消息被路由到多个broker中的一个。
pulsar自动维护分区的分布在哪个broker。
分区主题需要通过admin API显式创建。分区的数量可以在创建主题时指定。
路由模式决定了每个消息应该发布到哪个分区,而订阅类型决定了哪些消息将发送到哪个consumer。
通常,吞吐量问题应该指导分区/路由决策,而订阅决策应该由应用程序语义指导。
(1)路由模式
路由模式决定每条消息应该发布到哪个分区(内部topic)。
模式 | 描述 |
---|---|
RoundRobinPartition | 如果消息没有指定了key,生产者将以循环方式给所有分区发布消息(批),以实现最大吞吐量。 如果消息指定了key,消费者将散列key将消息分配给特定分区。 默认模式 |
SinglePartition | 如果消息没有指定key,生产者随机选择一个分区发布消息; 如果消息指定了key,消费者将散列key将消息分配给特定分区 |
CustomPartition | 自定义实现消息路由,该实现将被调用以确定特定的消息分区。 用户可以通过使用Java client和实现MessageRouter接口来创建自定义路由模式。 |
(2)保证顺序
消息的顺序与路由模式和key相关,通常用户希望每个key分区的消息是有序的。
顺序保证方式 | 描述 | 路由模式和key |
---|---|---|
Per-key-partition | 具有相同键的所有消息将按顺序排列并放置在同一个分区中。 | 使用SinglePartition或RoundRobinPartition模式,并且消息指定key |
Per-producer | 来自同一生产者的所有消息将是有序的。 | 使用SinglePartition模式,并且不为每条消息提供Key。 |
(3)Hashing scheme
HashingScheme是一个枚举,表示在为特定消息选择要使用的分区时可用的标准哈希函数集。
有两种类型的标准哈希函数可用:JavaStringHash和Murmur3_32Hash。
producer 的默认哈希函数是JavaStringHash。
注意,当生产者可以来自不同的多语言客户端时,JavaStringHash是没有用的,在这种用例下,建议使用Murmur3_32Hash。
9、非持久topic
消息永远不会持久化到磁盘,而只存在于内存中。
在使用非持久传递时,杀死Pulsar代理或断开与topic的订阅者的连接意味着在该非持久topic上所有正在传输的消息都会丢失。
在非持久topic中,broker立即将消息传递给所有已连接的订阅,而不会持久化到BookKeeper。
如果订阅断开连接,broker无法传递正在传输的消息,订阅将无法再次收到这些消息。
非持久topic的消息传递会稍微比持久topic的快。
性能
非持久化消息传递通常比持久化消息传递更快,因为代理不会持久化消息,而是在消息被传递到连接的代理时立即将ack发送回生产者。生产者因此看到相对较低的非持久性主题的发布延迟。连接方式
生产者和消费者与以持久性topic相同的方式连接到非持久性topic,但需要以non-persistent开头。
支持三种订阅类型:
exclusive、shared、failover
10、消息重传
11、消息保留和过期
12、消息去重
13、消息延迟传递
四、架构
在最高级别上,一个pulsar实例可以由一个或多个集群组成,实例中的集群之间可以复制数据。
相关文章:
Apache Pulsar 云原生消息中间件之王
一、简介 pulsar,消息中间件,是一个用于服务器到服务器的消息系统,具有多租户、高性能等优势。 pulsar采用发布-订阅的设计模式,producer发布消息到topic,consumer订阅这些topic处理流入的消息,并当处理完…...
精选博客系列|公用事业中的VMware:在边缘重新定义价值
VMware 已经成为公用事业行业的核心。您可以在那里找到例如 VMware vSphere(包括基础 Hypervisor ESXi 和 VMware vCenter 建立的整体控制平面)的核心产品。来自软件定义的基础架构带来的诸多好处使 IT 团队将其先前基于硬件的系统转变为 VMware Cloud F…...
数字档案室测评的些许感悟
我是甲方,明明我家是档案“室”,为什么申请的是数字档案“馆”? 笔者正对着手里的一份方案苦笑,甲方爸爸是某机关单位档案室,方案最后的附件赫然写着几个大字:“申请国家级数字档案馆……“。这样的事屡见…...
Java 函数式编程实例
一、函数式编程概念 函数式编程是一种编程的范式和编程的方法论(programming paradigm),它属于结构化编程的一种,主要的思想是把运算的过程尽量通过一组嵌套的函数来实现。 函数式编程的几个特点: 函数可以作为变量、参数、返回值和数据类…...
Ant design Chart onReady函数使用外部变量问题
一、问题描述封装了一个Chart组件,它接收一个boolean类型的props,根据这个boolean的true或false执行不同的操作。经过console.log验证,onReady函数只会在组件初次渲染时取到props值,不管后面的props变化成什么都无法重新取值。二、…...
Unity使用webSocket与服务器通信(一)搭建一个简单地服务器和客户端
你想在unity WebGL里面使用TCP通信吗,那么你可以用一用webSocket。当然,桌面端也可以使用webSocket,这样Unity多平台发布的时候,业务层的通信代码可以使用一套,而不是桌面用socket,网页用http… 一、什么是…...
SpringCloud微服务实战——搭建企业级开发框架(四十九):数据字典注解的设计与实现
数据字典是系统中基本的必不可少的功能,在多种多样的系统中,数据字典表的设计都大同小异。但是使用方式确是多种多样,设计好一套易用的数据字典功能模块,可以使开发事半功倍。 常用的数据字典使用方式: 直接在SQL语句…...
mysql下,实现保存指定用户、ip、命令的查询日志
环境:mysql 8.0.14 社区版 阅读文本需要的背景知识:对数据库的基本概念(触发器、存储过程、事件),mysql下general log的配置指令 背景:因审计需要,对于数据库操作需要留痕。实际访问数据库的有…...
Vue 3.0 学习笔记之基础知识
系列文章目录 提示:阅读本章之前,请先阅读目录 文章目录系列文章目录前言Vue 3.0 创建与Vue2.0对比的变化关闭语法检查setup 组合式函数compositions响应式数据 refreactive 函数Vue3.0 响应原理ref 和 reactive 区别setup 注意点computed 计算函数watch…...
WebGIS行政区炫酷特效——流光特效教程
先来看下效果: 图片截图: 流光特效的思路是从行政区的边界中随着时间不断的取若干段线条换成另一种高亮颜色。 流光的第一步首先是发光,发光的教程在这里: GIS矢量图形多边形地块行政区发光,阴影发光特效实现_疯狂的GISer的博客-CSDN博客 学会发光以后,接下来需要做的…...
2023-3-3 刷题情况
保证文件名唯一 题目描述 给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹:在第 i 分钟,新建名为 names[i] 的文件夹。 由于两个文件 不能 共享相同的文件名,因此如果新建文件夹使用的文件名已经被占用…...
《青浦区加快发展跨境电子商务实施细则(审议稿)》
为进一步贯彻落实《中华人民共和国电子商务法》,上海市《关于促进本市跨境电子商务发展的若干意见》,切实做好青浦区跨境电子商务试点工作,探索和规范跨境电子商务管理,促进跨境电子商务健康快速发展,青浦商务委根据多…...
【React全家桶】React生命周期
React生命周期 1、初始化阶段 componentDidMount:render之前最后一次修改状态的机会 render:只能访问this.props和this.state,不允许修改状态和DOM输出 componentDidMount:成功render并渲染完成真实DOM之后触发 2、旧生命周期 👉👉👉加…...
B. Count the Number of Pairs
原题链接 纯纯水一下; 昨天晚上的比赛,由于半夜打的,精神状态不好,wa了俩发直接睡觉去了,现在白天写写发现,不难,水中水 模拟题吧,题目怎么说就这么作 Kristina has a string ss…...
离线数据仓库项目--技术选择
文章目录(一)技术选型1)数据采集工具2)数据存储3)数据计算4)数据可视化(二)整体架构设计(三)服务器资源规划(一)技术选型 1ÿ…...
GC Garbage Collectors
本质一、算法1、哪些是垃圾?引用计数法:reference countPython中使用了。个对象如果没有任何与之关联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。漏洞:循环…...
【网络】-- 网络基础
(本文是网络的宏观的概念铺垫) 目录 计算机网络背景 网络发展 认识 "协议" 网络协议初识 协议分层 OSI七层模型 TCP/IP 五层(或四层)模型 报头 以太网 碰撞 路由器 IP地址和MAC地址 IP地址与MAC地址总结 IP地址 MAC地址 计算机…...
二、Redis安装配置(云服务器、vmware本地虚拟机)
一、自己购买服务器 自己购买阿里云、青牛云、腾讯云或华为云服务器, 自带CentoOS或者Ubuntu环境,直接开干 二、Vmware本地虚拟机安装 1、VMWare虚拟机的安装,不讲解,默认懂 2、如何查看自己的linux是32位还是64位 getconf L…...
【学习Docker(七)】详细讲解Jenkins部署SpringCloud微服务项目,Docker-compose启动
Jenkins部署SpringCloud微服务项目,Docker-compose启动 座右铭:《坚持有效输出,创造价值无限》 本文介绍使用Jenkins部署SpringCloud微服务项目,Docker-compose启动。 之前写过安装Jenkins的过程,这里就不写安装细节了…...
时机将至,名创优品或将再掀起一波消费热浪
北京时间2月28日,名创优品发布2023财年中报,财报显示,2023财年第二季度营收规模有所收窄,但净利润、毛利率、门店数量均实现了不错的增长,总体表现可圈可点。 (资料来源:富途牛牛) …...
深圳大学计软《面向对象的程序设计》实验8 静态与友元
A. 旅馆旅客管理(静态成员) 题目描述 编写程序,实现某旅馆的客人住宿记录功能。 定义一个Customer类,要求输入客人的姓名,创建一个Customer对象。类声明如下: 调用类的Display函数输出客人IDÿ…...
【基础算法】单链表的OJ练习(2) # 链表的中间结点 # 链表中倒数第k个结点 #
文章目录前言链表的中间结点链表中倒数第k个结点写在最后前言 对于单链表的OJ练习,需要深刻理解做题的思路,这样我们才能够在任何场景都能够熟练的解答有关链表的问题。 关于OJ练习(1):-> 传送门 <-,…...
vue路由文件拆分管理
随着项目的原来越大,路由越来越多,我们的路由也会越来越多,如果都集中在一个文件中,会很冗杂文件很长。这时候我们可以将路由文件拆分,可读、方便管理。多人合作添加路由也能更多的避免代码冲突 代码拆分目录如图&…...
实例解析Java反射
反射是大多数语言里都必不不可少的组成部分,对象可以通过反射获取他的类,类可以通过反射拿到所有方法(包括私有),拿到的方法可以调用,总之通过“反射”,我们可以将Java这种静态语言附加上动态特…...
Android 9适配经验总结
目录四大组件适配Activity启动方式适配Service启动方式适配前台服务需要添加权限限制静态广播的接收限制ContentResolver数据更新操作权限与安全相关主要适配点运行时动态权限申请默认不支持 http 请求SharedPreferences 适配四大组件适配 Android 应用的开发离不开 Android 四…...
定时任务调度方案——Xxl-Job
定时任务调度方案 随着系统规模的发展,项目的组织结构以及架构越来越复杂,业务覆盖的范围越来越广,定时任务数量日益增多,任务也变得越来越复杂,尤其是为了满足在用户体量日历增大时,系统能够稳定运行&…...
操作系统引导
操作系统是一种程序,程序以数据的形式存放在硬盘中,而硬盘通常分为多个区,一个计算机中又有多个或多种外部设备。 操作系统引导指的是计算机利用CPU运行特定程序,通过程序识别硬盘,识别硬盘分区,识别硬盘分…...
[C#] 多线程单例子,分为阻塞型和分阻塞型, 在unity里的应用
在单例中使用多线程时,需要注意以下几点: 线程安全:在多线程环境下,单例对象可能被多个线程同时访问,因此需要确保单例的线程安全,避免出现数据竞争等问题。 对象创建:如果在单例对象的构造函数…...
使用MAT进行内存分析,并找到OOM问题
前言 在处理一次现场问题时,发现服务还在运行,但是出现假死情况,后通过分析GC日志以及使用MAT分析确定问题是内存溢出OutOfMemery(OOM);这里只记录MAT分析学习过程,最近工作忙,补记录。 GC日志分析 首先,如…...
初识Python
目录初识Python1.Python简介Python的优缺点Python的应用领域2.安装Python解释器Windows环境Linux环境macOS环境3.运行Python程序确认Python的版本编写Python源代码运行程序代码中的注释4.Python开发工具IDLE - 自带的集成开发工具IPython - 更好的交互式编程工具Sublime Text -…...
乐清企业网站建设/谷歌排名查询
往期精选● 架构师高并发高性能分布式教程(4000G)● 39阶段精品云计算大数据实战视频教程● 互联网技术干货视频教程大全【菜单为准】● 2017年8月最新Intellij IDEA全套视频教程● 程序员如何制作高质量的简历【视频简历】● 两套大型电商实战项目 ● 200本经典编程相关…...
织梦是怎么做网站/新出的app推广在哪找
叶问《叶问》是知数堂新设计的互动栏目,不定期给大家提供技术知识小贴士,形式不限,或提问、或讨论均可,并在当天发布答案,让大家轻轻松松利用碎片时间就可以学到最实用的知识点。2018年11月6日,周二Show pr…...
网站设计合同范本/2023年九月份新闻
报名号姓名生源省市专业191033522000094蔡礼阳广东省综合评价-(101)电子与计算机工程(中外合作办学)191033522000480曹淞广东省综合评价-(101)电子与计算机工程(中外合作办学)191033522000684曾成广东省综合评价-(101)电子与计算机工程(中外合作办学)191033522000350曾维翰广东…...
wordpress 提请审批/seo是哪里
如何在以下示例中删除保留html内容的所有未知存在自定义标记:my headermy Titlemy SubTitle我想回来my headermy Titlemy SubTitleHTML清理程序有什么解决方案吗?谢谢你的帮助。答案您可以使用HtmlSanitizer.RemovingTag事件来保留标记的内容:…...
营销网站的成功案例/制作网站的工具
策划|小智 “Single boy,single boy,single all the way~Cant find a girl for whole day,better to be gay,hey!” 国人有一种族天赋,就是可以把各种节都过成情人节,继而为爱鼓掌。但与此同时,中国又是一个性别比例失调严重的国家…...
免费的网站推广 外贸/网络优化的三个方法
php Undefined index和Undefined variable的解决方法$act$_POST[act];用以上代码总是提示Notice: Undefined index: act in F:\windsflybook\post.php on line 18另外,有时还会出现引用内容Notice: Undefined variable: Submit ......等一些这样的提示原因ÿ…...