Redis (Remote Dictionary Server) 是一种高性能的键值(Key-Value)内存数据库,以其丰富的数据结构、极低的延迟、出色的稳定性和强大的集群能力,在现代应用程序的开发中扮演着至关重要的角色。无论是作为缓存、消息队列、会话存储,还是简单的键值对数据库,Redis 都展现出卓越的性能和灵活性。

本文将深入探讨 Redis 的三大核心基石:核心数据结构、数据持久化机制以及高可用与高扩展的集群方案。通过理解这些底层原理,开发者能够更有效地利用 Redis، 规避常见陷阱,并构建出更加健壮、高效的分布式系统。

第一章:Redis 核心数据结构——不仅仅是 Key-Value

Redis 的核心竞争力之一就在于其提供了多种高效、特化的数据结构,远超简单的字符串(String)类型。这些数据结构允许开发者用更恰当的方式来存储和操作数据,极大地提高了效率和表达能力。

1.1 String (字符串)

String 是 Redis 最基本也是最常用的数据类型。它能够存储任何形式的字符串,包括二进制安全(Binary Safe),这意味着你可以存储图片、序列化的对象等。

用途: 缓存单个键值对、计数器、简单的会话存储。

常用命令: SET, GET, INCR, DECR, SETNX (Set if Not Exists), GETRANGE, SETEX (Set with Expiration), APPEND。

底层实现:

SDS (Simple Dynamic String): Redis 自己实现的一种动态字符串结构。它比 C 语言的 char* 数组更高效,包含额外信息(如字符串长度、已分配空间),避免了多次内存重分配。

Embstr (Embedded String): 当字符串长度较短(小于 39 字节)时,Redis 会将其直接存储在 SDS 的 buf 字段之后,无需额外的内存分配。

1.2 List (列表)

List 是一个按照插入顺序排序的字符串集合。它可以通过链表或压缩列表(ziplist)来实现。

用途: 微博时间线、消息队列、任务队列。

常用命令: LPUSH, RPUSH (从左/右侧入栈), LPOP, RPOP (从左/右侧出栈), LRANGE (获取范围元素), LLEN (获取长度), BLPOP/BRPOP (阻塞式出栈)。

底层实现:

Quicklist: Redis 3.2 引入的混合数据结构,它是一个双向链表,链表的每个节点都是一个压缩列表 (ziplist)。当列表元素较少时,表现为 ziplist;当元素增多时,链表会分裂成多个 ziplist 节点,提供了很好的内存利用率和操作性能。

1.3 Hash (散列)

Hash 是一种键值对的集合,用于存储对象的属性。

用途: 存储用户对象、配置信息。

常用命令: HSET, HGET, HMSET, HMGET, HGETALL, HINCRBY。

底层实现:

Hashtable: 当字段和值的数量较少时,使用压缩列表 (ziplist)。

Hash Table: 当字段和值的数量超过一定阈值时(hash-max-ziplist-entries 和 hash-max-ziplist-value),会自动转换成普通哈希表。HASHTABLE 是基于动态数组和链表实现的,提供 O(1) 的平均复杂度的查找。

1.4 Set (集合)

Set 是一个无序的、不重复的字符串集合。

用途: 点赞/关注列表、用户标签。

常用命令: SADD, SM REM, SISMEMBER, SCARD (个数), SRANDMEMBER (随机成员), 集合间操作 (SINTER, SUNION, SDIFF)。

底层实现:

Hashtable: 当元素个数较少时,使用压缩列表 (ziplist)。

Intset: 当集合中的所有成员都是整数时,Redis 会优先使用整数集合 (intset),这是一种更节省内存的实现。

1.5 Sorted Set (有序集合)

Sorted Set 是一个有序的、不重复的字符串集合。每个成员都关联一个分数(score),Redis 会根据分数对成员进行排序。

用途: 排行榜、文章的权重排序、延时任务队列。

常用命令: ZADD, ZREM, ZCARD, ZRANGE (按分数/索引范围获取), ZRANK (按索引获取), ZSCORE (获取分数), ZINCRBY。

底层实现:

Hashtable + Skip List: Redis 使用一个散列表 (hashtable) 来存储成员和分数的映射,实现 O(1) 的平均查找。同时,使用 跳跃表 (Skip List) 来存储成员和分数,并根据分数进行排序,实现 O(log N) 的插入、删除和查找。

Ziplist: 当集合中的成员数量和元素值都比较小时,Sorted Set 也会使用 压缩列表 (ziplist) 来优化内存。

