Kafka生产调优实践。Kafka消息安全性、消息丢失、消息积压、保证消息顺序性
文章目录
- 搭建Kafka监控平台
- 合理规划Kafka部署环境
- 合理优化Kafka集群配置
- 优化Kafka客户端使用方式
- 合理保证消息安全
- 消费者防止消息重复消费
- 生产环境常见问题分析
- 消息零丢失方案
- 消息积压如何处理
- 如何保证消息顺序
搭建Kafka监控平台
官网地址
下载efak-web-3.0.2-bin.tar.gz安装包之后,efak需要依赖JDK和数据库。数据库支持本地化的SQLLite以及集中式的MySQL。生产环境建议使用MySQL。
数据库不需要建表初始化,EFAK在执行过程中会自己完成初始化。
将efak压缩包解压
[root@worker1 ~]# tar -zxvf efak-web-3.0.2-bin.tar.gz -C /app/kafka/eagle
修改efak解压目录下的conf/system-config.properties。 这个文件中提供了完整的配置,下面只列出需要修改的部分。
######################################
# multi zookeeper & kafka cluster list
# Settings prefixed with 'kafka.eagle.' will be deprecated, use 'efak.' instead
######################################
# 指向Zookeeper地址
efak.zk.cluster.alias=cluster1
cluster1.zk.list=worker1:2181,worker2:2181,worker3:2181######################################
# zookeeper enable acl
######################################
# Zookeeper权限控制
cluster1.zk.acl.enable=false
cluster1.zk.acl.schema=digest
#cluster1.zk.acl.username=test
#cluster1.zk.acl.password=test123######################################
# kafka offset storage
######################################
# offset选择存在kafka中。
cluster1.efak.offset.storage=kafka
#cluster2.efak.offset.storage=zk######################################
# kafka mysql jdbc driver address
######################################
#指向自己的MySQL服务。库需要提前创建
efak.driver=com.mysql.cj.jdbc.Driver
efak.url=jdbc:mysql://worker1:3306/ke?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
efak.username=root
efak.password=root
配置EFAK的环境变量
[root@worker1 ~]# vi ~/.bash_profile
export KE_HOME=/app/kafka/eagle/efak-web-3.0.2
PATH=$PATH:#KE_HOME/bin:$HOME/.local/bin:$HOME/bin[root@worker1 ~]# source ~/.bash_profile
启动EFAK
配置完成后,先启动Zookeeper和Kafka服务,然后调用EFAK的bin目录下的ke.sh脚本启动服务
[root@worker1 bin]$ ./ke.sh start
-- 日志很长,看到以下内容表示服务启动成功
[2023-06-28 16:09:43] INFO: [Job done!]
Welcome to______ ______ ___ __ __/ ____/ / ____/ / | / //_// __/ / /_ / /| | / ,< / /___ / __/ / ___ | / /| |
/_____/ /_/ /_/ |_|/_/ |_|
( Eagle For Apache Kafka® )Version v3.0.2 -- Copyright 2016-2022
*******************************************************************
* EFAK Service has started success.
* Welcome, Now you can visit 'http://192.168.232.128:8048'
* Account:admin ,Password:123456
*******************************************************************
* <Usage> ke.sh [start|status|stop|restart|stats] </Usage>
* <Usage> https://www.kafka-eagle.org/ </Usage>
*******************************************************************
EFAK管理页面
接下来就可以访问EFAK的管理页面。http://192.168.232.128:8048。 默认的用户名是admin ,密码是123456
关于EFAK更多的使用方式,比如EFAK服务如何集群部署等,可以参考官方文档。
合理规划Kafka部署环境
机械硬盘kafka使用机械硬盘即可,可以不用给Kafka固态硬盘
内存,修改 bin/kafka-start-server.sh
启动脚本,修改JVM启动参数中的内存,默认只申请了1G内存。
[oper@worker1 bin]$ cat kafka-server-start.sh
......
if [ "x$KAFKA_HEAP_OPTS" = "x" ]; thenexport KAFKA_HEAP_OPTS="-Xmx1G -Xms1G"
fi
......
对于主流的16核32G服务器,可以适当扩大Kafka的内存。例如:
export KAFKA_HEAP_OPTS="‐Xmx16G ‐Xms16G ‐Xmn10G ‐XX:MetaspaceSize=256M ‐XX:+UseG1GC ‐XX:MaxGCPauseMillis=50 ‐XX:G1HeapRegionSize=16M"
高性能网卡,Kafka本身的服务性能非常高,单机就可以支持百万级的TPS,在高流量冲击下,网络非常有可能优先成为性能瓶颈。对于Kafka服务器,建议配置高性能的网卡。成本允许的话,尽量选择千兆以上的网卡。
合理优化Kafka集群配置
合理配置partition分区数量
Kafka的单个Partition读写效率是非常高的,但是Kafka的Partition设计是非常碎片化。如果Partition文件过多,很容易严重影响Kafka的整体性能。
- 尽量不要使用过多的Topic,通常不建议超过3个Topic。
- 一个分区下的副本集数量不要设置过多 将副本数设置为2就可以了。
至于Partition的数量,最好根据业务情况灵活调整。partition数量设置多一些,可以一定程度增加Topic的吞吐量。但是过多的partition数量还是同样会带来partition索引的压力。
Kafka提供了一个生产者的性能压测脚本,可以用来衡量集群的整体性能。
# num-record表示要发送100000条压测消息,record-size表示每条消息大小1KB,throughput表示限流控制,设置为小于0表示不限流。
# properducer-props用来设置生产者的参数。
[oper@worker1 bin]$ ./kafka-producer-perf-test.sh --topic test --num-record 1000000 --record-size 1024 --throughput -1 --producer-props bootstrap.servers=worker1:9092 acks=1
94846 records sent, 18969.2 records/sec (18.52 MB/sec), 1157.4 ms avg latency, 1581.0 ms max latency.
133740 records sent, 26748.0 records/sec (26.12 MB/sec), 1150.6 ms avg latency, 1312.0 ms max latency.
146760 records sent, 29346.1 records/sec (28.66 MB/sec), 1051.5 ms avg latency, 1164.0 ms max latency.
137400 records sent, 27480.0 records/sec (26.84 MB/sec), 1123.7 ms avg latency, 1182.0 ms max latency.
158700 records sent, 31740.0 records/sec (31.00 MB/sec), 972.1 ms avg latency, 1022.0 ms max latency.
158775 records sent, 31755.0 records/sec (31.01 MB/sec), 963.5 ms avg latency, 1055.0 ms max latency.
1000000 records sent, 28667.259123 records/sec (28.00 MB/sec), 1030.44 ms avg latency, 1581.00 ms max latency, 1002 ms 50th, 1231 ms 95th, 1440 ms 99th, 1563 ms 99.9th.
合理对数据进行压缩
在生产者的ProducerConfig中,有一个配置 COMPRESSION_TYPE_CONFIG,是用来对消息进行压缩的。
public static final String COMPRESSION_TYPE_CONFIG = "compression.type";
生产者配置了压缩策略后,会对生产的每个消息进行压缩,从而降低Producer到Broker的网络传输,也降低了Broker的数据存储压力。
所支持的几种压缩算法中,zstd算法具有最高的数据压缩比,但是吞吐量不高,lz4在吞吐量方面的优势比较明显。压缩消息必然增加CPU的消耗,如果CPU资源紧张,就不要压缩了。
关于数据压缩机制,可以在Broker的conf/server.properties文件中进行配置。正常情况下,Broker从Producer端接收到消息后不会对其进行任何修改,但是如果Broker端和Producer端指定了不同的压缩算法,就会产生很多异常的表现。
compression.typeType: string
Default: producer
Valid Values: [uncompressed, zstd, lz4, snappy, gzip, producer]
如果开启了消息压缩,那么在消费者端自然是要进行解压缩的。
在Kafka中,消息从Producer到Broker再到Consumer会一直携带消息的压缩方式,这样当Consumer读取到消息集合时,自然就知道了这些消息使用的是哪种压缩算法,也就可以自己进行解压了。但是这时要注意的是应用中使用的Kafka客户端版本和Kafka服务端版本是否匹配。
优化Kafka客户端使用方式
合理保证消息安全
消息生产者设置好发送者应答参数
- 消息生产者的
acks
参数,可以设置为0、1、all或-1 - Broker的min.insync.replicas参数。如果生产者的acks设置为-1或all,服务端并不是强行要求所有Paritition都完成写入再返回,而是可以配置多少个Partition完成消息写入后,再往Producer返回消息。
生产者端的幂等性配置
// 值为 true 或 false
public static final String ENABLE_IDEMPOTENCE_CONFIG = "enable.idempotence";
如果要开启幂等性,那么
- 生产者消息缓存机制中的
max.in.flight.requests.per.connection
<=5 - 重试次数
retries
>0 - 应答机制中的
acks
必须为all
其他补充点:
- 如果没有设置冲突配置,则默认启用幂等性。
- 如果设置了冲突的配置,并且幂等性没有显式启用,则幂等性被禁用。
- 即显示开启的幂等性,又有冲突配置,就抛异常
使用生产者事务机制发送消息
// 1 初始化事务
void initTransactions();
// 2 开启事务
void beginTransaction() throws ProducerFencedException;
// 3 提交事务
void commitTransaction() throws ProducerFencedException;
// 4 放弃事务(类似于回滚事务的操作)
void abortTransaction() throws ProducerFencedException;
SpringBoot集成Kafka时使用的KafkaTemplate就提供了事务消息机制
消费者端合理使用提交方式
如果消费者要使用异步方式进行业务处理,那么如果业务处理失败,此时消费者已经提交了Offset,这个消息就无法重试了,这就会造成消息丢失。
因此在消费者端,尽量不要使用异步处理方式,在绝大部分场景下,就能够通过Kafka的消费者重试机制,保证消息安全处理。此时,在消费者端,需要更多考虑的问题,就变成了消费重试机制造成的消息重复消费的问题。
消费者防止消息重复消费
问题的产生:消费者业务处理时间较长,此时消费者正常处理消息的过程中,Broker端就已经等不下去了,认为这个消费者处理失败了。这时就会往同组的其他消费者实例投递消息,这就造成了消息重复处理。这就给消费者端带来不必要的幂等性问题。
解决方式:
-
根据业务ID校验。比如对于订单消息,消费者根据订单ID去确认一下这个订单消息有没有处理过。
-
统一的方式处理幂等性问题
将Offset放到Redis中自行进行管理。通过Redis中的offset来判断消息之前是否处理过。
具体实现详情请参考上文《客户端 — 客户端属性分析 — 消息重复消费问题》
生产环境常见问题分析
消息零丢失方案
1、 生产者发送消息到Broker不丢失
生产者丢失消息的原因就和ack机制有关,如果将acks
设置为1、all或-1 就表示接收到Broker成功将消息写入文件后的ack应答
2、Broker端保证消息不丢失
Broker端丢失消息的原因主要有两种:Leader partition重新选举、服务器非正常关机 pageCache中的消息还未刷盘
《服务端的Zookeeper元数据梳理 — Partition故障恢复机制》 《服务端日志 — 合理配置刷盘频率》
消息生产者将acks
设置为all可以有效避免因为Leader partition故障导致的消息丢失;
而pageCache刷盘可以通过下面的参数来设定合理的配置
# 多长时间进行一次强制刷盘。默认是Long.MAX。
flush.ms# 表示当同一个Partiton的消息条数积累到这个数量时,就会申请一次刷盘操作。默认是Long.MAX。
log.flush.interval.messages#当一个消息在内存中保留的时间,达到这个数量时,就会申请一次刷盘操作。他的默认值是空。如果这个参数配置为空,则生效的是下一个参数。
log.flush.interval.ms# 日志刷新程序检查是否需要将日志刷新到磁盘的频率(以毫秒为单位),默认也是Long.MAX。
log.flush.scheduler.interval.ms
3、消费者保证消息不丢失
同步处理业务逻辑,同步手动提交offset
消息积压如何处理
-
如果业务运行正常,只是因为消费者处理消息过慢,造成消息加压。
增加消费者个数,最多让一个消费者组下的消费者个数=Partition分区数,让一个Consumer负责一个分区,将消费进度提升到最大。
如果还是不够,那就新创建一个topic,给这个topic更多的partition,然后启动一批消费者,将消息从旧topic中搬运到新topic中,这些消费者不处理业务消息,仅仅是搬运。这样就可以创建更多的消费者消费从新topic消费了
-
如果是消费者业务处理异常导致的消息积压。
使用一种降级方案。先启动一个Consumer将Topic下的消息先转发到其他队列中,然后再慢慢分析新队列里的消息处理问题。类似于死信队列的处理方式。
如何保证消息顺序
Kafka很难保证消息的顺序,因为Kafka设计的最优先重点是海量吞吐。
这个问题要分两个方面考虑:
- Topic下各个partition是并发处理消息的 ,producer要保证一组有序的消息发送到一个partition中
- consumer要从partition中顺序处理消息
问题一:producer要保证一组有序的消息发送到一个partition中
第一种简单粗暴的方式就只为Topic创建一个partition,这种方式放弃了多partition带来的高吞吐量。
第二种方式,自己定义一个分区路由机制,实现org.apache.kafka.clients.producer.Partitioner
接口,将消息分配到同一个Partition上。
此时发送方保证了发送时的消息顺序性。但是存在网络问题,导致发送的一批消息中某一个消息丢失,这样消息到Broker时就还是没办法保证顺序性。Kafka是通过幂等性中单调递增的sequenceNumber来保证消息是顺序,因为是单调递增的,所以还能判断是否存在消息丢失一旦Kafka发现Producer传过来的SequenceNumber出现了跨越,那么就意味着中间有可能消息出现了丢失,就会往Producer抛出一个OutOfOrderSequenceException异常。
问题二:Partition中的消息有序后,如何保证Consumer的消费顺序是有序的
// 一次拉取消息的数量
public static final String FETCH_MAX_BYTES_CONFIG = "fetch.max.bytes";
Note that the consumer performs multiple fetches in parallel.public static final int DEFAULT_FETCH_MAX_BYTES = 50 * 1024 * 1024;
从上方fetch.max.bytes
参数的最后一个解释可以知道Consumer其实是每次并行的拉取多个Batch批次的消息进行处理的。所以在Kafka提供的客户端Consumer中,是没有办法直接保证消费的消息顺序。
我们能做的就是在Consumer的处理逻辑中,将消息进行排序。比如将消息按照业务独立性收集到一个集合中,然后在集合中对消息进行排序。
RocketMQ中提供了顺序消息的实现。他的实现原理是先锁定一个队列,消费完这一个队列后,才开始锁定下一个队列,并消费队列中的消息。再结合MessageQueue中的消息有序性,就能保证整体消息的消费顺序是有序的。
相关文章:

