ben de bir sürü insan gibi "openclaw" için bir Mac Mini aldım (lol).
geçen sene birkaç gün boyunca local LLM'lerin değerini abarttım ve sebepsiz birkaç bin dolar harcadım. ama işe yaradı: subagent'lar + daha ağır MCP client'larıyla Mac Mini sürekli açık duran local build makinem oldu, çoğu zaman MacBook'tan "vibe code" yapıp ona atıyorum.
problem: macOS'ta SMB üzerinden dosya paylaşımı büyük dosyalarda fena değil ama küçük dosyalarla dolu dev ağaçlarında (TypeScript, config, node_modules) acı verici yavaş. "canlı dosya sistemi" kısmını NFS'e geçirdim ve hem LAN'da hızlı hem de MacBook LAN'dan çıktığında sağ kalacak hâle gelene kadar tuneladım — işin zor yarısı burası oluyor ve NFS-on-macOS bloglarının çoğu tam bu kısımda yanılıyor.
bu workload için neden SMB yerine NFS
macOS'ta SMB küçük-dosya workload'larında zorlanıyor çünkü:
- Finder ve arkadaşları fazladan metadata işi yapıyor (extended attribute'lar dahil)
- SMB'de per-operation overhead daha yüksek (ve macOS'un implementation'ı "60k tiny files" için her zaman optimize hissettirmiyor)
- dizin listeleme bir sürü küçük round-trip'e dönüşüyor
NFS daha basit. benim LAN'ımda tuned NFS "büyük dizinleri listeleme"yi "bu niye bu kadar sürüyor"dan "tamam, kullanılabilir"e taşıdı.
test ettiğim setup
- server: Mac Mini (apple silicon), kablolu LAN,
192.168.1.200 - client: MacBook (macOS), aynı network, LAN'a girip çıkıyor
- workload: ~60,000 dosya / ~8GB, çoğunluk TypeScript + config + node_modules
- rtt: ~4ms (Wi-Fi → switch → ethernet)
hiçbir ayarı kurcalamadan önce client profilini seç
aynı "NFS client" etiketinin altında tamamen farklı iki reçete var:
- kablolu workstation — sürekli açık, kablolu ethernet, hareket etmiyor, kapağı kapanmıyor. bir şey kaybolmadığı için agresif davranabilirsin.
- mobil laptop — uyuyor, network değiştiriyor, Wi-Fi olmayan odalara giriyor. client tarafındaki her knob server'ın kesin kaybolacağını varsaymak zorunda.
blogların çoğu workstation ayarlarını öneriyor ve dosyayı kapatıyor. bu ayarlar laptop'ta Raycast'i crash ettiriyor, Finder'ı beachball'a sokuyor ve launchd'nin Wi-Fi'ına dakikada bir saldırmasına yol açıyor. server tuning ikisi için de aynı; yol client tarafında ayrılıyor.
server (Mac Mini): exports + nfsd tuning
/etc/exports
önemli olanlar:
-alldirs: sadece export kökünü değil, alt dizinleri de mount edebiliyorsun-mapall=501:20: client erişimlerinin hepsini tek bir local uid/gid'e mapliyor (tek-kullanıcılı dev için rahat)-network ... -mask ...: erişimi local subnet'inle sınırlıyor
not: 501:20 macOS'ta yaygın (ilk user + staff), ama garanti değil. kendi uid/gid'ini id -u / id -g ile al.
/etc/nfs.conf (server)
kısa "neden" tablosu:
| parametre | default | değer | neden |
|---|---|---|---|
| require_resv_port | 1 | 0 | macOS client'ları sık sık non-privileged portlardan mount ediyor; sessiz mount sıkıntısını engelliyor |
| nfsd_threads | 8 | 16 | bol küçük-dosya operasyonu için daha fazla concurrency |
| async | 0 | 1 | daha hızlı write; git'in source of truth olduğu dev için uygun |
| fsevents | 1 | 0 | server tarafı overhead'i azalıyor |
| wg_delay / wg_delay_v3 | 1000 / 0 | 0 / 0 | küçük-dosya write'larında daha düşük latency |
| reqcache_size | 64 | 512 | retransmit sırasında duplicate-request'leri daha iyi yönetiyor |
| request_queue_length | 128 | 512 | burst'lerde queue bottleneck'i engelliyor |
| export_hash_size | 64 | 256 | yüklü anda daha hızlı export lookup |
| bonjour | 1 | 0 | zaten IP ile bağlanıyorum |
daemon'u aç:
client — kablolu workstation profili
/Volumes/yigitkonur altında mount et, agresif tuning ve hard mount'larla. bu profil server'ın asla yokolmadığını varsayıyor.
/etc/auto_nfs
/etc/auto_master
sona ekle (yoksa auto_nfs es geçiliyor):
uygula:
/etc/nfs.conf (client)
nfs.client.is_mobile = 0 ekleme. kablolu makinede bile auto doğru default — burada kapalıya zorlamanın sana bir kazancı yok ve reçeteyi bir gün laptop'a taşırsan felaket oluyor.
önemli mount option'lar
| option | neden |
|---|---|
| vers=3 | macOS'ta NFSv3 en stabil olanı. NFSv4 (macOS 4.0'ı destekliyor, 4.1'i değil) sürümler arası sallantılı |
| hard,intr | hard mount rastgele I/O hatasıyla düşmüyor; intr takılan op'ları ctrl+c ile kırmana izin veriyor |
| noresvport | "macOS'ta NFS niye mount olmuyor" sorununun sık çözümü |
| nfc | macOS'ta unicode normalization doğruluğu |
| locallocks | NLM overhead'ini ve bayat lock sorunlarını engelliyor |
| nonegnamecache | dosya akışında hayalet ENOENT'leri engelliyor |
| rsize / wsize | daha büyük buffer, büyük read/write'larda daha az gidip-gelme |
| noatime | read'lerde write RPC'sini engelliyor |
| actimeo=10 | daha az metadata RPC; dev için hâlâ makul freshness |
| rdirplus | büyük dizinlerde büyük kazanç: attribute'ları dizin entry'leriyle birlikte getiriyor |
en büyük kazanç veren knob'lar (workstation)
| parametre | default | değer | neden |
|---|---|---|---|
| nfs.client.access_for_getattr | 0 | 1 | tek başına en büyük perf kazancı: permission check'leri getattr çağrılarına gömüyor (daha az RPC spam'i) |
| nfs.client.nfsiod_thread_max | 16 | 32 | bol küçük dosya için daha fazla eşzamanlı I/O |
| nfs.client.allow_async | 0 | 1 | async mount option'ının gerçekten bir işe yaramasını sağlıyor |
client — laptop profili (gerçekten çalıştırdığım)
workstation reçetesinden dört şey değişiyor. dördü de önemli.
1. mount path: ~/mnt/mini, /Volumes/bir-şey değil.
laptop'ta tek başına en etkili değişiklik bu. /Volumes'i Finder, Spotlight, Raycast, Dock, LaunchServices, Time Machine ve kurduğun her backup tool'u sürekli tarıyor. /Volumes altında takılan bir mount bu takılmayı hepsine yayıyor — Raycast crash ve Finder beachball buradan geliyor. ~/mnt/ altındaki takılı mount sadece oraya elle giren process'leri etkiliyor.
2. mount option'ları: hard,intr'ı koru, kısa timeo + retrans ekle, nobrowse ekle, deadtimeout'u at.
hard,intr data integrity'yi koruyor ve takılan interactive op'ları ctrl+c ile kırmana izin veriyor. asıl değişiklik kısa timeo=30,retrans=3 (RPC başına ~90s budget): server ölüyse process'ler mount'tan saniyeler içinde sekip çıkıyor, deadtimeout=600'ün sattığı 10 dakika yerine. nobrowse ise Finder'ın mount'u listelemesini tamamen engelliyor — her ihtimale karşı, bir gün yine de /Volumes altına koyarsın diye.
3. /etc/nfs.conf (client) — workstation bloğunun aynısı, ama nfs.client.is_mobile'ı kasıtlı olarak hiç ellemiyorsun.
macOS default'u (auto) "laptop'ta yanıtsız network volume'ü otomatik unmount et" davranışını açıyor. 0'a çekmek o güvenlik ağını kapatıyor — disconnect'te yaşanan beachball'ın kökü bu ve "NFS on Mac" bloglarının çoğu bu yüzden LAN'da hızlı, LAN dışında kullanılmaz bir makine üretiyor. default'ta bırak. satırı dosyaya hiç koyma.
4. reconnect LaunchDaemon yok. asla.
server'ı 30–60s'de bir pingleyen StartInterval daemon, Console.app'ini sonsuza kadar "attaching network" event'leriyle dolduran şey — evde ya da kafede fark etmiyor. laptop'ta asla doğru şekil değil. iki alternatif:
on-demand automount — ~/mnt/mini'ye erişince mount tetikleniyor, idle kaldıkça unmount oluyor:
/etc/auto_mini:
/etc/auto_master (sona ekle):
uygula:
ya da elle — share'i gerçekten istediğinde çalıştırdığın küçük bir mount-mini:
istediğin zaman çalıştırıyorsun. senin LAN'ınla alakası olmayan kafe Wi-Fi'ındayken çalıştırmıyorsun.
kapatabileceğin opsiyonel macOS overhead'leri
Gatekeeper'ın quarantine'ini "perf tweak" diye kapatma. bazı reçeteler defaults write com.apple.LaunchServices LSQuarantine -bool NO öneriyor. o flag NFS knob'u değil — tüm indirilen dosyalar için, her yerde quarantine prompt'unu kapatıyor. perf kazancı gürültü seviyesinde; security etkisi değil. pas geç.
security: bunu havada bırakma
NFSv3 + sec=sys uid/gid ile authenticate ediyor. encryption yok, signing yok, Kerberos yok. dürüst threat model: LAN'ında 501 uid'ini spoof edebilen her makine (kontrolündeki her Mac'te trivial) export ettiğin home dizinindeki her dosyayı okuyup yazabilir.
sadece senin cihazlarının olduğu kablolu ev network'ünde sorun yok. guest Wi-Fi, aynı subnet'te IoT cihazları, ev arkadaşı ya da coworking'e benzeyen herhangi bir yer varsa durum başka. share'i kilitsiz bir git remote gibi düşün — kimse aynı telin üstünde olmadığı için işe yarıyor.
reboot-safe hâle getirme
server tarafı (Mac Mini) — sürekli açık, kablolu, hareket etmiyor
opsiyonel: daemon çakarsa geri gelsin diye küçük bir watchdog.
root crontab:
client tarafı (MacBook) — mobil, dolaşıyor
hiçbir şey. LaunchDaemon yok, cron yok, polling yok. yukarıdaki automount direct map "erişince mount et, idle kalınca unmount et" işini retry loop'u olmadan hallediyor. cd ~/mnt/mini yaparken LAN orada değilse, Raycast ve Finder'ı beraberinde götüren 10 dakikalık hang yerine saniyeler içinde mount hatası alıyorsun.
asıl ders: NFS mount üzerinden rsync yapma
önce şaşırdım ama küçük dosyalarda matematik affetmiyor:
60.000 dosya için asıl iş başlamadan önce sadece protokol overhead'ine dakikalar ödüyorsun. toplu transferde stream'le:
bende: 60.000 dosya 1 dk 57 sn. rsync-over-nfs yanından bile geçmedi.
helper:
benchmark özeti
sağlıklı LAN, tuning pass'lerinde aynı test suite:
| test | original | tuning sonrası | research sonrası | toplam kazanç |
|---|---|---|---|---|
| 1000 dosya oluştur (1–10KB) | 101.7s (9/s) | 84.3s (11/s) | 61.9s (16/s) | +78% |
| 1000 dosya oku | 25.1s (39/s) | 20.2s (49/s) | 10.3s (97/s) | +149% |
| 1000 dosya stat | 2.8s (363/s) | 1.9s (533/s) | 1.9s (535/s) | +47% |
| 500 dosya overwrite | 31.3s (15/s) | 18.8s (26/s) | 10.5s (47/s) | +213% |
| ls -la (1000 dosya) | 42.3s | 7.5s | 4.4s | 9.6x |
sağlıklı LAN'da en büyük katkıyı yapanlar:
nfs.client.access_for_getattr = 1actimeo=10+rdirplus(metadata verimliliği)- zaman zaman gelen büyük dosya için daha büyük
rsize/wsize
bu tabloda olmayan sayı, LAN gittiğinde laptop'un kullanılabilir kalıp kalmayacağını belirliyor: "server erişilemezken mount'ta ls". laptop'a naif workstation ayarlarıyla (is_mobile=0, hard,intr,deadtimeout=600, /Volumes altında mount) gittiğinde on dakikalık beachball. yukarıdaki laptop profiliyle birkaç saniye ENOENT ve yoluna devam ediyorsun.
macOS'ta NFSv3 vs NFSv4: v4'e bulaşma
- macOS NFSv4.0'ı destekliyor, 4.1'i değil
vers=4.1zaten genelde v3'e düşüyorvers=4, bazı Sonoma / Sequoia sürümlerinde regresyonlu- tuned v3 dev workload'ları için zaten yeterince iyi
NFS vs SMB vs alternatifler
| protokol | küçük-dosya perf | kurulum zorluğu | laptop-dostu | macOS desteği |
|---|---|---|---|---|
| NFS (tuned) | iyi | orta | laptop profiliyle evet | v3 ile stabil |
| SMB | küçük dosyalarda zayıf | kolay | evet (built-in reconnect) | var ama çoğu zaman hantal |
| SSHFS | orta | kolay | evet | proje durumu değişken |
| Mutagen | çoğunlukla güçlü | orta | evet | aktif geliştirme |
| Syncthing | asenkron sync | kolay | evet | iyi |
kullandığım perf test script'i
/tmp/nfs-perftest.sh içine koy (NFS_TARGET'ı kendi mount'unun içine ayarla):
appendix: Craft.do'ya API üzerinden post atıyorsan (markdown'ı otomatik güvene al)
üç-tırnak code fence'li "github-flavored" versiyonun varsa, POST atmadan önce fence'li kod bloklarını indent'li kod bloklarına çevirerek Craft.do-safe markdown'a dönüştürebilirsin. jq filter'ı:
yollayacağın markdown string'inde çalıştır (tek geçişli jq; shell variable'ına sokup round-trip yaptırma).
tldr
- macOS'ta küçük dosyalarda SMB yavaş hissettiriyorsa NFSv3 dene — server tuning herkes için aynı, client tuning'de yollar şekle göre ayrılıyor
- server tarafı:
require_resv_port=0,nfsd_threads=16,async=1, sadece TCP - workstation client:
/Volumes/*,hard,intr,actimeo=10,rdirplus, automount direct map - laptop client:
~/mnt/*, aynı option'lar artıtimeo=30,retrans=3,nobrowse,nfs.client.is_mobile'ı default'ta bırak, reconnect LaunchDaemon yok - en büyük perf knob'u
nfs.client.access_for_getattr = 1; laptop'ta en tehlikeli ayarnfs.client.is_mobile = 0 - Gatekeeper'ın
LSQuarantine'ini "perf tweak" diye kapatma - NFSv3 +
sec=syssadece uid/gid auth'u; share'i güvenilir subnet'te tut - toplu kopya için mount üzerinden rsync değil,
tar | sshkullan