从系统崩溃到绝地反击:一次微服务存储危机的救赎

怎么会这样?”凌晨两点,我盯着监控面板,心跳加速。用户请求像洪水猛兽般涌来,每一秒都在增加,而服务器却毫无回应。电梯般的访问量突如其来,仿佛一夜之间,我们的微服务系统被压入了崩溃的边缘。那一刻,我以为我们掌控了一切,直到现实狠狠地给了我一记耳光——NFS的性能瓶颈,让整个系统陷入了泥潭。

一、崩溃的前夜

那时,我们的架构看似无懈可击:多个微服务共享一个NFS存储,用来管理每天生成的数百万个小文件。起初,这套方案运行得井然有序,用户增长也在可控范围内。微服务之间通过挂载的NFS目录轻松共享文件,数据读写仿佛流水线般高效。然而,随着流量的飙升,隐藏在系统背后的问题开始浮现。

性能变慢,我在日志中看到了NFS服务器的响应时间逐渐增长,监控图表上的延迟曲线不断攀升。最可怕的是锁竞争的加剧,多个微服务在高并发下试图同时访问同一个文件,NFS的锁机制让我们始料未及地陷入了性能瓶颈。服务器资源被迅速消耗殆尽,NFS几乎被压垮,无法再承受突如其来的高负荷。

二、绝望的修复尝试

那天深夜,系统彻底崩溃了。主服务器的CPU利用率飙升至100%,内存溢出警报频频响起,用户的投诉电话如同潮水般涌来:“数据无法访问”、“数据加载缓慢”,每一个声音都刺痛我的耳膜。我紧急组织团队,试图通过重启服务来恢复系统运行,但NFS的锁机制问题让恢复变得异常困难。每次重启,系统都会因为锁的不释放而卡住,恢复过程漫长而痛苦。那种无力感,仿佛将我整个灵魂都吞噬了。

三、灵光一现的对象存储

焦虑中,我不得不再次审视我们的技术选择。为什么最初看似完美的NFS架构会在高并发下崩溃?反思中,脑海中反复回荡着一个问题:“有没有更好的解决方案?

就在几乎绝望时,我接触到了对象存储。对象存储不同于传统的文件系统,它采用扁平化的命名空间,通过唯一的标识符管理对象,而不是复杂的层级目录。这意味着数据可以更容易地进行水平扩展,通过增加存储节点来线性提升存储容量和处理能力。正是这项特性,让我看到了突破NFS瓶颈的希望。

我深入研究了MinIO,一种高性能的开源对象存储解决方案。MinIO的分布式架构不仅消除了单点故障的风险,还通过纠删码(Erasure Coding)技术保障数据的高可用性和持久性。纠删码将数据分割成多个块并生成冗余块,即便有部分节点失效,数据依然可以通过剩余的块来恢复。我意识到,这正是我们系统所需要的容错和扩展能力。

对象存储的原理

对象存储(Object Storage)是一种用于存储海量非结构化数据的存储架构。与传统的块存储和文件存储不同,对象存储以对象(object)为基本单元,每个对象包含数据本身、元数据以及一个唯一标识符。这种结构使得对象存储具备高度的可扩展性、灵活性和易管理性,特别适合用于存储图片、视频、备份数据等大量小文件的场景。

1.1 元数据与数据

在对象存储中,每个对象由两部分组成:

  • 数据:即存储的实际内容,如图片、文档等。
  • 元数据:描述数据的附加信息,如文件名、大小、类型、创建时间等。这些元数据使得数据的管理和检索更加高效。
  • 唯一标识符(Object ID):用于唯一标识和访问对象的键,通常是一个全局唯一的字符串。

元数据的灵活性允许用户根据需求自定义信息,使得对象存储在数据分类和检索上表现出色。

1.2 数据如何分布

对象存储系统通过分布式架构将数据分布在多个存储节点上。这种分布方式不仅提升了存储容量,还增强了系统的容错性。数据通常以对象的形式被切分并分布到不同的节点,确保在某个节点故障时,数据仍然可以从其他节点恢复。