Kafka生产调优实践。Kafka消息安全性、消息丢失、消息积压、保证消息顺序性
文章目录 搭建Kafka监控平台合理规划Kafka部署环境合理优化Kafka集群配置优化Kafka客户端使用方式合理保证消息安全消费者防止消息重复消费 生产环境常见问题分析消息零丢失方案消息积压如何处理如何保证消息顺序 搭建Kafka监控平台 官网地址 下载efak-web-3.0.2-bin.tar.gz安…...

DDColor部署安装,在服务器Ubuntu22.04系统——点动科技
DDColor图片上色项目的部署安装,在服务器Ubuntu22.04系统——点动科技 一、ubuntu22.04基本环境配置1.1 更换清华Ubuntu镜像源1.2 更新包列表:2. 安装英伟达显卡驱动2.1 使用wget在命令行下载驱动包2.2 更新软件列表和安装必要软件、依赖2.2 卸载原有驱动…...
使用 SSL/TLS 加密保障 RocketMQ 的安全传输
引言 在现代分布式系统中,数据传输的安全性至关重要。Apache RocketMQ作为一款高性能、高吞吐量的消息中间件,在许多关键应用场景中被广泛使用。为了确保消息传输的安全性,SSL/TLS 加密提供了一种可靠的解决方案。本文将详细介绍如何在 Rock…...
uni-app开发
参考帖 uniapp官方文档 组件库 项目中肯定需要使用第三方组件库,因为现有的这些不够方便我们去使用 uview: 演示 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 ThorUI: 介绍 | ThorUI文档 创建uni-app项目 有HBuilder…...
2024社招面经_存储DB广告架构方向
总结 第一次社招,主要是三四月份面的,offer的有高德、拼多多、腾讯、美团、快手、携程,后面面的比较累了,因为美团定级和涨幅都还行就去了美团,没再继续面别的。 因为时间比较久了,只在这里贴一下当时有记…...

