全面解析缓存应用经典问题
1、前言
随着互联网从简单的单向浏览请求,发展为基于用户个性信息的定制化以及社交化的请求,这要求产品需要做到以用户和关系为基础,对海量数据进行分析和计算。对于后端服务来说,意味着用户的每次请求都需要查询用户的个人信息和大量的关系信息,此外大部分场景还需要对上述信息进行聚合、过滤、排序,最终才能返回给用户。
CPU 是信息处理、程序运行的最终执行单元,如果它的世界也有 “秒” 的概念,假设它的时钟跳一下为一秒,那么在 CPU(CPU 的一个核心)眼中的时间概念是什么样的呢?
可见 I/O 的速度与 CPU 和内存相比是要差几个数量级的,如果数据全部从数据库获取,一次请求涉及多次数据库操作会大大增加响应时间,无法提供好的用户体验。
对于大型高并发场景下的 Web 应用,缓存更为重要,更高的缓存命中率就意味着更好的性能。缓存系统的引入,是提升系统响应时延、提升用户体验的唯一途径,良好的缓存架构设计也是高并发系统的基石。
缓存的思想基于以下几点:
-
时间局限性原理 程序有在一段时间内多次访问同一个数据块的倾向。例如一个热门的商品或者一个热门的新闻会被数以百万甚至千万的更多用户查看。通过缓存,可以高效地重用之前检索或计算的数据。
-
以空间换取时间 对于大部分系统,全量数据通常存储在 MySQL 或者 Hbase,但是它们的访问效率太低。所以会开辟一个高速的访问空间来加速访问过程,例如 Redis 读的速度是 110000 次 /s,写的速度是 81000 次 /s 。
-
性能和成本的 Tradeoff 高速的访问空间带来的是成本的提升,在系统设计时要兼顾性能和成本。例如,在相同成本的情况下,SSD 硬盘容量会比内存大 10~30 倍以上,但读写延迟却高 50~100 倍。
引入缓存会给系统带来以下优势:
-
提升请求性能
-
降低网络拥塞
-
减轻服务负载
-
增强可扩展性
同样的,引入缓存也会带来以下劣势:
-
毫无疑问会增加系统的复杂性,开发复杂性和运维复杂性成倍提升。
-
高速的访问空间会比数据库存储的成本高。
-
由于一份数据同时存在缓存和数据库中,甚至缓存内部也会有多个数据副本,多份数据就会存在数据双写的不一致问题,同时缓存体系本身也会存在可用性问题和分区的问题。
在缓存系统的设计架构中,还有很多坑,很多的明枪暗箭,如果设计不当会导致很多严重的后果。设计不当,轻则请求变慢、性能降低,重则会数据不一致、系统可用性降低,甚至会导致缓存雪崩,整个系统无法对外提供服务。
2、缓存的主要存储模式
三种模式各有优劣,适用于不同的业务场景,不存在最佳模式。
● Cache Aside(旁路缓存)
写: 更新 db 时,删除缓存,当下次读取数据库时,驱动缓存的更新。
读: 读的时候先读缓存,缓存未命中,那么就读数据库,并且将数据回种到缓存,同时返回相应结果
特点:懒加载思想,以数据库中的数据为准。在稍微复杂点的缓存场景,缓存都不简单是数据库中直接取出来的,可能还需要从其他表查询一些数据,然后进行一些复杂的运算,才能最终计算出值。这种存储模式适合于对数据一致性要求比较高的业务,或者是缓存数据更新比较复杂、代价比较高的业务。例如:一个缓存涉及多个表的多个字段,在 1 分钟内被修改了 100 次,但是这个缓存在 1 分钟内就被读取了 1 次。如果使用这种存储模式只删除缓存的话,那么 1 分钟内,这个缓存不过就重新计算一次而已,开销大幅度降低。
● Read/Write Through(读写穿透)
写: 缓存存在,更新数据库,缓存不存在,同时更新缓存和数据库
读: 缓存未命中,由缓存服务加载数据并且写入缓存
特点:
读写穿透对热数据友好,特别适合有冷热数据区分的场合。
1)简化应用程序代码
在缓存方法中,应用程序代码仍然很复杂,并且直接依赖于数据库,如果多个应用程序处理相同的数据,甚至会出现代码重复。读写穿透模式将一些数据访问代码从应用程序转移到缓存层,这极大地简化了应用程序并更清晰地抽象了数据库操作。
2)具有更好的读取可伸缩性
在多数情况下,缓存数据过期以后,多个并行用户线程最终会打到数据库,再加上数以百万计的缓存项和数千个并行用户请求,数据库上的负载会显著增加。读写穿透可以保证应用程序永远不会为这些缓存项访问数据库,这也可以让数据库负载保持在最小值。
3)具有更好的写性能
读写穿透模式可以让应用程序快速更新缓存并返回,之后它让缓存服务在后台更新数据库。当数据库写操作的执行速度不如缓存更新的速度快时,还可以指定限流机制,将数据库写操作安排在非高峰时间进行,减轻数据库的压力。
4)过期时自动刷新缓存
读写穿透模式允许缓存在过期时自动从数据库重新加载对象。这意味着应用程序不必在高峰时间访问数据库,因为最新数据总是在缓存中。
● Write Behind Caching(异步缓存写入)
写:只更新缓存,缓存服务异步更新数据库。
读:缓存未命中由封装好的缓存服务加载数据并且写入缓存。
特点:写性能最高,定期异步刷新数据库数据,数据丢失的概率大,适合写频率高,并且写操作需要合并的场景。使用异步缓存写入模式,数据的读取和更新通过缓存进行,与读写穿透模式不同,更新的数据并不会立即传到数据库。相反,在缓存服务中一旦进行更新操作,缓存服务就会跟踪脏记录列表,并定期将当前的脏记录集刷新到数据库中。作为额外的性能改善,缓存服务会合并这些脏记录,合并意味着如果相同的记录被更新,或者在缓冲区内被多次标记为脏数据,则只保证最后一次更新。对于那些值更新非常频繁,例如金融市场中的股票价格等场景,这种方式能够很大程度上改善性能。如果股票价格每秒钟变化 100 次,则意味着在 30 秒内会发生 30 x 100 次更新,合并将其减少至只有一次。
3、缓存 7 大经典问题
问题的常用解决方案
1 缓存集中失效
缓存集中失效大多数情况出现在高并发的时候,如果大量的缓存数据集中在一个时间段失效,查询请求会打到数据库,数据库压力凸显。比如同一批火车票、飞机票,当可以售卖时,系统会一次性加载到缓存,并且过期时间设置为预先配置的固定时间,那过期时间到期后,系统就会因为热点数据的集中没有命中而出现性能变慢的情况。
解决方案:
-
使用基准时间 + 随机时间,降低过期时间的重复率,避免集体失效。即相同业务数据设置缓存失效时间时,在原来设置的失效时间基础上,再加上一个随机值,让数据分散过期,同时对数据库的请求也会分散开,避免瞬时全部过期对数据库造成过大压力。
2 缓存穿透
缓存穿透是指一些异常访问,每次都去查询压根儿就不存在的 key,导致每次请求都会打到数据库上去。例如查询不存在的用户,查询不存在的商品 id。如果是用户偶尔错误输入,问题不大。但如果是一些特殊用户,控制一批肉鸡,持续的访问缓存不存在的 key,会严重影响系统的性能,影响正常用户的访问,甚至可能会让数据库直接宕机。我们在设计系统时,通常只考虑正常的访问请求,所以这种情况往往容易被忽略。
解决方案:
-
第一种方案就是,查询到不存在的数据时,首次查询数据库,即便数据库没有数据,仍然回种这个 key 到缓存,并使用一个特殊约定的 value 表示这个 key 的值为空。后面再次出现对这个 key 的请求时,直接返回 null。为了健壮性,设置空缓存 key 时,一定要设置过期时间,以防止之后该 key 被写入了数据。
-
第二种方案是,构建一个 BloomFilter 缓存过滤器,记录全量数据,这样访问数据时,可以直接通过 BloomFilter 判断这个 key 是否存在,如果不存在直接返回即可,压根儿不需要查询缓存或数据库。比如,可以使用基于数据库增量日志解析框架(阿里的 canal),通过消费增量数据写入到 BloomFilter 过滤器。BloomFilter 的所有操作也是在内存里实现,性能很高,要达到 1% 的误判率,平均单条记录占用 1.2 字节即可。同时需要注意的是 BloomFilter 只有新增没有删除操作,对于已经删除的 key 可以配合上述缓存空值解决方案一起使用。Redis 提供了自定义参数的布隆顾虑器,可以使用 bf.reserve 进行创建,需要设置参数 error_rate(错误率)和 innitial_size。error_rate 越低需要的空间越大,innitial_size 表示预计放入的元素数量,当实际数量超过这个值以后,误判率会上升。
3 缓存雪崩
缓存雪崩是缓存机器因为某种原因全部或者部分宕机,导致大量的数据落到数据库,最终把数据库打死。例如某个服务,恰好在请求高峰期间缓存服务宕机,本来打到缓存的请求,这是时候全部打到数据库,数据库扛不住在报警以后也会宕机,重启数据库以后,新的请求会再次把数据库打死。
解决方案:
-
事前:缓存采用高可用架构设计,redis 使用集群部署方式。对重要业务数据的数据库访问添加开关,当发现数据库出现阻塞、响应慢超过阈值的时候,关闭开关,将一部分或者全都的数据库请求执行 failfast 操作。
-
事中:引入多级缓存架构,增加缓存副本,比如新增本地 ehcache 缓存。引入限流降级组件,对缓存进行实时监控和实时报警。通过机器替换、服务替换进行及时恢复;也可以通过各种自动故障转移策略,自动关闭异常接口、停止边缘服务、停止部分非核心功能措施,确保在极端场景下,核心功能的正常运行。
-
事后:redis 持久化,支持同时开启两种持久化方式,我们可以综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择;用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。同时把 RDB 数据备份到远端的云服务,如果服务器内存和磁盘的数据同时丢失,依然可以从远端拉取数据做灾备恢复操作。
4 缓存数据不一致
同一份数据,既在缓存里又在数据库里,肯定会出现数据库与缓存中的数据不一致现象。如果引入多级缓存架构,缓存会存在多个副本,多个副本之间也会出现缓存不一致现象。缓存机器的带宽被打满,或者机房网络出现波动时,缓存更新失败,新数据没有写入缓存,就会导致缓存和 DB 的数据不一致。缓存 rehash 时,某个缓存机器反复异常,多次上下线,更新请求多次 rehash。这样,一份数据存在多个节点,且每次 rehash 只更新某个节点,导致一些缓存节点产生脏数据。再比如,数据发生了变更,先删除了缓存,然后要去修改数据库,此时还没修改。一个请求过来,去读缓存,发现缓存空了,去查询数据库,查到了修改前的旧数据,放到了缓存中。随后数据变更的程序完成了数据库的修改,数据库和缓存中的数据不一样了。
解决方案:
-
设置 key 的过期时间尽量短,让缓存更早的过期,从 db 加载新数据,这样无法保证数据的强一致性,但是可以保证最终一致性。
cache 更新失败以后引入重试机制,比如连续重试失败以后,可以将操作写入重试队列,当缓存服务可用时,将这些 key 从缓存中删除,当这些 key 被重新查询时,重新从数据库回种。
延时双删除策略,首先删除缓存中的数据,在写数据库,休眠一秒以后(具体时间需要根据具体业务逻辑的耗时进行调整)再次删除缓存。这样可以将一秒内造成的所有脏数据再次删除。
缓存最终一致性,使客户端数据与缓存解耦,应用直接写数据到数据库中。数据库更新 binlog 日志,利用 Canal 中间件读取 binlog 日志。Canal 借助于限流组件按频率将数据发到 MQ 中,应用监控 MQ 通道,将 MQ 的数据更新到 Redis 缓存中。
更新数据的时候,根据数据的唯一标识,将操作路由之后,发送到一个 jvm 内部队列中。读取数据的时候,如果发现数据不在缓存中,那么将重新执行 “读取数据 + 更新缓存” 的操作,根据唯一标识路由之后,也发送到同一个 jvm 内部队列中。该方案对于读请求进行了非常轻度的异步化,使用一定要注意读超时的问题,每个读请求必须在超时时间范围内返回。因此需要根据自己的业务情况进行测试,可能需要部署多个服务,每个服务分摊一些数据的更新操作。如果一个内存队列里居然会挤压 100 个业务数据的修改操作,每个操作操作要耗费 10ms 去完成,那么最后一个读请求,可能等待 10 * 100 = 1000ms = 1s 后,才能得到数据,这个时候就导致读请求的长时阻塞。
5 竞争并发
当系统的线上流量特别大的时候,缓存中会出现数据并发竞争的现象。在高并发的场景下,如果缓存数据正好过期,各个并发请求之间又没有任何协调动作,这样并发请求就会打到数据库,对数据造成较大的压力,严重的可能会导致缓存 “雪崩”。另外高并发竞争也会导致数据不一致问题,例如多个 redis 客户端同时 set 同一个 key 时,key 最开始的值是 1,本来按顺序修改为 2,3,4,最后是 4,但是顺序变成了 4,3,2,最后变成了 2。
解决方案:
分布式锁 + 时间戳
可以基于 redis 或者 zookeeper 实现一个分布式锁,当一个 key 被高并发访问时,让请求去抢锁。也可以引入消息中间件,把 Redis.set 操作放在消息队列中。总之,将并行读写改成串行读写的方式,从而来避免资源竞争。对于 key 的操作的顺序性问题,可以通过设置一个时间戳来解决。大部分场景下,要写入缓存的数据都是从数据库中查询出来的。在数据写入数据库时,可以维护一个时间戳字段,这样数据被查询出来时都会带一个时间戳。写缓存的时候,可以判断一下当前数据的时间戳是否比缓存里的数据的时间戳要新,这样就避免了旧数据对新数据的覆盖。
6 热点 Key 问题
对于大多数互联网系统,数据是分冷热的,访问频率高的 key 被称为热 key,比如热点新闻、热点的评论。而在突发事件发生时,瞬间会有大量用户去访问这个突发热点信息,这个突发热点信息所在的缓存节点由于超大流量而达到理网卡、带宽、CPU 的极限,从而导致缓存访问变慢、卡顿、甚至宕机。接下来数据请求到数据库,最终导致整个服务不可用。比如微博中数十万、数百万的用户同时去吃一个新瓜,秒杀、双 11、618 、春节等线上促销活动,明星结婚、离婚、出轨这种特殊突发事件。
解决方案:
要解决这种极热 key 的问题,首先要找出这些 热 key 。对于重要节假日、线上促销活动、凭借经验可以提前评估出可能的热 key 来。而对于突发事件,无法提前评估,可以通过 Spark 或者 Flink,进行流式计算,及时发现新发布的热点 key。而对于之前已发出的事情,逐步发酵成为热 key 的,则可以通过 Hadoop 进行离线跑批计算,找出最近历史数据中的高频热 key。还可以通过客户端进行统计或者上报。找到热 key 后,就有很多解决办法了。首先可以将这些热 key 进行分散处理。redis cluster 有固定的 16384 个 hash slot,对每个 key 计算 CRC16 值,然后对 16384 取模,可以获取 key 对应的 hash slot。比如一个热 key 名字叫 hotkey,可以被分散为 hotkey#1、hotkey#2、hotkey#3,……hotkey#n,这 n 个 key 就会分散存在多个缓存节点,然后 client 端请求时,随机访问其中某个后缀的热 key,这样就可以把热 key 的请求打散。
其次,也可以 key 的名字不变,对缓存提前进行多副本 + 多级结合的缓存架构设计。比如利用 ehcache,或者一个 HashMap 都可以。在你发现热 key 以后,把热 key 加载到系统的 JVM 中,之后针对热 key 的请求,可以直接从 jvm 中获取数据。再次,如果热 key 较多,还可以通过监控体系对缓存的 SLA 实时监控,通过快速扩容来减少热 key 的冲击。
7 大 Key 问题
有些时候开发人员设计不合理,在缓存中会形成特别大的对象,这些大对象会导致数据迁移卡顿,另外在内存分配方面,如果一个 key 特别大,当需要扩容时,会一次性申请更大的一块内存,这也会导致卡顿。如果大对象被删除,内存会被一次性回收,卡顿现象会再次发生。在平时的业务开发中,要尽量避免大 key 的产生。如果发现系统的缓存大起大落,极有可能是大 key 引起的,这就需要开发人员定位出大 key 的来源,然后进行相关的业务代码重构。Redis 官方已经提供了相关的指令进行大 key 的扫描,可以直接使用。
解决方案:
-
如果数据存在 Redis 中,比如业务数据存 set 格式,大 key 对应的 set 结构有几千几万个元素,这种写入 Redis 时会消耗很长的时间,导致 Redis 卡顿。此时,可以扩展新的数据结构,同时让 client 在这些大 key 写缓存之前,进行序列化构建,然后通过 restore 一次性写入。
-
将大 key 分拆为多个 key,尽量减少大 key 的存在。同时由于大 key 一旦穿透到 DB,加载耗时很大,所以可以对这些大 key 进行特殊照顾,比如设置较长的过期时间,比如缓存内部在淘汰 key 时,同等条件下,尽量不淘汰这些大 key。
相关文章:
全面解析缓存应用经典问题
1、前言 随着互联网从简单的单向浏览请求,发展为基于用户个性信息的定制化以及社交化的请求,这要求产品需要做到以用户和关系为基础,对海量数据进行分析和计算。对于后端服务来说,意味着用户的每次请求都需要查询用户的个人信息和…...