1.6 Bitmaps (位图) & HyperLogLog

Bitmaps: 将字符串看作一个大的位数组,可以对单个比特位进行设置和获取。

用途: 用户签到统计、在线状态跟踪。

命令: SETBIT, GETBIT, BITCOUNT, BITOP (位运算)。

HyperLogLog (HLL): 一种概率性数据结构,用于基数统计(Cardinality Estimation),即统计一个集合中不重复元素的数量。即使数据集非常庞大,HLL 也能以极小的内存占用(约 12KB)提供非常接近准确的估计值。

用途: 统计网站 UV、直播观看人数、用户标签数量。

命令: PFADD, PFCOUNT, PFMERGE。

1.7 Geospatial (地理空间索引)

Redis 3.2 引入了地理空间索引,支持根据经度和纬度进行存储和查询。

用途: 附近的人/地点查找。

命令: GEOADD, GEORADIUS, GEODIST, GEOHASH, GEOPOS。

底层实现: 使用 Sorted Set 来存储地理位置信息,通过将二维坐标编码为一维的 zset 分数来实现。

第二章:Redis 数据持久化——内存数据的“保鲜之道”

Redis 是一个内存数据库,数据存储在内存中,操作速度快。但一旦 Redis 进程关闭或服务器断电,内存中的数据就会丢失。为了解决这个问题,Redis 提供了两种持久化机制:RDB (Redis Database) 快照 和 AOF (Append Only File) 日志。

2.1 RDB (Redis Database) 快照

RDB 持久化是指在指定的时间间隔内,将内存中的数据集以快照的形式周期性地保存到磁盘上的一个二进制文件(dump.rdb)中。

工作原理:

Redis 使用 fork() 系统调用创建一个子进程。

子进程继承父进程的内存副本,并通过写时复制(Copy-On-Write, COW)机制。当父进程修改内存中的数据时,子进程会复制需要修改的部分,以保证数据的一致性。

子进程完成后,将内存快照写入 RDB 文件。

父进程继续接收客户端请求,并修改内存数据。

优点:

生成紧凑的二进制文件: RDB 文件体积小,易于传输和备份。

完全备份: RDB 文件包含了某个时间点上的完整数据库状态。

恢复速度快: 加载 RDB 文件时,Redis 可以快速地将数据恢复到内存中。

不阻塞主进程: RDB 保存操作由子进程完成,主进程可以继续处理读写请求。

缺点:

数据丢失风险: 由于是周期性快照,如果服务器在两次快照之间发生故障,期间发生的数据修改将丢失。

fork() 操作的开销: 当数据集非常大时,fork() 操作可能会消耗较多的 CPU 和内存资源,尤其是在主 Redis 进程还在处理写请求时。

配置参数 (redis.conf):

<REDIS>

# RDB 持久化配置

# 900秒(15分钟)内,如果至少有1个key被修改

save 900 1

# 300秒(5分钟)内,如果至少有10个key被修改

save 300 10

# 60秒(1分钟)内,如果至少有10000个key被修改

save 60 10000

# RDB 文件名

dbfilename dump.rdb

# RDB 文件保存目录

dir /var/lib/redis/

2.2 AOF (Append Only File) 日志

AOF 持久化会将 每一个 客户端写操作命令都记录到一个 AOF 文件中。当 Redis 重启时,会重新执行 AOF 文件中的所有命令,将数据恢复到内存。

工作原理:

客户端发送写命令。

Redis 将该写命令追加到 AOF 缓冲区的末尾。

根据 appendfsync 的策略,将 AOF 缓冲区的内容写入 AOF 文件。

appendfsync always: 每一次写命令都立即写入 AOF 文件,并立即将数据同步到磁盘。最安全,但性能最低。

appendfsync everysec (默认): 每秒将 AOF 缓冲区的内容写入 AOF 文件一次,并同步到磁盘。兼顾了安全性和性能。

appendfsync no: 不主动将 AOF 缓冲区写入磁盘,而是交给操作系统异步写入。性能最高,但数据丢失风险最大。

当 AOF 文件过大时,Redis 会启动 AOF 重写 (AOF Rewrite) 机制,将内存中的数据重新以命令的形式写入一个新的 AOF 文件,从而压缩文件大小。Rewrite 操作是异步进行的。

优点:

数据丢失风险小: 相比 RDB,AOF 的数据丢失风险极低(everysec 模式下最多丢失 1 秒的数据)。