对象存储采用扁平的命名空间结构,没有传统文件系统中的层级目录。这种设计使得对象存储在横向扩展时更加简便和高效。用户通过唯一标识符直接访问对象,无需遍历目录结构。

	传统文件系统(层级结构):
	====================
	root/
	├── documents/
	│   ├── report.pdf
	│   └── memo.doc
	├── images/
	│   ├── photo1.jpg
	│   └── photo2.png
	└── music/
	    ├── song1.mp3
	    └── song2.mp3
	
	对象存储(扁平结构):
	================
	[Object Storage]
	┌──────────────────────────────────────┐
	│                                      │
	│  ● 7b2f...a8e1 (report.pdf)         │
	│  ● 9c4d...f2b3 (memo.doc)           │
	│  ● 3e8a...d9c5 (photo1.jpg)         │
	│  ● 5f1b...c7d4 (photo2.png)         │
	│  ● 2d6e...b4a9 (song1.mp3)          │
	│  ● 8h3k...m5n6 (song2.mp3)          │
	│                                      │
	└──────────────────────────────────────┘

对象存储系统通常具备高度的可扩展性,能够通过增加存储节点来线性扩展存储容量和处理能力。此外,通过数据冗余(如复制或纠删码)技术,确保数据的高可用性和持久性,即使部分节点发生故障,数据仍然可以被恢复和访问。

在 MinIO 中,元数据与对象数据是紧密绑定的。当一个对象被上传到 MinIO 集群时,元数据会作为对象的一部分进行存储,并与数据一起通过纠删码(Erasure Coding)被分割成多个数据块,分布存储在不同的节点上。这样,每个数据块不仅包含对象的部分数据,还包含部分元数据,从而实现元数据的冗余存储和高可用性。

关键技术解析

2.1 纠删码与冗余备份

为了保证数据的可靠性和可用性,对象存储采用了纠删码(Erasure Coding)和冗余备份技术。纠删码将数据分割成多个碎片,并通过一定的算法生成校验片段。当部分碎片丢失时,依靠校验片段可以恢复完整的数据。这种方法相比简单的冗余备份,节省了存储空间,同时提供了同样甚至更高的数据保护能力。

Minio使用的是Reed-Solomon编码,让我用简单方式解释它的基本公式:

假设我们有4个数据块(Data)和2个校验块(Parity),用D1-D4表示数据块,P1-P2表示校验块:

基本公式为:

P1 = D1 + D2 + D3 + D4
P2 = D1 + 2D2 + 3D3 + 4D4

这是一个极度简化的版本。实际的Minio中:

  1. 使用的是伽罗华域(GF)上的运算,不是普通的加法
  2. 数据被分成多个块(shards)
  3. 默认配置通常是N+M模式:
    • N个原始数据块
    • M个校验块
    • 常用配置是4+2(4个数据块,2个校验块)

让我们从方程的角度来理解这个问题:

假设我们有4个数据块(D1-D4)和2个校验块(P1,P2),总共形成两个方程:

P1 = D1 + D2 + D3 + D4       (方程1)
P2 = D1 + 2D2 + 3D3 + 4D4    (方程2)

现在假设我们丢失了两个数据块,比如D1和D2:

  1. 我们认识的值是:D3、D4、P1、P2
  2. 未知数是:D1、D2
  3. 有两个方程:
    • D1 + D2 = P1 - D3 - D4
    • D1 + 2D2 = P2 - 3D3 - 4D4

这是一个有两个未知数的二元一次方程组,可以解出唯一解。

但如果丢失三个数据块,比如D1、D2、D3:

  1. 我们认识的值是:D4、P1、P2
  2. 未知数是:D1、D2、D3
  3. 还是只有两个方程:
    • D1 + D2 + D3 = P1 - D4
    • D1 + 2D2 + 3D3 = P2 - 4D4

这就变成了三个未知数,只有两个方程,方程组无法求出唯一解。