Java版本企业电子招采系统源码——信息数智化招采系统
信息数智化招采系统 服务框架:Spring Cloud、Spring Boot2、Mybatis、OAuth2、Security 前端架构:VUE、Uniapp、Layui、Bootstrap、H5、CSS3 涉及技术:Eureka、Config、Zuul、OAuth2、Security、OSS、Turbine、Zipkin、Feign、Monitor、Stre…...

Rust每日一练(Leetday0005) 罗马数字、公共前缀、三数之和
目录 13. 罗马数字转整数 Roman to Integer 🌟 14. 最长公共前缀 Longest Common Prefix 🌟 15. 三数之和 3Sum 🌟🌟 🌟 每日一练刷题专栏 🌟 Rust每日一练 专栏 Golang每日一练 专栏 Python每日…...
【告别校园,迎接未来】
作为一个曾经的大学生,我的四年大学时光充满了起伏和挑战。回顾这段时光,我深刻认识到了自己的不足,同时也感悟了一些珍贵的人生经验和收获。 我是一个比较内向的人,进入大学后感觉有些孤独,难以适应新的环境和生活方…...

SaaS系统用户权限设计
SaaS系统用户权限设计 学习目标: 理解RBAC模型的基本概念及设计思路 了解SAAS-HRM中权限控制的需求及表结构分析完成组织机构的基本CRUD操作 完成用户管理的基本CRUD操作完成角色管理的基本CRUD操作 组织机构管理 需求分析 需求分析 实现企业组织结构管理࿰…...

