突破内存限制: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:构建亿级数据毫秒级查询的平民方案》中,我们…...
【排版教程】Word、WPS 分节符(奇数页等) 自动变成 分节符(下一页) 解决办法
毕业设计排版时,一般要求每章节的起始页为奇数页,空白页不显示页眉和页脚。具体做法如下: 1 Word 在一个章节的内容完成后,在【布局】中,点击【分隔符】,然后选择【奇数页】 这样在下一章节开始的时&…...
【在Linux世界中追寻伟大的One Piece】多线程(二)
目录 1 -> 分离线程 2 -> Linux线程互斥 2.1 -> 进程线程间的互斥相关背景概念 2.2 -> 互斥量mutex 2.3 -> 互斥量的接口 2.4 -> 互斥量实现原理探究 3 -> 可重入VS线程安全 3.1 -> 概念 3.2 -> 常见的线程不安全的情况 3.3 -> 常见的…...
flink学习(8)——窗口函数
增量聚合函数 ——指窗口每进入一条数据就计算一次 例如:要计算数字之和,进去一个12 计算结果为20, 再进入一个7 ——结果为27 reduce aggregate(aggregateFunction) package com.bigdata.day04;public class _04_agg函数 {public static …...
「实战应用」如何用图表控件LightningChart .NET实现散点图?(一)
LightningChart .NET完全由GPU加速,并且性能经过优化,可用于实时显示海量数据-超过10亿个数据点。 LightningChart包括广泛的2D,高级3D,Polar,Smith,3D饼/甜甜圈,地理地图和GIS图表以及适用于科…...
鸿蒙Native使用Demo
DevecoStudio使用Native 今天,给大家带来的是关于DevecoStudio中使用Native进行开发 个人拙见:为什么要使用Native?无论是JS还是TS在复杂的情况下运行速度,肯定不如直接操作内存的C/C的运行速度快,所以,会选择使用Native;这里面的过程是什么?通过映射转化,使用napi提供的接口…...
29.UE5蓝图的网络通讯,多人自定义事件,变量同步
3-9 蓝图的网络通讯、多人自定义事件、变量同步_哔哩哔哩_bilibili 目录 1.网络通讯 1.1玩家Pawn之间的同步 1.2事件同步 1.3UI同步 1.4组播 1.5变量同步 1.网络通讯 1.1玩家Pawn之间的同步 创建一个第三人称项目 将网络模式更改为监听服务器,即将房主作为…...
Scala—列表(可变ListBuffer、不可变List)用法详解
Scala集合概述-链接 大家可以点击上方链接,先对Scala的集合有一个整体的概念🤣🤣🤣 在 Scala 中,列表(List)分为不可变列表(List)和可变列表(ListBuffer&…...
【论文复现】偏标记学习+图像分类
📝个人主页🌹:Eternity._ 🌹🌹期待您的关注 🌹🌹 ❀ 偏标记学习图像分类 概述算法原理核心逻辑效果演示使用方式参考文献 概述 本文复现论文 Progressive Identification of True Labels for Pa…...
C嘎嘎探索篇:栈与队列的交响:C++中的结构艺术
C嘎嘎探索篇:栈与队列的交响:C中的结构艺术 前言: 小编在之前刚完成了C中栈和队列(stack和queue)的讲解,忘记的小伙伴可以去我上一篇文章看一眼的,今天小编将会带领大家吹奏栈和队列的交响&am…...
AIGC-----AIGC在虚拟现实中的应用前景
AIGC在虚拟现实中的应用前景 引言 随着人工智能生成内容(AIGC)的快速发展,虚拟现实(VR)技术的应用也迎来了新的契机。AIGC与VR的结合为创造沉浸式体验带来了全新的可能性,这种组合不仅极大地降低了VR内容的…...
Django 路由层
1. 路由基础概念 URLconf (URL 配置):Django 的路由系统是基于 urls.py 文件定义的。路径匹配:通过模式匹配 URL,并将请求传递给对应的视图处理函数。命名路由:每个路由可以定义一个名称,用于反向解析。 2. 基本路由配…...
《硬件架构的艺术》笔记(八):消抖技术
简介 在电子设备中两个金属触点随着触点的断开闭合便产生了多个信号,这就是抖动。 消抖是用来确保每一次断开或闭合触点时只有一个信号起作用的硬件设备或软件。(就是每次断开闭合只对应一个操作)。 抖动在某些模拟和逻辑电路中可能产生问…...
Spring 与 Spring MVC 与 Spring Boot三者之间的区别与联系
一.什么是Spring?它解决了什么问题? 1.1什么是Spring? Spring,一般指代的是Spring Framework 它是一个开源的应用程序框架,提供了一个简易的开发方式,通过这种开发方式,将避免那些可能致使代码…...
【算法】连通块问题(C/C++)
目录 连通块问题 解决思路 步骤: 初始化: DFS函数: 复杂度分析 代码实现(C) 题目链接:2060. 奶牛选美 - AcWing题库 解题思路: AC代码: 题目链接:687. 扫雷 -…...
如何选择黑白相机和彩色相机
我们在选择成像解决方案时黑白相机很容易被忽略,因为许多新相机提供鲜艳的颜色,鲜明的对比度和改进的弱光性能。然而,有许多应用,选择黑白相机将是更好的选择,因为他们产生更清晰的图像,更好的分辨率&#…...
Rust 力扣 - 740. 删除并获得点数
文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 首先对于这题我们如果将所有点数装入一个切片f中,该切片f中的i号下标表示所有点数为i的点数之和 那么这题就转换成了打家劫舍这道题,也就是求选择了切片中某个下标的元素后,该…...
OpenCV从入门到精通实战(七)——探索图像处理:自定义滤波与OpenCV卷积核
本文主要介绍如何使用Python和OpenCV库通过卷积操作来应用不同的图像滤波效果。主要分为几个步骤:图像的读取与处理、自定义卷积函数的实现、不同卷积核的应用,以及结果的展示。 卷积 在图像处理中,卷积是一种重要的操作,它通过…...
Docker核心概念总结
本文只是对 Docker 的概念做了较为详细的介绍,并不涉及一些像 Docker 环境的安装以及 Docker 的一些常见操作和命令。 容器介绍 Docker 是世界领先的软件容器平台,所以想要搞懂 Docker 的概念我们必须先从容器开始说起。 什么是容器? 先来看看容器较为…...
环形缓冲区
什么是环形缓冲区 环形缓冲区,也称为循环缓冲区或环形队列,是一种特殊的FIFO(先进先出)数据结构。它使用一块固定大小的内存空间来缓存数据,并通过两个指针(读指针和写指针)来管理数据的读写。当任意一个指针到达缓冲区末尾时,会自动回绕到缓冲区开头,形成一个"环"。…...
jQuery-Word-Export 使用记录及完整修正文件下载 jquery.wordexport.js
参考资料: jQuery-Word-Export导出word_jquery.wordexport.js下载-CSDN博客 近期又需要自己做个 Html2Doc 的解决方案,因为客户又不想要 Html2pdf 的下载了,当初还给我费尽心思解决Html转pdf时中文输出的问题(html转pdf文件下载之…...
云服务器部署WebSocket项目
WebSocket是一种在单个TCP连接上进行全双工通信的协议,其设计的目的是在Web浏览器和Web服务器之间进行实时通信(实时Web) WebSocket协议的优点包括: 1. 更高效的网络利用率:与HTTP相比,WebSocket的握手只…...
C#+数据库 实现动态权限设置
将权限信息存储在数据库中,支持动态调整。根据用户所属的角色、特定的功能模块,动态加载权限” 1. 数据库设计 根据这种需求,可以通过以下表设计: 用户表 (Users):存储用户信息。角色表 (Roles):存储角色…...
(原创)Android Studio新老界面UI切换及老版本下载地址
前言 这两天下载了一个新版的Android Studio,发现整个界面都发生了很大改动: 新的界面的一些设置可参考一些博客: Android Studio新版UI常用设置 但是对于一些急着开发的小伙伴来说,没有时间去适应,那么怎么办呢&am…...
Ubuntu24虚拟机-gnome-boxes
推荐使用gnome-boxes, virtualbox构建失败,multipass需要开启防火墙 sudo apt install gnome-boxes创建完毕~...
k8s rainbond centos7/win10 -20241124
参考 https://www.rainbond.com/ 国内一站式云原生平台 对centos7环境支持不太行 [lighthouseVM-16-5-centos ~]$ curl -o install.sh https://get.rainbond.com && bash ./install.sh 2024-11-24 09:56:57 ERROR: Ops! Docker daemon is not running. Start docke…...
SpringBoot+Vue滑雪社区网站设计与实现
【1】系统介绍 研究背景 随着互联网技术的快速发展和冰雪运动的普及,滑雪作为一种受欢迎的冬季运动项目,吸引了越来越多的爱好者。与此同时,社交媒体和在线社区平台的兴起为滑雪爱好者提供了一个交流经验、分享心得、获取信息的重要渠道。滑…...
MySql.2
sql查询语句执行过程 SQL 查询语句的执行过程是一个复杂的过程,涉及多个步骤。以下是典型的关系数据库管理系统 (RDBMS) 中 SQL 查询语句的执行过程概述: 1. 客户端发送查询 用户通过 SQL 客户端或应用程序发送 SQL 查询语句给数据库服务器。 2. …...
算法之区间和题目讲解
题干 难度:简单 题目分析 题目要求算出每个指定区间内元素的总和。 然而,区间在输入的最下面,所以按照暴力破解的思路,我们首先要遍历数组,把它的值都存进去。 然后,遍历下面的区间,从索引a…...
价格分类(神经网络)
# 1.导入依赖包 import timeimport torch import torch.nn as nn import torch.optim as optimfrom torch.utils.data import TensorDataset, DataLoader from sklearn.model_selection import train_test_splitimport numpy as np import pandas as pd import matplotlib.pypl…...
南通网站制作维护/互联网全网推广
类集中提供了以下几种接口: 1.单值操作接口:conllection,List,Set list和set是conllection接口的子接口 2.一对值的操作接口:Map 3.排序的操作接口:SortedMap, SortedSet 4.输出的接口:Iterator, ListIterator, Enumeration 5.队列…...
网站项目报价单模板免费下载/舆情信息在哪里找
在使用PCA和NFC中有三个函数fit,fit_transform,transform区分不清各自的功能。通过测试,勉强了解各自的不同,在这里做一些笔记。 1.fit_transform是fit和transform的混合,相当于先调用fit再调用transform。 2.transf…...
自己做传奇网站/宁波seo关键词优化制作
STS介绍Spring Tool Suite(sts)就是一个基于Eclipse的开发环境, 用于开发Spring应用程序。它提供了一个现成的使用环境来实现, 调试, 运行, 和部署你的Spring应用程序。包括为关键的的服务器和云计算,Git, Maven, Aspe…...
怎么做中英文网站/seo案例分析
struts2.0 hibernate oracle 分页问题 最近弄了下 struts2.0 hibernate oracle 分页问题的 从网上搜了些资料。总觉得不是很合心意。自己做了例子。 ueser.sql Sql代码 DROP TABLE "SCOTT"."T_USER" cascade constraints; DROP SEQUENCE "…...
建设网站电脑配置/百度推广工具
练习 2.1: 向tempconv包添加类型、常量和函数用来处理Kelvin绝对温度的转换,Kelvin 绝对零度是−273.15C,Kelvin绝对温度1K和摄氏度1C的单位间隔是一样的 package tempconvimport "fmt"type Celsius float64 type Fahrenheit float…...
天津手机网站建设制作/广州seo推广
文章目录📂 第二章、程序语言基础知识 📁 2.1 程序语言概述 📖 2.1.1 程序语言的基本概念 📖 2.1.2 程序语言的基本成分 📁 2.2 程序语言翻译基础 📖 2.2.1 汇编程序基本原理 📖 2.2.2 编译程序…...