这就是为什么2个纠删码只能容忍两个失效 - 因为:

  • 每个校验块提供一个方程
  • 要解出N个未知数,至少需要N个方程
  • 有2个校验块就只有2个方程,最多只能解出2个未知数

如果需要容忍更多失效,就需要更多的校验块,也就是更多的方程。

  1. N个方程是独立的且具有解的情况下, N个方程可以解出N个未知数,也就是容忍N个失效
  2. 纠删码:在 k个原始数据的基础上,通过生成 r个冗余数据,构建n=k+r 个数据块,容忍最多 r个失效。
2.2 对象的不可变性与多版本控制

在对象存储中,多版本控制(Versioning)允许对同一个对象的不同版本进行存储。这对于需要记录历史数据变更、数据回滚或保护数据免受意外删除和覆盖非常重要。通过版本控制,用户可以轻松访问和恢复之前的任何一个版本,确保数据的完整性和安全性。

对象的不可变性(Immutability)

在 MinIO 中,对象一旦被写入后即为不可变。这意味着无法在原地修改对象的部分内容。任何需要修改对象的操作都必须通过以下步骤完成:

  1. 上传新版本:将修改后的整个对象作为一个新的版本上传到存储系统。
  2. 删除旧版本(可选):根据需求,可以删除旧的对象版本,或者保留以支持版本回滚和审计。

这种设计简化了并发控制和数据一致性管理,因为每个写操作都是对一个新的对象版本的独立操作,避免了部分更新带来的不一致性问题。

多版本控制(Versioning)

MinIO 支持 对象版本控制(Object Versioning),这允许存储同一个对象的多个版本。版本控制在并发写入场景下具有以下优势:

  • 并发写入:多个微服务或客户端可以同时对同一对象进行写入操作,每个操作都会创建一个独立的对象版本。
  • 冲突解决:通过版本控制,系统不会覆盖同一个对象的不同写入请求,而是分别记录每个版本。用户可以根据需要选择读取特定版本的数据。
  • 数据恢复:版本控制提供了数据回滚的能力,可以在需要时恢复到某个特定版本,增强了数据的可靠性和安全性。
2.3 数据一致性原理

在多客户端环境下,对象存储需要处理并发的读写操作,确保数据的一致性。

写操作(写入新文件)

  • 在 MinIO 中,每次写操作都是对整个对象的覆盖,意味着新的写入会生成一个新的对象版本(如果启用了版本控制)。
  • 如果没有启用版本控制,新的写入会直接覆盖同名的旧对象,旧对象的数据会被替换为新的数据。
  • 写入操作在完成之前,对象的数据不可用,MinIO 不会让部分写入的对象被读取。

读操作(读取旧文件)

  • 读操作通常是强一致性的,这意味着在写操作尚未完全完成的情况下,读取的仍然是旧文件完整的数据。
  • 如果有写操作正在进行,读操作不会读取部分写入的数据,而是读取上一次成功写入的完整对象。
  • 当写操作完成后,新的写入才能对读操作可见。

MinIO 遵循强一致性模型,这意味着:

  • 当一个对象正在被写入时,读操作不会看到部分写入的对象,也不会返回不完整的数据。
  • 当写入操作完成并成功持久化后,读操作将立即看到新写入的数据。
  • 在写入完成之前,所有的读操作将继续返回旧的对象数据。这种行为保证了数据的一致性,并避免了脏读的情况。

因此,对于并发读写的场景,读操作的可见性由写操作的完成状态决定:

  • 写入进行中:读操作返回旧的数据。
  • 写入完成后:读操作返回新写入的数据。
2.4 并发写入冲突的处理机制

在 MinIO 中,处理并发写入冲突主要通过以下机制实现:

1. 原子性写操作

MinIO 支持 原子性操作(Atomic Operations),即每个写操作(如 PUT 请求)都是一个独立的不可分割的事务。这样,当多个写操作同时发生时,每个操作都会以原子方式完成,确保没有部分写入导致的数据不一致。

2. 一致性哈希与分布式锁