可读性强: AOF 文件是文本格式,人类可读,可以手动修改(尽管不推荐,容易破坏数据)。

命令恢复: 通过重放命令恢复数据,数据一致性更好。

缺点:

文件体积大: AOF 文件记录了每一个写命令,体积通常比 RDB 文件大。

恢复速度慢: 重放大量命令比加载 RDB 文件慢。

写操作开销: appendfsync always 和 everysec 都会涉及到 fsync 系统调用,这对性能有影响。

配置参数 (redis.conf):

<REDIS>

# 是否开启 AOF 持久化

appendonly yes

# AOF 文件名

appendfilename "appendonly.aof"

# AOF 同步策略

# appendfsync always # 每次写入都同步,最安全

appendfsync everysec # 每秒同步一次,数据丢失最少,推荐

# appendfsync no # 由操作系统决定何时同步,性能最高,风险最大

# AOF Rewrite 相关配置

auto-aof-rewrite-percentage 100 # 当前 AOF 文件大小超过上一次重写后增长多少百分比时触发重写

auto-aof-rewrite-min-size 64mb # 触发重写的最小文件大小

2.3 RDB 和 AOF 的选择与组合

RDB: 适合做全量备份,可以定期生成 RDB 快照(例如每天一次)用于灾难恢复。

AOF: 适合记录增量数据,保证高可用性。

推荐组合: 同时开启 RDB 和 AOF。Redis 会优先使用 AOF 文件来恢复数据(如果 AOF 文件存在)。RDB 则可以定期用于备份。这种组合兼顾了数据可靠性和恢复效率。

第三章:Redis 集群——高可用与高扩展的基石

当单个 Redis 实例的内存或 QPS 无法满足需求时,就需要引入 Redis 集群方案。Redis 提供了多种集群方案,其中 Redis Cluster 是官方推荐的、原生支持高可用和高扩展的分布式解决方案。

3.1 Redis Cluster 核心概念

槽 (Slot): Redis Cluster 将整个数据集划分为 16384 个哈希槽 (hash slots)。每个键 (key) 都会被计算一个哈希值,然后映射到这 16384 个槽中的一个。

主从复制 (Master-Replica Replication): 每个槽都可以被复制到多个 Redis 节点上,形成主从关系。主节点负责写操作,从节点负责读操作(只读)。

数据分片 (Sharding): 通过将不同的哈希槽分配给不同的节点,数据被分散存储在不同的 Redis 实例上,实现了数据的水平扩展。

hash(key) -> slot -> node

自动故障转移 (Automatic Failover): 当主节点发生故障时,从节点可以自动升级为主节点,保证集群的可用性。

高可用性: 通过主从复制和自动故障转移,确保即使部分节点宕机,服务仍然可用。

高扩展性: 通过增加更多节点,可以存储更多数据,并分担更多的请求压力。

3.2 Redis Cluster 的工作流程

客户端连接: 客户端可以选择连接到集群中的任意一个主节点。

槽查找: 当客户端尝试对一个键执行命令时,客户端会计算该键的哈希值,并找到对应的槽。

转向 (Redirection):

如果客户端连接的节点不负责该槽,该节点会返回一个 MOVED 错误,告知客户端正确的节点地址。

客户端收到 MOVED 错误后,会自动更新本地的槽位信息,并重新向正确的节点发送命令。

PoinTTs 模式 (Smart Clients): 为了减少客户端的转向次数,现代 Redis 客户端支持 PoinTTs 模式,它们会维护一个槽到节点的映射表,并缓存起来。

执行命令: 命令最终被发送到负责该槽的主节点上执行。

数据写入/同步: 主节点执行写命令,并将数据同步给其所有从节点。

读操作: 读操作可以分发到主节点或从节点。

3.3 Redis Cluster 的一致性

Redis Cluster 遵循 CAP 定理 中的 CP (Consistency, Partition Tolerance) 模型。

一致性 (Consistency): 在正常网络环境下,所有节点都应持有最新的数据。

分区容忍性 (Partition Tolerance): 在网络分区(节点间无法通信)的情况下,集群可以继续提供服务(但可能会降低一致性)。

可用性 (Availability): 在网络分区期间,如果发生主从切换,可能会出现短暂的不可用。