我们为什么还要学习Altium Designer?
Altium Designe(简称“AD”)是电子设计领域中备受推崇的软件工具之一,拥有强大的功能和灵活的设计环境,也是要用最广泛的EDA工具之一,为电子工程师提供了无限可能,但很多工程师学完AD基本操作就转投其他EDA…...

Q1业绩整体回暖,影视行业找到增长新路径
凛冬已过,影视行业恢复了生机。 数据显示,今年一季度,影视院线板块全部上市公司分别实现营收、归母净利111.86亿元、10.15亿元,同比增幅为1.44%和53.76%。在经济复苏的背景下,影视行业实现了扭亏为盈和跨越式增长。 …...

Zabbix
概述 作为一个运维,需要会使用监控系统查看服务器系统性能、应用服务状态和网站流量指标等,利用监控系统的数据去了解网站上线发布的结果和健康状态。 利用一个优秀的监控软件,我们可以: ●通过一个友好的界面进行浏览整个网站所有的服务器…...

OpenHarmony支持HDMI接口声卡适配说明
高清多媒体接口(High Definition Multimedia Interface,HDMI )是一种全数字化视频和声音发送接口,可以发送未压缩的音频及视频信号。HDMI可用于机顶盒、DVD播放机、个人计算机、电视、游戏主机、综合扩大机、数字音响与电视机等设…...
AtCoder Beginner Contest 300G - P-smooth number解题报告
AtCoder Beginner Contest 300G - P-smooth number解题报告 1 题目链接 传送门 2 题目大意 题目:P-光滑数的数量 题目大意: 在 1 1 1 到 n n n 中,有多少个数的所有质因数均不超过 p ( p ≤ 100 ) p\ (p\leq100) p (p≤100)。 3 解…...