MinIO 使用 一致性哈希(Consistent Hashing) 将对象分布到不同的存储节点上。为了在分布式环境下防止并发写入造成的数据不一致,MinIO 实现了 分布式锁机制,具体包括:

  • 分布式锁:在多个节点间协调对同一对象的写入操作,确保在任何时刻只有一个写入操作可以对对象进行更改。
  • 一致性协议:采用分布式一致性协议来管理锁的获取和释放,确保在节点故障或网络分区时锁状态的一致性。

通过这种方式,MinIO 能够在高并发环境下有效防止写入冲突,保持数据的一致性和完整性。

2.5 读写一致性与性能优化

1. 并行读写能力

MinIO 设计优化了 并行读写能力,能够同时处理多个读写请求:

  • 多线程和异步处理:MinIO 的存储引擎支持多线程和异步 I/O 操作,充分利用多核 CPU 和高速存储设备(如 SSD),提升整体吞吐量和响应速度。
  • 数据分片与并行传输:通过将对象数据分片存储在不同节点上,MinIO 可以并行处理跨节点的数据读取和写入,提高数据访问效率。

2. 读写分离机制

MinIO 通过 读写分离机制 优化系统性能:

  • 读优化:读操作可以从多个副本或节点同时获取数据,减少单点负载,提升读取速度。
  • 写优化:写操作集中在特定节点,确保写入一致性,并通过后端的数据冗余机制(如纠删码)确保数据的可靠性。

3. 缓存策略

MinIO 实施了多层次的 缓存策略 以优化读写性能:

  • 内存缓存:常用数据(热点数据)被缓存在内存中,提供快速访问,减少磁盘 I/O 延迟。
  • 分层缓存:结合内存和闪存(如 NVMe SSD)进行分层缓存,平衡成本与性能,提升数据访问速度。
  • 内容分发网络(CDN)集成:通过与 CDN 结合,可以缓存热点对象在边缘节点,进一步降低访问延迟,提高全球范围内的访问性能。
2.6 示例场景与操作流程

场景:多个微服务同时写入同一对象

假设有两个微服务 AB 同时尝试写入同一个对象 object1

  1. 写入请求发送
    • 微服务 A 发送 PUT 请求上传 object1 的新版本。
    • 微服务 B 同时发送另一个 PUT 请求上传 object1 的另一新版本。
  2. 分布式锁获取
    • MinIO 在服务器端尝试为 object1 获取分布式锁。
    • 假设微服务 A 的请求先到达并成功获取锁。
    • 微服务 B 的请求必须等待,直到锁被释放或根据锁策略重试。
  3. 写入执行
    • 微服务 A 成功写入新的 object1 版本,释放锁。
    • 微服务 B 的请求接收到锁释放的通知,随后获取锁并执行写入操作,创建 object1 的另一个版本。
  4. 版本控制
    • 由于启用了版本控制,object1 现在有两个版本,分别由微服务 A 和 B 上传。
    • 客户端可以选择读取最新版本或指定特定版本的数据。

场景:读取最新对象同时有写入操作

  1. 读取请求发送
    • 微服务 C 发起 GET 请求读取 object1
  2. 一致性保障
    • 如果微服务 A 的 PUT 请求尚未完成,微服务 C 将读取到旧版本的 object1
    • 若微服务 A 的 PUT 请求已完成,微服务 C 将读取到最新版本的 object1
2.4 客户端原理

对象存储客户端(Client)负责与存储服务器进行通信,管理数据的上传、下载和删除等操作。

获取数据

客户端通过API(如RESTful接口)与对象存储进行交互。每个对象都有一个唯一的标识符,客户端通过该标识符进行数据的定位和访问。客户端可以直接从存储节点获取数据,或者通过负载均衡器实现高效的数据传输。

通信机制

客户端与对象存储服务器之间的通信通常基于HTTP/HTTPS协议,确保数据传输的可靠性和安全性。此外,客户端还可以利用多线程或异步通信技术,提高数据传输的效率,减少延迟。

客户端级的冲突控制