注意: Redis Cluster 存在“最终一致性”。在主节点写入数据后,到数据完全同步给所有从节点之间,可能存在一个很短的延迟。在此期间,如果该主节点宕机,数据可能会丢失。 cluster-replica-no-failover 配置项在一定程度上规避了这个问题(如果设为 yes,主节点宕机后,复制该主节点的从节点不会自动升级)。

3.4 搭建和管理 Redis Cluster

redis-cluster-cli: Redis 官方提供了一个命令行工具 redis-cli,可以通过 -c 参数启用 Cluster 模式。redis-cluster-cli 可以用于创建集群、添加/删除节点、槽迁移、故障转移等操作。

Redis Sentinel: 在 Redis Cluster 出现之前,Sentinel 是 Redis 高可用的解决方案。Sentinel 是一个独立的进程,用于监控 Redis 主节点和从节点,当主节点故障时,Sentinel 会自动进行故障转移,将从节点晋升为新的主节点。Redis Cluster 集成了 Sentinel 的一部分监控和故障转移机制。

3.5 其他集群/高可用方案

Redis Sentinel: 如上所述,用于提供哨兵管理的主从高可用方案。

Codis (由豌豆荚开发): 一款 Redis 集群方案,它将 Redis 的数据分片、集群管理、路由等功能放在一个独立的 Proxy 层实现。Proxy 层负责将客户端请求路由到正确的 Redis 节点。Codis 优点在于灵活,不要求 Redis 本身支持 Cluster 协议,但增加了额外的 Proxy 层。

Twemproxy (Twitter Proxy): 一个轻量级的 Redis 和 Memcached 代理,用于提供连接池和分片功能。它本身不提供高可用性,需要与其他的 HA 方案结合。

第四章:调优策略与实践建议

4.1 数据结构选择的艺术

优先使用特化数据结构: 如 Hash, Set, Sorted Set, List,它们通常比 String 加上复杂逻辑更高效。

考虑 SDS、ziplist、intset、Skip List: 当你的数据量和范围符合特定结构(如短字符串、整数集合、有序集合)的优化条件时,Redis 会自动选用更节省内存的底层实现。

合理使用 Bitmaps 和 HyperLogLog: 对于计数、状态跟踪、基数统计等场景,它们能提供极致的内存效率。

4.2 持久化策略的权衡

生产环境首选“RDB + AOF (everysec)”组合: 兼顾了备份的数据完整性和低数据丢失风险。

根据业务对数据丢失的敏感度调整: 如果数据丢失是毁灭性的,可以考虑 appendfsync always,但要注意其性能影响。

AOF 重写: 确保 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 设置合理,避免 AOF 文件过大。Redis 4.0 以后,AOF 可以与 RDB 混合持久化 (Coalescing)。

RDB 备份: 定期将 RDB 文件备份到安全的地方,并测试恢复流程。

4.3 Redis Cluster 最佳实践

节点数量: 建议集群至少有 3 个主节点,并为每个主节点配置至少一个从节点,以保证高可用性。

槽分配: 尽量将 16384 个槽均匀分配到每个主节点上,以实现负载均衡。

槽迁移: 在扩容或缩容时,使用 redis-cluster-cli --cluster reshard 进行槽的迁移,尽量平滑地进行。

客户端: 使用支持 Redis Cluster 协议的 Redis 客户端,并启用 PoinTTs 模式。

监控: 密切监控集群状态,包括节点连接、槽分配、主从同步、CPU/内存、命令执行延迟等。

数据一致性: 理解 Redis Cluster 提供的“最终一致性”,并在应用设计中考虑如何处理短暂的不一致。

4.4 内存优化与性能调优

maxmemory 配置: 设置 Redis 的最大内存限制,并指定驱逐策略(maxmemory-policy,如 volatile-lru, allkeys-lru),防止 Redis 耗尽系统内存,导致 OOM KILL。

Lua 脚本: 将多个 Redis 命令打包成一个 Lua 脚本在服务器端执行,可以减少网络往返次数,提高效率。

管道 (Pipeline): 将多个 Redis 命令打包发送给 Redis 服务器,服务器会连续执行所有命令并将结果打包返回。这可以显著减少网络开销。

连接池: 在客户端使用连接池,避免频繁地创建和关闭 TCP 连接。

CPU 核心分配: 考虑为 Redis 分配专门的 CPU 核心,避免与其他进程争抢 CPU 资源,尤其是在高负载场景下。

结论

Redis 强大而复杂,其核心数据结构、持久化机制和集群方案共同构成了其在高性能、高可用、高扩展领域的基石。

