突破内存限制:Mac Mini M2 服务器化实践指南
本篇文章,我们聊聊如何使用 Mac Mini M2 来实现比上篇文章性价比更高的内存服务器使用,分享背后的一些小的思考。
希望对有类似需求的你有帮助。
写在前面
在上文《ThinkPad + Redis:构建亿级数据毫秒级查询的平民方案》中,我们探讨了如何用经济实惠的方案打造高性能本地服务器。然而,随着数据表查询加速需求的增加,按原方案继续扩展将占用我家中三台 64GB 内存的设备(一台运行数据库,两台负责缓存)。这无疑会挤占我其他实验环境的资源,毕竟除了家里跑着虚拟化的几台设备外,我手头可用的机器总共也就四五台。
就在我为此困扰时,一个灵感突然闪现 —— 通过二手交易 App,我发现 500 米外的卖家正在出售一台被 M4 Mac Mini 替代的 M2 机型。配置完美契合需求,价格也在预算之内。半个小时后,这台设备就躺在了我的桌面上。
接下来,让我们开启全新的折腾之旅。
技术方案的思考
在开始代码编写和设备配置之前,我们需要首先厘清以下四个关键问题。
为什么不继续沿用原有架构
在原方案中,我们成功实现了高性价比的性能优化。然而,随着待缓存数据量的增长,我希望在不持续增加设备投入的前提下找到更优解。
如果仅从工程优化的角度考虑,即使我们继续深入优化当前方案,预计效率提升的空间也仅剩约10%。这个现实限制很简单:64GB 内存一旦用尽,就无法突破这个物理瓶颈。
在传统的系统架构中,当面临内存容量限制时,我们通常会考虑启用SWAP 机制来扩展存储空间。但在 Redis 环境下,这个方案却带来了严重的性能问题:一旦启用 SWAP,内存与硬盘之间的数据交换会导致访问延迟攀升至秒级,同时引发请求堵塞,最终造成服务异常。
这就给我们带来了一个颇具挑战性的思考:面对相比内存资源充裕的多的硬盘空间,是否存在一种方案,能够在保持高性能的同时,充分利用这些存储资源?
切换至数据持久化的 KV 系统
在上篇文章中,我们提到过一个可行方案:采用互联网公司广泛使用的、兼容 Redis 协议的持久化 KV 系统。这类系统的优势在于能够智能地处理内存与硬盘之间的数据交换,而不是等到内存耗尽才被动应对。它采用动态调度策略,在服务运行期间持续优化数据分布。
这种方案本质上是一种性能与可用性的平衡之道:虽然可能会略微增加单次请求的响应时间,但避免了因内存耗尽导致的服务中断或因为 SWAP 时大量数据交换产生的服务降级。其核心理念是:最小化内存与硬盘之间的数据交换,因为单次数据量交换操作越少,系统性能就越好。
至于此前提到的云端平滑迁移需求,只要我们在使用时避免采用复杂的数据结构,基于协议兼容的优势,迁移过程将变得简单直接 —— 一个迁移程序就能轻松完成这项工作。
顺着思路,让我们来看看该怎么选择硬件。
方案下合适的硬件选择思路
基于前文的技术分析,我们在选择硬件时需要重点考虑三个核心要素:处理器性能、存储系统性能以及硬件可靠性。高性能的处理器能够加速内存与硬盘之间的数据交换过程,优秀的存储系统可以最小化数据迁移带来的延迟,而硬件的可靠性则确保系统能够长期稳定地承载频繁的数据交换操作。
在权衡性能需求与成本控制后,二手设备市场提供了一个极具吸引力的选择——搭载 M2 芯片的 Mac Mini。随着 M4 版本的发布,M2 Mac Mini 的二手市场价格出现了显著下跌,为我们提供了高性价比的机会。
苹果公司在供应链管理和品质控制领域一直处于行业领先地位。虽然其原装 SSD 经常因高价格、容量限制和难以更换而备受争议。当我们通过二手市场降低硬件成本后,再结合合理的技术方案来充分利用这些高品质但容量有限的存储设备时,一个看似对普通用户不够友好的特点,反而可能成为专业应用场景下的优势。
苹果自研的 M1/M2 芯片系列在多个关键指标上都表现出色:强劲的算力、优秀的内存带宽,再加上严格的硬件品质管控。尽管这些设备没有采用传统服务器常见的 ECC 内存和 SLC 固态硬盘,但在长期高负载运行测试中,它们依然展现出极高的可靠性和耐久性,完全没有出现数据错误问题。
不过,并非所有配置的 M2 Mac Mini 都能完全满足我们的技术需求,在具体选型时还需要注意一些关键细节。
Mac Mini 设备的选择细节
在这个专业应用场景下,我们对硬件配置有着明确的最低要求:M2及以上处理器、16GB及以上内存、512GB及以上存储容量。
512GB 容量的选择并非仅仅考虑存储空间,更重要的是性能因素。 M2 Mac Mini 搭载的 Apple SSD AP0512Z 相比 256GB 版本提供了双倍的性能表现。考虑到数据交换性能是我们方案中的关键因素,这一性能差异直接影响着系统的实际使用体验。
选择 16GB 及以上内存配置基于两个重要考虑:更大的内存空间能够有效减少内存与硬盘之间的数据交换频率,从而提升整体性能表现。吸取了 M1 8GB 版本的教训 —— 由于系统资源不足导致的频繁磁盘写入,曾让许多设备在一年内就严重消耗了 SSD 寿命。这种情况并非用户使用习惯导致,而是源于硬件配置限制下的系统级响应。
处理器不建议选择 M1 版本的原因同样有三点主要原因。技术代际有明显差距,作为 2020 年末发布的产品,其性能与 2022 年的 M2 乃至最新的 M4 相比存在明显差距。目前二手市场上主流的 M1 版本多为 8GB 内存配置,这些设备可能已经经历了大量磁盘读写操作,可靠性难以保证。而其 1900-2000 元的价格区间,性价比优势并不明显。暂时只有 M1、M2、M2 Pro 的芯片设备支持安装 Linux 操作系统,我之前在文章中《MacBook Pro 原生安装 Ubuntu 24.04 ARM 版》提到过,感兴趣可以自行翻阅。
如果你对 M1 和 M2 芯片的性能差异感兴趣,不妨了解以下资料:芯片技术参数的详细对比、专业论坛上的实测评测和用户体验分享。
开始实践
让我们从更换 Mac Mini 设备的操作系统开始实践。
为 Mac Mini 更换操作系统
与前文相同,我依然选择了 Ubuntu(ARM 版)作为主操作系统。基础安装步骤可参照《MacBook Pro 原生安装 Ubuntu 24.04 ARM 版》,以下重点说明几处差异。
首先是磁盘分区方案:为新系统分配了 75% 的磁盘空间,同时预留 15% 给 macOS。这样的配置既确保了 Ubuntu 系统的充足运行空间,又保证了在需要系统维护时,macOS 能有足够空间供必要软件的安装与运行(相当于一个高级版的 PE 系统)。
We're going to resize this partition:APFS [Macintosh HD] (494.38 GB, 6 volumes)Total size: 494.38 GBFree space: 469.81 GBAvailable space: 431.81 GBOverhead: 0 BMinimum new size: 62.57 GB (12.66%)Enter the new size for your existing partition:You can enter a size such as '1GB', a fraction such as '50%',or the word 'min' for the smallest allowable size.Examples:30% - 30% to macOS, 70% to the new OS80GB - 80GB to macOS, the rest to your new OSmin - Shrink macOS as much as (safely) possible» New size (50%): 15%
值得一提的是,最新版安装脚本已完全兼容 Ubuntu 24.04.1。这意味着我们可以直接进行系统安装,省去了先装早期版本再升级的繁琐步骤。
Choose an OS to install:1: Ubuntu Desktop 24.04.1 LTS2: Ubuntu Server 24.04.1 LTS3: Ubuntu Desktop 23.104: Ubuntu 22.04 LTS Server (unsupported)
» OS: 1
在 macOS 环境完成系统安装的第一阶段操作后,关闭设备并重新启动。在开机过程中,长按电源键直至出现引导选项界面。从中选择新安装的 Linux(Ubuntu)系统进行引导。
首次切换至新系统时,设备会自动进入 macOS 恢复模式。此时,系统会要求输入当前主机的用户名和密码,以解锁系统并授权引导至非 macOS 系统。只需按照屏幕提示一步步操作即可完成此过程。
操作完成后,系统会自动重启并进入 Linux 环境。此时,您可能会发现显示器没有任何输出。这是因为 Linux 系统暂不支持通过雷电接口输出画面。要解决这个问题,只需将显示器连接线从雷电接口切换到 HDMI 接口即可。
Mac Mini 的 Linux 启动速度非常快。片刻之间,熟悉的 Ubuntu 界面就会在连接的显示器上出现。
系统初始化后,首要任务是安装 SSH Server,以实现局域网内的远程管理功能。然而,在此之前,我们需要更新软件源以确保安装过程的效率和稳定性。
值得注意的是,随着系统版本的迭代,更新软件源的具体操作方法也发生了变化。
# 24.04.1 之前的版本
# sed -i 's/ports.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list# 24.04.1 及之后的版本
sed -i 's/ports.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list.d/ubuntu.sources
安装过程十分简单,只需两步即可完成:首先更新软件列表(同时顺便更新系统软件),然后执行安装 openssh-server
的命令。
apt update && apt upgrade -y
apt install openssh-server -y
接下来,我们就能够在终端输入 ssh [Mac Mini 局域网 IP 地址]
命令,来轻松地通过 SSH 远程管理它啦。
编译构建数据持久化 KV:Pika
Pika 是一款基于 RocksDB 存储引擎的高性能 KV 存储系统,它不仅完全兼容 Redis 协议,还支持持久化存储和多租户特性。作为 Redis 的有力补充,它支持 string、hash、list、zset、set、geo、hyperloglog、pubsub、bitmap、stream 等所有常用的 Redis 数据结构。
日常业务过程中,当 Redis 内存使用超过特定阈值(如 16GiB)时,往往会遇到以下挑战:内存容量受限、单线程处理导致阻塞、系统启动恢复耗时过长、内存硬件成本高昂、缓冲区易达到上限、主从切换开销巨大等问题。
Pika 在保持 Redis 协议兼容性和便捷运维特性的同时,通过持久化存储方案解决了 Redis 面临的大数据量存储瓶颈。此外,它还支持 slaveof 主从模式,并提供全量/增量数据同步功能。
由于官方暂未提供 ARM 平台的预编译二进制文件,我们需要通过源码自行构建。构建步骤非常简单,主要命令如下:
# 下载最近的正式发布版本
wget https://github.com/OpenAtomFoundation/pika/archive/refs/tags/v4.0.1.zip
# 解压缩源码
unzip v4.0.1.zip
# 切换工作目录
cd pika-4.0.1/
# 安装必要的构建工具
apt install cmake -y
# 执行构建脚本
bash build.sh
执行构建脚本后,系统首先会检查环境中是否包含所需的构建工具,随后自动下载项目的外部依赖包,并启动构建流程。在这个过程中,我们将看到类似下面的构建日志:
+ C_RED='\033[31m'
+ C_GREEN='\033[32m'
+ C_END='\033[0m'
+ CMAKE_MIN_VERSION=3.18
+ TAR_MIN_VERSION=1.26
+ BUILD_DIR=output
+ CLEAN_BUILD=false
+ ARGS=()
+ '[' '!' -f /proc/cpuinfo ']'
++ cat /proc/cpuinfo
++ grep processor
++ wc -l
+ CPU_CORE=8
+ '[' 8 -eq 0 ']'
+ echo 'cpu core 8'
cpu core 8
+ [[ false = \t\r\u\e ]]
+ [[ '' = \c\l\e\a\n ]]
+ [[ '' = \c\o\d\i\s ]]
+ source ./utils/Get_OS_Version.sh
++ Get_Dist_Name
++ '[' '!' -f /etc/issue ']'
...
++ grep -Eqi Debian /etc/issue
++ grep -Eq Debian /etc/lsb-release /etc/os-release
++ grep -Eqi Ubuntu /etc/issue
++ DISTRO=Ubuntu
++ PM=apt
++ echo Ubuntu
Ubuntu
+ check_program autoconf
+ type autoconf
+ return 0
+ check_program tar
+ type tar
...
pika PROTO_SRCS = /root/projects/pika-4.0.1/output/pika_inner_message.pb.cc;/root/projects/pika-4.0.1/output/rsync_service.pb.cc
pika PROTO_HDRS = /root/projects/pika-4.0.1/output/pika_inner_message.pb.h;/root/projects/pika-4.0.1/output/rsync_service.pb.h
-- Configuring done (0.1s)
-- Generating done (0.0s)
-- Build files have been written to: /root/projects/pika-4.0.1/output
+ '[' 0 -ne 0 ']'
+ make -j 8
[ 1%] Performing build step for 'fmt'
[ 1%] Performing build step for 'gflags'
[ 3%] Built target unwind
[ 3%] Performing build step for 'gtest'
[ 3%] Performing build step for 'zlib'
[ 6%] Performing build step for 'lz4'
[ 6%] Performing build step for 'snappy'
[ 7%] Performing build step for 'zstd'
[ 8%] Performing build step for 'jemalloc'...[100%] Linking CXX executable pika
[100%] Built target pika
[100%] Linking CXX executable keys_test
[100%] Built target keys_test
[100%] Linking CXX executable zsets_test
[100%] Built target zsets_test
+ '[' 0 -eq 0 ']'
+ echo -e 'pika compile complete, output file \033[32m output/pika \033[0m'
pika compile complete, output file output/pika
当出现 pika compile complete, output file output/pika
提示时,表明程序构建已成功完成。
编译过程中,Mac Mini 的功耗首次攀升至 26 瓦,令人惊讶。而在日常运行时,功耗却始终保持在 1 至 5 瓦之间,如此低的数值甚至让我一度怀疑电源显示器是否出现故障。
基础功能验证
接下来,我们可以通过以下命令对 Pika 进行基础功能验证(使用少量内存和大量磁盘提供等效 Redis 的服务):
./output/pika -c ./conf/pika.conf
运行命令后,终端将显示 Pika 在默认配置下的运行日志。
...
I20241122 15:02:55.769603] 78 cache-type string, set, zset, list, hash, bit
I20241122 15:02:55.769608] 79 zset-cache-field-num-per-key 512
I20241122 15:02:55.769613] 80 zset-cache-start-direction 0
I20241122 15:02:55.769618] 81 cache-maxmemory 10737418240
I20241122 15:02:55.769622] 82 cache-maxmemory-policy 1
I20241122 15:02:55.769627] 83 cache-maxmemory-samples 5
I20241122 15:02:55.769632] 84 cache-lfu-decay-time 1
I20241122 15:02:55.769637] 85 internal-used-unfinished-full-sync
I20241122 15:02:55.769641] 86 wash-data true............. .... ..... ..... ..... ################# #### ##### ##### ####### #### ##### #### ##### ##### ######### #### ##### #### ##### ##### #### ##### #### ##### #### ##### ##### #### ##### ################ #### ##### ##### #### ##### #### #### ##### ##### ################# #### #### ##### ###### ##### ##### #### #### ##### ###### ##### #####
-----------Pika config end----------
W20241122 15:02:55.769673 52462 pika.cc:191] your 'limit -n ' of 1024 is not enough for Redis to start. pika have successfully reconfig it to 25000
I20241122 15:02:55.769685 52462 pika.cc:209] Server at: ./conf/pika.conf
I20241122 15:02:55.769832 52462 net_interfaces.cc:108] Using Networker Interface: end0
I20241122 15:02:55.769907 52462 net_interfaces.cc:152] got ip 10.11.12.93
I20241122 15:02:55.769915 52462 pika_server.cc:157] host: 10.11.12.93 port: 9221
I20241122 15:02:55.769927 52462 pika_server.cc:71] Worker queue limit is 20100
W20241122 15:02:55.769932 52462 pika_server.cc:72] 0.0.0.0
I20241122 15:02:55.770182 52462 pika_server.cc:1664] Dump file is not exist,path: ./dump/
I20241122 15:02:55.770282 52462 pika_binlog.cc:98] Binlog: Find the exist file.
I20241122 15:02:55.797559 52462 pika_db.cc:50] db0 DB Success
I20241122 15:02:55.797613 52783 pika_cache_load_thread.cc:181] PikaCacheLoadThread::ThreadMain Start
I20241122 15:02:55.798816 52462 net_util.cc:121] TimerTaskThread Starting...
I20241122 15:02:55.798950 52462 pika_server.cc:214] Pika Server going to start
I20241122 15:02:55.798961 52462 rsync_server.cc:48] start RsyncServer ...
I20241122 15:02:55.799070 52462 rsync_server.cc:60] RsyncServer started ...
在默认配置下,Pika 运行于 9222 端口,并为 RocksDB 的数据设置了如下策略:
- 数据生命周期为 7 天
- 每三天自动执行一次数据压缩和过期清理
为避免数据因自动清理而丢失,我们需要根据实际应用场景调整这些配置,特别是延长数据的生命周期。
测试验证 M2 Mac Mini 上的 Pika 性能
测试结果令我非常满意。这台设备不仅能耗极低、运行静音,还几乎跑满了设备本身的千兆网口,同时保留了充足的系统算力。
测试环境配置:
- 网络环境:基于《千兆之上:家庭网络 2.5G 升级实践》搭建的 2.5G 内网
- 服务端:Mac Mini M2(千兆网口,未安装 2.5G 网卡)
- 测试端:MacBook Air M3
本次测试采用开源工具 Vire Benchmark。测试流程如下:
- 通过 Docker 拉取预构建镜像
- 启动容器
- 执行性能测试:模拟 100 并发,向 Pika 发送 10 万次请求,测试
PING
、SET
、GET
命令,每次请求携带 20KB 数据。
具体测试命令如下:
docker pull putianhui/vire-benchmark
docker run --rm -it putianhui/vire-benchmark bashvire-benchmark -h 10.11.12.93 -p 9221 -t ping,set,get -n 100000 -c 100 -d 20480
执行完成后,系统将返回如下测试结果:
====== PING_INLINE ======100000 requests completed in 2.35 seconds100 parallel clients20480 bytes payloadkeep alive: 116.49% <= 1 milliseconds
59.89% <= 2 milliseconds
92.06% <= 3 milliseconds
96.72% <= 4 milliseconds
97.89% <= 5 milliseconds
98.40% <= 6 milliseconds
98.70% <= 7 milliseconds
98.93% <= 8 milliseconds
99.00% <= 9 milliseconds
99.07% <= 10 milliseconds
99.08% <= 11 milliseconds
99.22% <= 12 milliseconds
99.27% <= 13 milliseconds
99.30% <= 14 milliseconds
99.31% <= 15 milliseconds
99.31% <= 16 milliseconds
99.33% <= 17 milliseconds
99.35% <= 18 milliseconds
99.40% <= 19 milliseconds
99.43% <= 20 milliseconds
99.48% <= 21 milliseconds
99.58% <= 22 milliseconds
99.63% <= 23 milliseconds
99.79% <= 24 milliseconds
99.82% <= 25 milliseconds
99.84% <= 26 milliseconds
99.84% <= 35 milliseconds
99.84% <= 36 milliseconds
99.85% <= 39 milliseconds
99.85% <= 40 milliseconds
99.85% <= 41 milliseconds
99.86% <= 42 milliseconds
99.87% <= 43 milliseconds
99.87% <= 44 milliseconds
99.88% <= 45 milliseconds
99.91% <= 46 milliseconds
99.95% <= 47 milliseconds
99.97% <= 48 milliseconds
99.98% <= 49 milliseconds
100.00% <= 50 milliseconds
100.00% <= 51 milliseconds
100.00% <= 52 milliseconds
100.00% <= 53 milliseconds
42607.59 requests per second====== PING_BULK ======100000 requests completed in 1.98 seconds100 parallel clients20480 bytes payloadkeep alive: 112.37% <= 1 milliseconds
79.92% <= 2 milliseconds
93.37% <= 3 milliseconds
96.13% <= 4 milliseconds
97.54% <= 5 milliseconds
98.19% <= 6 milliseconds
98.58% <= 7 milliseconds
98.84% <= 8 milliseconds
99.04% <= 9 milliseconds
99.25% <= 10 milliseconds
99.35% <= 11 milliseconds
99.44% <= 12 milliseconds
99.53% <= 13 milliseconds
99.59% <= 14 milliseconds
99.65% <= 15 milliseconds
99.71% <= 16 milliseconds
99.73% <= 17 milliseconds
99.79% <= 18 milliseconds
99.84% <= 19 milliseconds
99.86% <= 20 milliseconds
99.88% <= 55 milliseconds
99.89% <= 56 milliseconds
99.89% <= 57 milliseconds
99.90% <= 58 milliseconds
99.90% <= 59 milliseconds
99.91% <= 60 milliseconds
99.91% <= 61 milliseconds
99.93% <= 62 milliseconds
99.93% <= 63 milliseconds
99.94% <= 64 milliseconds
99.96% <= 65 milliseconds
99.97% <= 67 milliseconds
99.97% <= 68 milliseconds
99.98% <= 103 milliseconds
99.98% <= 104 milliseconds
99.99% <= 108 milliseconds
100.00% <= 112 milliseconds
100.00% <= 113 milliseconds
100.00% <= 113 milliseconds
50632.91 requests per second
性能评估采用了 Redis 基准测试的两种标准方法:Redis Inline 格式和 Redis Bulk 批量格式。无论使用哪种方式,系统性能均大幅超越预期,完全满足并超出了我们的业务需求。
其他
在前文的“技术方案思考”小节中,我曾提及了选择 Mac Mini 作为设备的考量。既然设备已经到手,自然要一探究竟。
首先,让我们来看看这台二手 Mac Mini 的硬盘使用情况。拿到设备后,我立即进行了一次简单而关键的磁盘信息读取:
# smartctl -x /dev/disk0s1smartctl 7.4 2023-08-01 r5530 [Darwin 24.0.0 arm64] (local build)
Copyright (C) 2002-23, Bruce Allen, Christian Franke, www.smartmontools.org=== START OF INFORMATION SECTION ===
Model Number: APPLE SSD AP0512Z
Serial Number: 0ba01ee32330982c
Firmware Version: 499.0.9
PCI Vendor/Subsystem ID: 0x106b
IEEE OUI Identifier: 0x000000
Controller ID: 0
NVMe Version: <1.2
Number of Namespaces: 3
Local Time is: Thu Nov 21 06:06:19 2024 PST
Firmware Updates (0x02): 1 Slot
Optional Admin Commands (0x0004): Frmw_DL
Optional NVM Commands (0x0004): DS_Mngmt
Maximum Data Transfer Size: 256 PagesSupported Power States
St Op Max Active Idle RL RT WL WT Ent_Lat Ex_Lat0 + 0.00W - - 0 0 0 0 0 0=== START OF SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSEDSMART/Health Information (NVMe Log 0x02)
Critical Warning: 0x00
Temperature: 31 Celsius
Available Spare: 100%
Available Spare Threshold: 99%
Percentage Used: 0%
Data Units Read: 33,153,911 [16.9 TB]
Data Units Written: 10,289,877 [5.26 TB]
Host Read Commands: 522,484,819
Host Write Commands: 227,748,421
Controller Busy Time: 0
Power Cycles: 450
Power On Hours: 177
Unsafe Shutdowns: 16
Media and Data Integrity Errors: 0
Error Information Log Entries: 0Read 1 entries from Error Information Log failed: GetLogPage failed: system=0x38, sub=0x0, code=745
这台 Mac Mini 的使用数据表明设备处于近乎全新的状态。首先,SSD 硬盘的可用备用空间仍保持在 100%,表明设备几乎未被使用过。在读写方面,总读取量达到 16.9 TB,写入量为 5.26 TB,读取命令约 5.22 亿次,写入命令 2.28 亿次,形成了 3.2:1 的读写比例。这一比例说明设备的主要活动集中在内存中,使用强度相对较轻。
尽管设备记录了 450 次开关机循环(可能包括休眠唤醒),但实际通电时间仅有 177 小时,约合 7.4 天。这一数据进一步证实了设备的轻度使用状态。设备使用过程中的唯一异常是,硬盘记录了 16 次强制关机或断电操作。
综上所述,虽然这台 Mac Mini 经历了一定次数的开关机,但其实际使用时间极短,硬盘几乎未被使用。
当然,最重要的还是实际使用性能。我在这台 Mac Mini 上编译了上一篇文章中的内存读写性能测试工具,并进行了三轮测试。
# gcc -O2 memtest.c -o memtest# ./memtest
校验结果: 25427968
写入能力: 8.54 GB/s
读取能力: 298.51 GB/s
# ./memtest
校验结果: 25427968
写入能力: 9.21 GB/s
读取能力: 286.46 GB/s
# ./memtest
校验结果: 25427968
写入能力: 9.19 GB/s
读取能力: 293.86 GB/s
尽管在读取性能上略显逊色,只有 ThinkPad 方案的 60%,但这台 Mac Mini 在写入速度超过 ThinkPad 接近 5 倍。
文章至此已近尾声,让我与各位喜欢折腾的朋友分享一下这次设备购入的成本和设备市场价格情况。
由于这台设备距离我近在咫尺,当晚(九点)即可验证方案可行性,我选择了以二手市场中较高的价格成交。考虑到设备几乎全新,且目前仅此类设备支持安装 Linux,这个价格或许仍算合理:平摊到五年,每年 700 元(云服务器等规格一个月 1200 元起)。
当然,若您不急于使用,耐心等待总能换来更优惠的价格。特别是随着 M4 芯片 Mac Mini 的普及,相信这类设备的价格必将进一步下探。
最后
至此,本次探索告一段落。等这段手头事情忙完后,我计划折腾一套集群方案。
当然,正如本次实践,期待合适的老款 Mac Mini M2 能回归理想价位。目前的设备价格略显偏高,尤其考虑到折扣后的 M4 版 Mac Mini 仅需 3500 元。
祝大家玩的开心。
–EOF
我们有一个小小的折腾群,里面聚集了一些喜欢折腾、彼此坦诚相待的小伙伴。
我们在里面会一起聊聊软硬件、HomeLab、编程上、生活里以及职场中的一些问题,偶尔也在群里不定期的分享一些技术资料。
关于交友的标准,请参考下面的文章:
致新朋友:为生活投票,不断寻找更好的朋友
当然,通过下面这篇文章添加好友时,请备注实名和公司或学校、注明来源和目的,珍惜彼此的时间 😄
关于折腾群入群的那些事
如果你觉得内容还算实用,欢迎点赞分享给你的朋友,在此谢过。
如果你想更快的看到后续内容的更新,请戳 “点赞”、“分享”、“在看” ,这些免费的鼓励将会影响后续有关内容的更新速度。
本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)
本文作者: 苏洋
创建时间: 2024年11月22日
统计字数: 15327字
阅读时间: 31分钟阅读
本文链接: https://soulteary.com/2024/11/22/breaking-memory-limits-a-practical-guide-to-serverization-on-the-mac-mini-m2.html
相关文章:
突破内存限制:Mac Mini M2 服务器化实践指南
本篇文章,我们聊聊如何使用 Mac Mini M2 来实现比上篇文章性价比更高的内存服务器使用,分享背后的一些小的思考。 希望对有类似需求的你有帮助。 写在前面 在上文《ThinkPad Redis:构建亿级数据毫秒级查询的平民方案》中,我们…...
【Linux】Linux系统电源状态
前言 本文主要介绍Linux系统电源状态。 Linux内核代码声明如下,位于kernel/power/suspend.c。 参考链接 Linux系统电源状态 在Linux操作系统中,将电源划分为如下几个状态: ACPI StateLinux StateDescriptionS0On(on)WorkingS1Standby(sta…...
《用Python画蔡徐坤:艺术与编程的结合》
简介 大家好!今天带来一篇有趣的Python编程项目,用代码画出知名偶像蔡徐坤的形象。这个项目使用了Python的turtle库,通过简单的几何图形和精心设计的代码来展示艺术与编程的结合。 以下是完整的代码和效果介绍,快来试试看吧&…...
ARM(安谋) China处理器
0 Preface/Foreword 0.1 参考博客 Cortex-M23/M33与STAR-MC1星辰处理器 ARM China,2018年4月established,独立运行。 1 处理器类型 1.1 周易AIPU 1.2 STAR-MC1(星辰处理器) STAT-MC1,主要为满足AIOT应用性能、功…...
硬中断关闭后的堆栈抓取方法
一、背景 性能和稳定性是一个计算机工程里的一个永恒的主题。其中尤其稳定性这块的问题发现和问题分析及问题解决就依赖合适的对系统的观测的手段,帮助我们发现问题,识别问题原因最后才能解决问题。稳定性问题里尤其底层问题里,除了panic问题…...
电影风格城市夜景旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!
调色教程 电影风格城市夜景旅拍通过 Lightroom 调色,将城市夜晚的景色打造出如同电影画面般的质感和氛围。以独特的色彩和光影处理,展现出城市夜景的魅力与神秘。 预设信息 调色风格:电影风格预设适合类型:人像,街拍…...
基于FPGA的2FSK调制-串口收发-带tb仿真文件-实际上板验证成功
基于FPGA的2FSK调制 前言一、2FSK储备知识二、代码分析1.模块分析2.波形分析 总结 前言 设计实现连续相位 2FSK 调制器,2FSK 的两个频率为:fI15KHz,f23KHz,波特率为 1500 bps,比特0映射为f 载波,比特1映射为 载波。 1)…...
【Python】构建事件驱动架构:用Python实现实时应用的高效系统
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 事件驱动架构(Event-Driven Architecture,EDA)是一种基于事件流动进行系统设计的模式,广泛应用于游戏开发、实时监控和分布式系统中。它通过解耦事件的生产者和消费者,提升系统的可扩展性和灵活性。本文章从…...
安装 Docker(使用国内源)
一、安装Docker-ce 1、下载阿里云的repo源 [rootlocalhost ~]# yum install yum-utils -y && yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo && yum makecache # 尝试列出 docker-ce 的版本 [rootlocalh…...
001 MATLAB介绍
前言: 软件获取渠道有很多,难点也就是百度网盘下载慢; 线上版本每月有时间限制。 01 MATLAB介绍 性质: MATLAB即Matrix Laboratory 矩阵实验室的意思,是功能强大的计算机高级语言, 已广泛应用于各学科研究部门、…...
vscode利用ofExtensions插件可以调试单进程Openfoam,但是不能调试mpi多进程案例
问题: 准备调试流固耦合案例,包括流体和固体的,但是用ofextensions插件。但是流体的话使用的是域分解方法,将大的单元分成了小的单元用mpi并行处理,里面的program必须输入"/usr/bin/mpirun", // 这里改为使…...
2022年计算机网络408考研真题解析
第一题: 解析:网络体系结构-数据链路层 在ISO网络参考模型中,运输层,网络层和数据链路层都实现了流量的控制功能,其中运输层实现的是端到端的流量控制,网络层实现的是整个网络的流量控制,数据链…...
React-useEffect的使用
useEffect react提供的一个常用hook,用于在函数组件中执行副作用操作,比如数据获取、订阅或手动更改DOM。 基本用法: 接受2个参数: 一个包含命令式代码的函数(副作用函数)。一个依赖项数组,用…...
python学习笔记(10)算法(3)列表
一、列表 列表(list)是一个抽象的数据结构概念,它表示元素的有序集合,支持元素访问、修改、添加、删除和遍历 等操作,无须使用者考虑容量限制的问题。列表可以基于链表或数组实现。 ‧ 链表天然可以看作一个列表&#…...
嵌入式系统与单片机工作原理详解
随着现代科技的发展,嵌入式系统已经深入到我们日常生活中的方方面面。无论是智能家居、汽车电子,还是工业控制、医疗设备,都离不开嵌入式系统的支持。而单片机作为嵌入式系统的核心组件,是实现这些功能的关键之一。本文将详细介绍…...
Spark SQL 之 QueryStage
ExchangeQueryStageExec ExchangeQueryStageExec 分为两种...
Flink Standalone 集群模式安装部署教程
目录 一、前言 二、环境准备 三、安装步骤 1. 下载并安装 Flink 4. 配置 Flink 5. 配置环境变量 6. 启动 Flink 集群 7. 访问 Flink Web 界面 四、简单测试 五、常见问题和解决办法 1. 启动失败,无法连接到 TaskManager 2. Web 界面无法访问 六、总结 …...
【运维】 使用 shell 脚本实现类似 jumpserver 效果实现远程登录linux 服务器
实现效果 通过序号选择登录: 配置证书登录 配置证书登录可以免去每次都输入密码的麻烦。详见另一篇博文: 【ssh】使用秘钥对(公钥/私钥)登录linux主机以及原理介绍 自动登录脚本 直接复用以下脚本即可,在 server…...
根据实验试要求,打通隧道连接服务器上的数据库,前端进行数据调用。
1.背景介绍 数据库布置在了工大实验试K80服务器上,本地属于外网无法直接访问校园内网。需要打通隧道,通过堡垒机进行服务器的访问。获取到数据库数据进行前端展示。 2.打通隧道 访问指令: 我选择使用Xshell打通隧道。优点:凭证…...
ubuntu 安装 docker 记录
本文假设系统为 Ubuntu,从 16.04 到 24.04,且通过 APT 命令安装。理论上也其他 Debian 系的操作系统。 WSL 也一样。 感觉 Docker 官方在强推 Docker Desktop,搜索 Docker 安装文档,一不小心就被导航到了 Docker Desktop 的安装页…...
46.坑王驾到第十期:vscode 无法使用 tsc 命令
点赞收藏加关注,你也能住大别墅! 一、问题重现 上一篇帖子记录了我昨天在mac上安装typescript及调试的过程。今天打开vscode准备开干的时候,发现tsc命令又无法使用了,然后按照昨天的方法重新安装调试后又能用了,但是关…...
pytorch3d linux安装
目录 测试成功2024.11.21: 测试成功2024.11.21: python3.10 GitHub - facebookresearch/pytorch3d: PyTorch3D is FAIRs library of reusable components for deep learning with 3D data 安装脚本: cd pytorch3d && pip install…...
P1168 中位数
网址如下:P1168 中位数 - 洛谷 | 计算机科学教育新生态 一道求中位数的题,本来是想再用二分法来试一下的,但是出现了一点问题,先把AC的放出来 很简单,一个记录比中位数大的数的最小堆,和一个记录比中位数小…...
全面解析多种mfc140u.dll丢失的解决方法,五种方法详细解决
当你满心期待地打开某个常用软件,却突然弹出一个错误框,提示“mfc140u.dll丢失”,那一刻,你的好心情可能瞬间消失。这种情况在很多电脑用户的使用过程中都可能出现。无论是游戏玩家还是办公族,面对这个问题都可能不知所…...
✅✅✅【Vue.js】sd.js基于jQuery Ajax最新原生完整版for凯哥API版本
api.js //封装ajax方法 import $g from "../sg";//vue项目使用 import $ from jquery;//(提示:原生开发页面请前往https://jquery.com下载最新版jQuery) import { Message } from "element-ui";//element项目使用 // import axios from "…...
【Python】分割秘籍!掌握split()方法,让你的字符串处理轻松无敌!
在Python开发中,字符串处理是最常见也是最基础的任务之一。而在众多字符串操作方法中,split()函数无疑是最为重要和常用的一个。无论你是Python新手,还是经验丰富的开发者,深入理解并熟练运用split()方法,都将大大提升…...
非root用户安装CUDA
1.使用nvidia-smi查看当前驱动支持的最高CUDA版本: 表示当前驱动最多支持cuda12.1 2.进入cuda安装界面,https://developer.nvidia.com/cuda-toolkit-archive,选择想要安装的版本,例如想要安装CUDA11.4: 如果需要查看ub…...
Qt中2D绘制系统
目录 一、Qt绘制系统 1.1Qt绘制基本概念 1.2 绘制代码举例 1.3画家 1.3.1 QPainter的工作原理: 1.3.2 自定义绘制饼状图: 1.4画笔和画刷 1.4.1画笔 1.4.2 画刷填充样式 1.5 反走样和渐变 1.6绘制设备 1.7坐标变换 1.8QPainterPath 1.9绘制文…...
实战项目负载均衡式在线 OJ
> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:能自己实现负载均衡式在线 OJ。 > 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! > 专栏选自࿱…...
shell脚本启动springboot项目
nohup java -jar springboot.jar > springboot.log 2>&1 & 表示日志输出重定向到springboot.log日志文件, 而原本的日志继续输出到 项目同级的log文件夹下, 所以这个重定向没必要. 我们没必要要2分日志 #!/bin/bash# 获取springboot项目的进程ID PID$(ps -e…...
Django 自定义路由转换器
步骤 创建自定义转换器类 必须定义 regex 属性(用于匹配参数)。必须实现 to_python 和 to_url 方法。 to_python: 将匹配的参数转换为视图函数可用的 Python 数据。to_url: 将数据转换为 URL 格式(用于反向解析)。 注册转换器 使用…...
低速接口项目之串口Uart开发(二)——FIFO实现串口数据的收发回环测试
本节目录 一、设计思路 二、loop环回模块 三、仿真模块 四、仿真验证 五、上板验证 六、往期文章链接本节内容 一、设计思路 串口数据的收发回环测试,最简单的硬件测试是把Tx和Rx连接在一起,然后上位机进行发送和接收测试,但是需要考虑到串…...
Oracle 数据库 IDENTITY 列
IDENTITY列是Oracle数据库12c推出的新特性。之所以叫IDENTITY列,是由于其支持ANSI SQL 关键字 IDENTITY,其内部实现还是使用SEQUENCE。 不过推出这个新语法也是应该的,毕竟MyQL已经有 AUTO_INCREMENT列,而SQL Server也已经有IDENT…...
算法笔记:单调队列
单调队列: 队列元素之间的关系具有单调性(从队首到队尾单调递增/递减),队首和队尾都可以进行入队出队(即插入删除)操作,本质是由双端队列deque实现。 适用问题 通常解决动态小区间中寻找极值…...
深度解析:Nginx模块架构与工作机制的奥秘
文章目录 前言Nginx是什么?Ngnix特点: 一、Nginx模块与工作原理1.Nginx的模块1.1 Nginx模块常规的HTTP请求和响应的流程图:1.2 Nginx的模块从结构上分为如下三类:1.3 Nginx的模块从功能上分为如下三类: 2.Nginx的进程模型2.1 Nginx进程结构2.2 nginx进程…...
【git】commit之后,想撤销commit
一、已经commit,想要回退到上一步 保留代码 git reset --soft HEAD^回退到具体的哪一步 HEAD^的意思是上一个版本,也可以写成HEAD~1如果你进行了2次commit,想都撤回,可以使用HEAD~2二、git reflog 查看 sha值 git reflog 回到…...
实现在两台宿主机下的docker container 中实现多机器通讯
基于我的实验背景 上位机:ubuntu 20.04 (docker humble 22.04) 下位机:ubuntu 22.04(docker noetic 20.04) 目标:实现在上位机中的docker container 容器的22.04环境去成功远程访问 非同网段的下位机的20.04的contai…...
Python 网络爬虫操作指南
网络爬虫是自动化获取互联网上信息的一种工具。它广泛应用于数据采集、分析以及实现信息聚合等众多领域。本文将为你提供一个完整的Python网络爬虫操作指南,帮助你从零开始学习并实现简单的网络爬虫。我们将涵盖基本的爬虫概念、Python环境配置、常用库介绍。 上传…...
vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数
vue3 uniapp 扫普通链接或二维码打开小程序并获取携带参数 微信公众平台添加配置 微信公众平台 > 开发管理 > 开发设置 > 扫普通链接二维码打开小程序 配置链接规则需要下载校验文档给后端存入服务器中,保存配置的时候会校验一次,确定当前的配…...
高标准农田智慧农业系统建设方案
1 项目概述 1.1 建设背景 我国是农业大国,近30年来农田高产量主要依靠农药化肥的大量投入,大部分化肥和水资源没有被有效利用而随地弃置,导致大量养分损失并造成环境污染。我国农业生产仍然以传统生产模式为主,传统耕种只能凭经验施肥灌溉,不仅浪费大量的人力物力,也对环…...
【python图解】数据结构之字典和集合
【python图解】数据结构之字典和集合 在 Python 中,字典和集合是另外的两种重要数据结构,它们分别用于存储键值对和无序的唯一元素集合。下面我们将详细介绍字典和集合的定义、操作方法、使用场景及相关案例。 1. 字典(Dictionary࿰…...
vue 预览pdf 【@sunsetglow/vue-pdf-viewer】开箱即用,无需开发
sunsetglow/vue-pdf-viewer 开箱即用的pdf插件sunsetglow/vue-pdf-viewer, vue3 版本 无需多余开发,操作简单,支持大文件 pdf 滚动加载,缩放,左侧导航,下载,页码,打印,文本复制&…...
TCL嵌入式面试题及参考答案
USB2.0 和 USB3.0 的速度区别是什么? USB2.0 和 USB3.0 在速度上有显著的区别。USB2.0 理论上的最高传输速度为 480Mbps,也就是 60MB/s 左右。而 USB3.0 的理论传输速度则可达到 5Gbps,即约 625MB/s ,这比 USB2.0 快了很多倍。 在实际应用中,USB2.0 通常用于一些对速度要求…...
即时通讯服务器被ddos攻击了怎么办?
攻击即时通讯系统的主要手段 击键记录 目前盗取即时通讯工具帐号信息的最主要方法是通过特洛伊木马等恶意软件,例如QQ木马,这类程序能够盗取QQ密码信息,常见的能够盗取最新版本QQ密码的木马程序有十几种之多。几乎所有主要的QQ木马程序都采…...
RTC QoS方法十三.(ReedSolomonFEC简介)
一、FlexFEC恢复的困局 在使用FlexFEC进行冗余的时候,经验值需要冗余5倍的丢包率,才能有比较高的恢复率。 Flex FEC在2D数组异或时能获得比较高的恢复率,但是如上图所示,25个包发送10个FEC包,成本为10/2540%的冗余度。…...
嵌入式开发工程师面试题 - 2024/11/24
原文嵌入式开发工程师面试题 - 2024/11/24 转载请注明来源 1.若有以下定义语句double a[8],*pa;int i5;对数组元素错误的引用是? A *a B a[5] C *(p1) D p[8] 解析: 在 C 或 C 语言中&am…...
《Shader入门精要》透明效果
代码以及实例图可以看github :zaizai77/Shader-Learn: 实现一些书里讲到的shader 在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道(Alpha Channel)。当开启透明混合后,当一个物体被渲染到屏幕上时&…...
一篇文章了解Linux
目录 一:命令 1 ls命令作用 2 目录切换命令(cd/pwd) (1)cd切换工作目录命令 3 相对路径、绝对路径和特殊路径 (1)相对路径和绝对路径的概念和写法 (2)几种特殊路径的表示符 (3)练习题: 4 创建目录命令&#x…...
创建字典时,键名不能是数字
4. 请问下面创建字典的 8 种方法中,哪几种是正确的。 >>> a {99:"吕布", 90:"关羽", 60:"刘备"}>>> b dict(99:"吕布", 90:"关羽", 60:"刘备")>>> c dict(99"吕布…...
架构-微服务-环境搭建
文章目录 前言一、案例准备1. 技术选型2. 模块设计3. 微服务调用 二、创建父工程三、创建基础模块四、创建用户微服务五、创建商品微服务六、创建订单微服务 前言 微服务环境搭建 使用的电商项目中的商品、订单、用户为案例进行讲解。 一、案例准备 1. 技术选型 maven&a…...