除了服务器端的锁机制,MinIO 还支持客户端在进行写操作时使用 条件请求(如 ETag版本 ID)来控制并发写入:

  • 条件请求:客户端在提交写入请求时,可以指定条件(如当前对象的 ETag),只有在条件满足时才执行写入操作。这种机制可以防止因并发写入导致的数据覆盖。

    # 使用 curl 进行带条件的 PUT 请求
    curl -X PUT "https://minio.example.com/bucket/object" \
         -H "ETag: \"current-etag-value\"" \
         --upload-file localfile
    
  • 优化的错误处理:如果条件请求失败(如 ETag 不匹配),客户端可以选择重试或采取其他冲突解决策略,如提示用户或自动合并数据。

其他存储类型及其应用场景

除了对象存储,常见的存储类型还包括块存储(Block Storage)和文件存储(File Storage)。每种存储类型都有其独特的优势和适用场景。

块存储

块存储将数据分割成固定大小的块,每个块都有自己的地址。这种存储方式常用于需要高性能和低延迟的应用,如数据库、虚拟机磁盘等。块存储允许用户灵活地管理和配置存储资源,适合对性能要求苛刻的场景。

应用场景

  • 数据库存储
  • 虚拟机磁盘
  • 企业级应用
文件存储

文件存储以文件和目录的形式组织数据,类似于传统的文件系统。它适用于需要按文件访问和共享的场景,如文件共享、内容管理系统等。文件存储提供了易于使用的接口,方便用户进行文件的管理和访问。

应用场景

  • 文件共享与协作
  • 内容管理系统
  • 备份与归档
对象存储

如前所述,对象存储适用于海量非结构化数据的存储需求,具有高可扩展性和灵活性。

应用场景

  • 大数据分析
  • 媒体存储与分发
  • 云备份与恢复
三种存储的应用场景比较
存储类型性能可扩展性适用场景
块存储数据库、虚拟机
文件存储文件共享、内容管理
对象存储大数据、媒体存储

四、重塑架构的转折点

决定转型并不容易,但在团队的共同努力下,我们开始了向MinIO的迁移过程。对象的不可变性(Immutability)设计更是让我信服。每次写入操作都是对一个新的对象版本的创建,不再需要修改现有对象,这大大简化了并发控制和数据一致性管理。启用多版本控制后,我们可以存储同一对象的多个版本,每个写入请求都会生成一个独立的版本,避免了数据冲突,也为数据恢复和审计提供了坚实的保障。

MinIO的并行读写能力缓存策略极大地提升了系统性能。通过将对象数据和元数据分片存储在多个节点上,MinIO天生支持高并发访问,不再受制于NFS的锁机制限制。分布式锁机制确保在多个节点间协调对同一对象的写入操作,确保在任何时刻只有一个写入操作能够更改对象,避免了数据竞争和不一致性的问题。

迁移完成后的第一天,我们重新启动了系统。监控面板上,用户请求依旧如潮水般涌来,但这一次,MinIO高效地处理着每一个请求。系统运行稳定,响应速度恢复正常,用户体验得到了显著提升。团队的士气也因此大增,大家看到了希望,看到了问题的解决之道。

五、反思与感悟

经过这次经验,我深刻反思了我们的技术选择和架构设计。NFS虽然在初期解决了共享存储的问题,但随着业务的增长,它的局限性也逐渐显现出来。我们忽视了系统的可扩展性高并发处理能力,最终导致崩溃的发生。

对象存储的引入则为我们提供了一个更为灵活和高效的解决方案。它不仅解决了高并发读写的性能问题,还通过多版本控制分布式锁机制保障了数据的一致性和可靠性。这次转型不仅拯救了我们的系统,更让我重新认识到技术选型的重要性和前瞻性。

六、结语

每一次技术选型的背后,都隐藏着无数的挑战与机遇。在那一夜的崩溃中,我几乎失去了信心,但也让我看到了更好的选择——对象存储。MinIO不仅成为我们的救命稻草,更成为我们重塑系统架构、提升业务能力的重要基石。

如果你也正面临类似的困境,希望我的故事能为你带来一些启示。不要害怕面对问题,勇敢探索新的技术,或许一个简单的转变,就能为你的系统带来全新的生命力。