数据结构: 理解它们的设计原理,是巧妙利用 Redis 的关键。

持久化: 是数据安全可靠的关键,需要根据业务需求权衡 RDB、AOF 的使用。

集群: 是应对海量数据和高并发的必然选择,Redis Cluster 提供了原生、强大的解决方案。

深入掌握这些核心概念,并结合实际应用场景进行细致的调优和实践,才能真正发挥 Redis 的价值,为你的应用程序注入强劲的动力。

通过本文的学习,希望你对 Redis 有了更深层次的认识,并能将其应用于实际工作中,构建出更优、更稳定的系统。

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

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

相关文章

HTTPS优化简单总结

性能损耗选择椭圆曲线&#xff0c;并生成椭圆曲线的计算耗时CA证书验证的耗时计算pre-master的耗时硬件优化HTTPS是计算密集型任务&#xff0c;不是IO密集型任务所以硬件最好买更高级的CPU&#xff0c;而不是网卡&#xff0c;磁盘协议优化ECDHE代替RSA&#xff0c;因为ECDHE可以…

从IFA再出发:中国制造与海信三筒洗衣机的“答案”

当全球消费电子行业的目光再次聚焦柏林&#xff0c;柏林国际电子消费品展览会(IFA2025)不仅成为创新产品的秀场&#xff0c;更悄然变身为中国企业讲述全球化进阶故事的重要舞台。近日&#xff0c;海信旗下三筒洗衣机——棉花糖Ultra全家筒迎来它的国际首秀&#xff0c;首次海外…

c++工程如何提供http服务接口

在 C 工程里给类似 /index/api/ 的服务&#xff0c;基本步骤如下&#xff1a; 选一个HTTP服务框架&#xff1b;起一条监听线程&#xff08;或线程池&#xff09;&#xff1b;把路径-处理函数注册进去&#xff1b; 下面是 2 种简单的方案。方案 A&#xff1a;Crow&#xff08;He…

cfshow-web入门-php特性

web89 <?php ​ include("flag.php"); highlight_file(__FILE__); ​ if(isset($_GET[num])){$num $_GET[num];if(preg_match("/[0-9]/", $num)){die("no no no!");}if(intval($num)){echo $flag;} } 正则匹配检查不能是数字&#xff0c;但…

ctfshow - web - 命令执行漏洞总结(二)

web73该题目没有开启web72的open_basedir&#xff0c;所以可以使用var_export(scandir(/));exit();进行目录扫描。读取文件函数&#xff1a;require_once()web74scandir()函数被禁用&#xff0c;使用glob://伪协议进行读取根目录文件。cvar_export(glob(../../../*));exit(); c…

如何将视频从安卓手机传输到电脑?

无论你是否是视频爱好者&#xff0c;你可能都希望知道如何将视频从安卓手机传输到电脑&#xff0c;以释放存储空间并防止性能问题。这也有助于同步视频或防止意外删除。在本文中&#xff0c;我们将探索七种高效的传输方法。方法 1&#xff1a;仅通过 USB 将手机视频发送到电脑许…

Pico 4 Enterprise(企业版)与Unity的交互-有线串流调试篇

入手了Pico 4 E做VR开发&#xff0c;谁知入了天坑...根据官方文档&#xff0c;尝试了串流助手、企业串流、PICO Developer Center&#xff0c;陷入了各种版本问题、环境问题的陷阱。而且Pico4E的OS自24年12开始就不再更新&#xff0c;头盔中预装的企业串流版本也较低&#xff0…

redis里多线程的应用具体在哪些场景

Redis 6.0 引入的多线程I/O&#xff0c;​特指用于处理网络数据的读取&#xff08;read&#xff09;和写入&#xff08;write&#xff09;/解析&#xff08;parse&#xff09;的并行化&#xff0c;而绝非将命令的执行&#xff08;真正的数据操作&#xff09;变成多线程。这是一…

DI-GAN:基于深度学习的动态形变多模光纤透反射光控制

DI-GAN:基于深度学习的动态形变多模光纤透反射光控制 1 论文核心概念 本文提出了一种名为 DI-GAN(Deep Imaging Generative Adversarial Network) 的持续深度学习框架,用于动态形变多模光纤(MMF) 的光场控制。该框架能够同时利用透射和反射信息,实现对光纤末端光场的实…

【深度学习新浪潮】具身智能中使用到的世界模型是什么?