android10 系统定制:增加应用锁功能
实现效果如下,上锁应用在桌面或最近任务打开弹出解锁界面,需要解锁成功才能打开应用。解锁界面可点击返回或Home键关闭,非上锁应用可直接打开。 基本思路:拦截系统应用启动,判断应用是否在锁住状态,弹出解锁Window。解锁完成后再正常启动应用。分为从桌面启动和最近任务…...

数据结构----队列
一、队列 1)队列定义 队列(Queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。 允许插入的端是队尾,允许删除的端是队头。队列是一个先进先出(FIFO)的线性表,相应 的也有顺序存储和链式存储两种方式。 2&#…...

【python】实现对文件夹中的图像连续重命名方法
import os import shutildef rename_images(input_folder):# 获取输入文件夹下的所有图片文件(假设都是.jpg格式)image_files [f for f in os.listdir(input_folder) if os.path.isfile(os.path.join(input_folder, f)) and f.endswith(".jpg"…...

【nginx 第一篇章】认识一下 NGINX 服务器
一、简介 Nginx (engine x) 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。由俄罗斯程序员 Igor Sysoev 开发,并在2004年首次公开发布。Nginx 以其高并发处理能力、低内存消耗、稳定性、丰富的功能集、简单的配置以及低学…...
【物联网】(防水篇)哪些电子产品需要通过 IPX7 防水级别测试?
哪些电子产品需要通过 IPX7 防水级别测试? 举例一些可能需要通过 IPX7 防水级别测试的产品 - 电子产品:如智能手机、平板电脑、智能手表、运动手环等,以满足用户在不同场景下的使用需求,例如在潮湿环境或意外沾水时仍能正常工作。…...
高级java每日一道面试题-2024年8月09日-网络篇-什么是XSS攻击如何避免?
如果有遗漏,评论区告诉我进行补充 面试官: 什么是XSS攻击如何避免? 我回答: XSS(Cross-Site Scripting,跨站脚本攻击)是一种常见的Web应用程序安全漏洞,攻击者通过在网页中注入恶意脚本,当其他用户浏览这些网页时&…...
Linux时间管理:命令与脚本的完美结合
目录 前言 Linux时间管理命令 date命令 cron定时任务 at命令 sleep命令 脚本与时间命令的结合使用 备份脚本示例 设置cron任务 监控脚本执行时间 结论 致谢 前言 在Linux系统中,时间管理是一项基础而关键的任务。无论是安排周期性的备份、监控任务的执…...

基于ssm+vue+uniapp的微信外卖小程序
开发语言:Java框架:ssmuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:M…...

lvs(linux virtual server)实例
一.lvs概述 1.1什么是lvs LVS(Linux Virtual Server)是一个基于Linux操作系统的虚拟服务器技术,用于实现负载均衡和高可用性。LVS通过将客户端的请求分发到多台后端服务器上,从而提高整体服务的处理能力和可靠性。LVS主要有两个组…...

Unity游戏开发
Unity游戏开发 系列文章的目录: 第一章:Hello,Unity! “好读书,不求甚解;每有会意,便欣然忘食。” 本文目录: Unity游戏开发 Unity游戏开发前言今天我们来体验一下unity开发创建第一…...
5. MQTT消息类型详解(三)
9 SUBACK消息 9.1 消息结构 SUBACK消息是订阅确认消息,格式如下: ------------------------------- | 消息类型(1字节) | ------------------------------- | 保留标志(1字节) …...
TypeScript JSX
介绍 在线的免费的代码转换器工具:可以把HTML 代码移植到 JSX 语法。还支持很多其他的转换。 JSX 是 ECMAScript 的一种类似 XML 的语法扩展,没有任何定义的语义。它不打算由引擎或浏览器实现。它并不是将 JSX 纳入 ECMAScript 规范本身的提议。它旨在供…...

java里的序列化反序列化、HttpMessageConverter、Jackson、消息转化器、对象转化器...都是啥?
前段时间在学习SSM框架(spring boot、spring MVC、mybatis)后端项目的时候,发现他们的项目里:响应类Result类要实现Serializable接口、转化响应给前端的时间数据的格式要用到什么“消息转换器”MappingJackson2HttpMwssageConvert…...
GNU/Linux - memtool使用
在Yocto中为NXP的i.MX系列芯片构建Linux系统时,可以加入一些实用工具,比如直接操作内存的memtool。 这些工具在imx-test包中,比如imx-test_git.bb里。 比如在imx-image-core.bb中,IMAGE_INSTALL "imx-test" ࿰…...
Qt5.12.8源码交叉编译带openssl版本
一.背景 近期项目由于对接方的Qt版本是Qt5.12.8,后台服务是https的,之前用的Qt5.15.10要切换成Qt5.12.8,并且为了能支持https,必须要重新编译Qt。 二.环境 环境准备: Ubuntu版本 :18.04; openss…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...

JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...