希望这篇文章,能够有效地将MinIO的技术原理与实际应用场景融为一体,为读者提供有技术深度的内容。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/919398.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【视频讲解】Python深度神经网络DNNs-K-Means(K-均值)聚类方法在MNIST等数据可视化对比分析...

全文链接:https://tecdat.cn/?p38289 分析师:Cucu Sun 近年来,由于诸如自动编码器等深度神经网络(DNN)的高表示能力,深度聚类方法发展迅速。其核心思想是表示学习和聚类可以相互促进:好的表示会…

K8S资源限制之ResourceQuota

ResourceQuota介绍 在K8S中,大部分资源都可以指定到一个名称空间下,因此可以对一个名称空间的计算资源,存储资源,资源数量等维度做资源限制。 如限制pod数量、svc数量,控制器数量,限制PVC请求的存储量 注…

【Android原生问题分析】夸克、抖音划动无响应问题【Android14】

1 问题描述 偶现问题,用户打开夸克、抖音后,在界面上划动无响应,但是没有ANR。回到Launcher后再次打开夸克/抖音,发现App的界面发生了变化,但是仍然是划不动的。 2 log初分析 复现问题附近的log为: 用户…

[JavaWeb]微头条项目

完整笔记和项目代码: https://pan.baidu.com/s/1PZBO0mfpwDPic4Ezsk8orA?pwdwwp5 提取码: wwp5 JavaWeb-微头条项目开发 1 项目简介 1.1 业务介绍 微头条新闻发布和浏览平台,主要包含业务如下 用户功能 注册功能登录功能 头条新闻 新闻的分页浏览通过标题关键字搜…

AJAX学习(24.11.1-24.11.14)(包含HTTP协议)

AJAX学习(24.11.1-11.14) 来源: 传智 | 高校学习平台-首页 传智播课:黑马程序员 1.服务器和客户端 1.服务器:存放和对外提供资源的电脑。 2.客户端(用户):获取和消费资源的电脑。&#xff0…

9.《滑动窗口篇》---①长度最小的子数组(中等)

滑动窗口推导过程 我们不能说一上来就知道这个题目用滑动窗口,然后就使用滑动窗口的方法来做这个题目。 首先我们想到的应该是暴力解法。 接着再优化为滑动窗口 由于数字都是 ≥ 0 的数。因此累加的数越多。和越大。 因此right往后遍历的时候。当发现sum > targe…

《Python网络安全项目实战》项目5 编写网站扫描程序

《Python网络安全项目实战》项目5 编写网站扫描程序 项目目标:任务5.1 暴力破解网站目录和文件位置任务描述任务分析任务实施相关知识任务评价 任务5.2 制作网页JPG爬虫任务分析任务实施相关知识任务评价任务拓展 WEB网站安全渗透测试过程中需要进行目录扫描和网站爬…

React(二)

文章目录 项目地址七、数据流7.1 子组件传递数据给父组件7.1.1 方式一:給父设置回调函数,传递给子7.1.2 方式二:直接将父的setState传递给子7.2 给props传递jsx7.2.1 方式一:直接传递组件给子类7.2.2 方式二:传递函数给子组件7.3 props类型验证7.4 props的多层传递7.5 cla…

Python学习29天

二分查找 # 定义函数冒泡排序法从大到小排列 def bbble_sort(list):# i控制排序次数for i in range(len(list) - 1):# j控制每次排序比较次数for j in range(len(list) - 1 - i):if list[j] < list[j 1]:list[j], list[j 1] list[j 1], list[j] # 定义二分查找函数 def…

【工控】线扫相机小结 第三篇

海康软件更新 目前使用的是 MVS_STD_4.3.2_240705.exe &#xff0c;最新的已经到4.4了。 一个大的变动 在上一篇中我们提到一个问题&#xff1a; 需要注意的是&#xff0c;我们必须先设置 TriggerSelector 是 “FrameBurstStart” 还是 “LineStart” 再设置TriggerMode 是 …