数据分析与预处理常用的图和代码
1.训练集和测试集统计数据描述之间的差异作图: def diff_color(x):color red if x<0 else (green if x > 0 else black)return fcolor: {color}(train.describe() - test.describe())[features].T.iloc[:,1:].style\.bar(subset[mean, std], alignmid, colo…...

Http与Https 比较
目录 1、HTTP(HyperText Transfer Protocol:超文本传输协议) 2、HTTPS(Hypertext Transfer Protocol Secure:超文本传输安全协议) 3、HTTP 与 HTTPS 区别 4、HTTPS 的工作原理 1、HTTP(HyperTex…...
02 面向对象( 继承,抽象类)
强调:一定用自己的话总结,避免抄文档,否则视为作业未完成。 this关键字的作用 为了解决成员变量和局部变量所存在的二义性,适用于有参构造时使用 示例 private String name;private int age;public person(){}public person(String name,i…...
[C++]22种设计模式的C++实现大纲
前言 最近看遍全网,准备整理一套较好上手的设计模式文章,以便后续复习到处翻找,在此记录一下,如有侵权可以联系删除, 每天更新一篇,直到更新完 前置知识 UML类图与面向对象编程C UML类图详解软件设计原则与SOLID原则…...

用Powerpoint (PPT)制作并导出矢量图、高分辨率图
论文写作时经常需要导入矢量图,正规军都是用AI或者Inkscape作图,但是PPT更加适合小白用户,或者一些简单的构图需求使用PPT更加便捷,而且不得不承认PPT的某些功能是真的香,例如:简单的对齐、文字插入和格式修…...

小白量化《穿云箭集群量化》(9)用指标公式实现miniQMT全自动交易
小白量化《穿云箭集群量化》(9)用指标公式实现miniQMT全自动交易 在穿云箭量化平台中,支持3中公式源码运行模式,还支持在Python策略中使用仿指标公式源码运行,编写策略。 我们先看如何使用指标公式源码。 #编程_直接使…...
java Class类详解
Class类简介 在 java 世界里,一切皆对象。从某种意义上来说,java 有两种对象:实例对象和 Class 对象。每个类的运行时的类型信息就是用 Class 对象表示的,它包含了与类有关的信息,实例对象就是通过 Class 对象来创建的…...

DMGI:Unsupervised Attributed Multiplex Network Embedding
[1911.06750] Unsupervised Attributed Multiplex Network Embedding (arxiv.org) 目录 Abstract 1 Introduction 2 DGI 3 Deep Multiplex Graph Infomax: DMGI 特定关系类型的节点嵌入 Joint Modeling and Consensus Regularization Extension to Semi-Supervised Lea…...

C++基本介绍
文章目录 🥭1.C基本介绍🧂1.1 C是什么🧂1.2 C发展史 🍒2. C的优势🥔2.1 语言的使用广泛度🥔2.2 C的应用领域 🫒3. C学习计划 🥭1.C基本介绍 🧂1.1 C是什么 C是一种通用…...

如何理解工业互联网与智能制造,怎么共建智慧工厂?
第六届数字中国建设峰会26日在福州开幕,在这个数字化新技术的变革风口,企业如何把握机遇,借工业互联网和智能制造实现智慧工厂建设? 探讨三个问题: 什么是工业互联网、智能制造、智慧工厂;它们三者之间的…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...

全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...