在具身智能中,世界模型(World Model) 是智能体对物理环境的内在“认知地图”,它通过学习环境的动态规律(如物体运动、物理交互、因果关系等),实现对未来状态的预测、对过去状态的反推,以及对未观测状态的补全。其核心价值在于:让智能体无需频繁与真实环境交互,就能在…

Qt_UI界面的设计

一、设置UI窗口大小二、接收框只读三、下拉选项双击添加选项1是添加&#xff0c;2是调整顺序四、标签字体居中字体大小五、发送框六、按钮七、透明框&#xff08;可以放标签或图片啥的&#xff09;设置最小宽度八、水平布局九、垂直布局十、弹簧&#xff08;方便给水平垂直布局…

FTP文件传输服务

一、FTP协议、服务器FTP&#xff1a;文件传输协议&#xff08;用于网络文件双向传输的应用层协议&#xff09;特点&#xff1a;最广泛、最底层、较简单&#xff0c;但是明文传输&#xff1b;适用于较大文件的传输1.常见客户端、服务器客户端&#xff1a;WINSCP or filezilla&am…

Nginx运维之路(Docker多段构建新版本并增加第三方模块)

喜大普奔&#xff0c;前两天发现Nginx竟然自带支持了ACME功能&#xff0c;让我很想测试一下&#xff0c;但是发现手头没有资源让我测试&#xff0c;忽然我想到可以用docker来构建nginx然后测试ACME功能&#xff0c;在这个过程中发现原来官方Nginx镜像并没有集成ACME插件&#x…

DrissionPage 优化天猫店铺商品爬虫:现代化网页抓取技术详解

概述在网络数据采集领域&#xff0c;传统的爬虫方法通常面临反爬机制、动态内容加载和效率低下等挑战。本文将以天猫店铺商品爬虫为例&#xff0c;详细介绍如何从传统的 Requests 库迁移到更现代化的 DrissionPage 解决方案&#xff0c;实现更高效、稳定的数据采集。----------…

pytest并发测试,资源问题导致用例失败解决办法

遇见的问题&#xff1a; 测试用例使用thrift资源和redis资源&#xff0c;单独运行case没有问题&#xff0c;但是使用并发pytest-xdist&#xff08;-n 10 和 --distloadscope&#xff09;运行失败原因&#xff1a; 测试用例间存在共享资源竞争&#xff08;如 Redis、Thrift 连接…

C 盘又满了?6 个「零风险清理法」+5 款神器,让电脑瞬间多出 100GB 空间

你是否遇到过这样的场景&#xff1a;正在赶工写报告&#xff0c;突然弹出「C 盘存储空间不足」的警告&#xff1b;想安装新软件&#xff0c;却因为 C 盘爆红而反复失败&#xff1b;甚至电脑越来越卡&#xff0c;开机要等 5 分钟&#xff0c;打开文件夹都要转圈…… 作为系统盘…

Android 项目:画图白板APP开发(四)——笔锋(单 Path)

上一章讲解了如何通过多个 Path 叠加形成笔锋效果&#xff0c;还有另外的方式实现笔锋&#xff0c;并且只需要一条Path就可以了。在讲解具体方案之前&#xff0c;我们需要了解一个有意思的工具 PathMeasure &#xff0c;这是一个非常强大且实用的工具&#xff0c;常用于高级动画…

从C++开始的编程生活(7)——取地址运算符重载、类型转换、static成员和友元

前言 本系列文章承接C语言的学习&#xff0c;需要有C语言的基础才能学会哦~ 第7篇主要讲的是有关于C的取地址运算符重载、类型转换、static成员和友元。 C才起步&#xff0c;都很简单 目录 前言 取地址运算符重载 const成员函数 基本语法 特点 取地址运算符重载 类型转换…

SQL 入门指南:排序与分页查询(ORDER BY 多字段排序、LIMIT 分页实战)

在 SQL 查询中&#xff0c;我们常需要 “按报名时间先后看活动名单”“只看第 2 页的活动报名数据”—— 这些需求靠基础查询无法实现&#xff0c;而ORDER BY&#xff08;排序&#xff09; 和LIMIT&#xff08;分页&#xff09; 就是解决这类问题的核心工具。今天我们用 “校园…

jodconverter将word转pdf底层libreoffice的问题

近期项目中使用了word转pdf的功能&#xff0c;其中借助了远程服务的jodconverter来处理。 <dependency><groupId>org.jodconverter</groupId><artifactId>jodconverter-remote</artifactId><version>4.4.2</version> </dependen…