K8S资源限制之LimitRange

LimitRange介绍 LimitRange也是一种资源&#xff0c;在名称空间内有效&#xff1b;限制同一个名称空间下pod容器的申请资源的最大值&#xff0c;最小值pod的resources中requests和limits必须在这个范围内&#xff0c;否则pod无法创建。当然pod也可以不使用resources进行创建ty…

Maven maven项目构建的生命周期 Maven安装配置 IDEA 配置 Maven

一&#xff0c;Maven的概述 Maven的作用&#xff1a;专门用于管理和构建Java项目的工具&#xff0c;它的主要功能有&#xff1a; 提供了一套标准化的项目结构提供了一套标准化的构建流程&#xff08;编译&#xff0c;测试&#xff0c;打包&#xff0c;发布……&#xff09;提…

Rust “xxx“.to_string()和Rust String::from(“xxx“)区别(将字符串字面量(str类型)转换为String类型)

文章目录 Rust "xxx".to_string()和Rust String::from("xxx")区别1. .to_string()&#xff08;能够将任何可以显示的类型&#xff08;如数字、结构体等&#xff09;转为字符串&#xff09;2. String::from()区别总结&#xff1a;性能&#xff1a;示例对比&…

Windows仿macOS?看这一篇就够了

如果你有任何关于Windows仿macOS的问题&#xff0c;可加入942644281 &#xff08;QQ群&#xff09; Date9.20更新&#xff1a;增加功能按键左移部分Date9.16更新&#xff1a;增加了大多数资源的网盘链接Date9.15更新&#xff1a;增加StartAllBack&#xff0c;资源管理器调整部…

Django数据迁移出错,解决raise NodeNotFoundError问题

错误出现在&#xff1a; raise NodeNotFoundError(self.error_message, self.key, originself.origin) django.db.migrations.exceptions.NodeNotFoundError: Migration myApp.0003_alter_jobinfo_practise dependencies reference nonexistent parent node (myApp, 0002_renam…

PaddleNLP的环境配置:

PaddleNLP的环境配置&#xff1a; conda create -n paddle—test python3.9conda activate paddle—testpython -m pip install paddlepaddle-gpu2.6.1.post112 -f https://www.paddlepaddle.org.cn/whl/windows/mkl/avx/stable.html(paddle—test) (venv) PS D:\work\论文写…

【MySQL实战45讲笔记】基础篇——redo log 和 binlog

系列文章 基础篇——MySQL 的基础架构 目录 系列文章1. 重要的日志模块&#xff1a;redo log 和 binlog1.1 redo log1.2 binlog1.3 执行器和 InnoDB 引擎内部如何执行更新语句 1. 重要的日志模块&#xff1a;redo log 和 binlog 前面系统的了解了一个查询语句的执行流程&…

MATLAB常见数学运算函数

MATLAB中含有许多有用的函数,可以随时调用。 a b s abs abs函数 a b s abs abs函数在MATLAB中可以求绝对值,也可以求复数的模长:c e i l ceil ceil函数 向正无穷四舍五入(如果有小数,就向正方向进一)f l o o r floor floor函数 向负无穷四舍五入(如果有小数,就向负方向…

MySQL无开通SQL全审计下的故障分析方法

几年前MySQL数据库出现突然的从库延迟故障和CPU爆高时&#xff0c;如何排查具体原因&#xff0c;可能说已在腾讯云的MySQL库里开启了SQL全审计&#xff0c;记录了全部执行的SQL&#xff0c;再通过下面的方法就可以很容易找到原因&#xff1a; 1&#xff0c;实用QPS和TPS高的高效…

新手教学系列——善用 VSCode 工作区,让开发更高效

引言 作为一名开发者,你是否曾经在项目中频繁地切换不同文件夹,打开无数个 VSCode 窗口?特别是当你同时参与多个项目或者处理多个模块时,这种情况更是家常便饭。很快,你的任务栏上挤满了 VSCode 的小图标,切换起来手忙脚乱,工作效率直线下降。这时候,你可能会问:“有…