Strömmande pipelines och namngivna pipes för genomströmning
Använd FIFO:er och processubstitution för att strömma data mellan steg utan mellanliggande filer.
Strömmande pipelines och namngivna pipes för genomströmning är en gratis lektion i DevOps-bootcamp på CoddyKit. Detta är lektion 4 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för DevOps-bootcamp, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i DevOps-bootcamp innehåller totalt 4 lektioner.
Varför mellanliggande filer försämrar genomströmningen
När ni kedjar kommandon som sort file.txt > tmp.txt && uniq tmp.txt > result.txt betalar ni en dold kostnad: diskskrivningar, diskläsningar och en pipeline som står stilla tills det första steget har slutförts helt innan nästa börjar.
Pipeline:er som strömmar eliminerar den kostnaden. Data flödar direkt från producent till konsument i minnet, steg för steg och samtidigt. Detta är grundidén bakom Unix-rör — och namngivna rör (FIFO:er) bygger vidare på den.
- Anonymt rör (
|): kopplar samman två intilliggande kommandon på samma skalrad. - Namngivet rör (FIFO): en särskild fil i filsystemet som låter oberoende processer strömma data till varandra.
- Processubstitution: låter ett kommando behandla utdata från ett annat kommando som om den vore en fil.
I den här lektionen får ni se hur alla tre kan användas för att maximera genomströmningen i Bash-arbetsflöden i verkligheten.
En streaming-pipelines uppbyggnad
Ett anonymt rör kopplar stdout från en process till stdin för nästa. Kärnan håller båda processerna igång samtidigt i en buffert i minnet med fast storlek (vanligen 64 KB i Linux).
Den viktiga insikten är att pipelinen är lika snabb som sitt långsammaste steg. Om producenten är snabbare blockeras den när bufferten är full. Om konsumenten är snabbare blockeras den när bufferten är tom. Detta mottryck är kostnadsfri och automatisk flödeskontroll.
Exemplet nedan räknar unika IP-adresser i en stor åtkomstlogg utan att någonsin skriva en temporär fil. Alla steg körs samtidigt:
#!/usr/bin/env bash
# Stream a 2 GB access log — all stages run in parallel
grep '"GET' /var/log/nginx/access.log \
| awk '{print $1}' \
| sort \
| uniq -c \
| sort -rn \
| head -20Skapa namngivna rör med mkfifo
Ett namngivet rör (FIFO — First In, First Out) skapas med mkfifo. Det visas i filsystemet som en vanlig fil, men data som skrivs till det lagras aldrig på disken — den flödar direkt till processen som läser.
Viktiga beteenden att komma ihåg:
- En skrivning till en FIFO blockeras tills en läsare öppnar den, och omvänt.
- FIFO-posten finns kvar i filsystemet; ni måste ta bort den med
rmnär ni är klara. - Flera skrivare är tillåtna, men ordningen mellan dem kan inte garanteras.
Nedan komprimerar en producent data till en FIFO medan en konsument laddar upp den till S3 samtidigt — ingen temporär fil behövs.
#!/usr/bin/env bash
mkfifo /tmp/stream_pipe
# Producer: compress in background
gzip -c /var/log/syslog > /tmp/stream_pipe &
# Consumer: read from FIFO (runs in foreground)
wc -l < /tmp/stream_pipe
wait
rm /tmp/stream_pipeProcessubstitution: behandla ett kommando som en fil
Processubstitution använder syntaxen <(command) eller >(command). Bash skapar i bakgrunden en FIFO (eller en fildeskriptor för /dev/fd/N) och skickar sökvägen till det yttre kommandot.
Detta är kraftfullt när ett verktyg förväntar sig ett argument med ett filnamn i stället för stdin. Utan processubstitution skulle ni behöva en temporär fil; med processubstitution strömmar ni data direkt.
<(cmd)— det yttre kommandot läser från cmd:s utdata.>(cmd)— det yttre kommandot skriver till cmd:s indata.
#!/usr/bin/env bash
# diff two sorted streams without creating temp files
diff <(sort /etc/passwd) <(sort /etc/group)
# Compare live command output against a baseline
diff <(ls /usr/bin | sort) <(cat ~/bin_baseline.txt | sort)Tee: dela upp en ström till flera konsumenter
tee läser från stdin och skriver till både stdout och en eller flera filer. Tillsammans med processubstitution kan ni förgrena en enda ström till flera bearbetningspipeline:er samtidigt — helt utan att använda disken.
Detta mönster är användbart när ni till exempel vill logga rådata och bearbeta den samtidigt.
#!/usr/bin/env bash
# Generate 100000 random numbers, then simultaneously:
# 1. compute the sum
# 2. find the maximum
# 3. count lines (saved to a variable)
seq 1 100000 \
| tee >(awk '{s+=$1} END{print "Sum:", s}') \
>(awk 'BEGIN{m=0} $1>m{m=$1} END{print "Max:", m}') \
| wc -l | xargs echo "Count:"Förgreningsmönstret: en producent, många konsumenter
När en enda datakälla ska mata flera oberoende konsumenter kombinerar ni tee med flera processubstitutioner av typen >(). Varje konsument får hela strömmen och körs samtidigt.
Detta gör att källfilen inte behöver läsas flera gånger. För en fil på 10 GB är skillnaden enorm — en diskläsning i stället för N läsningar.
#!/usr/bin/env bash
# Read a large CSV once; simultaneously:
# - count rows
# - extract column 2 to a file
# - pass column 3 to a stats script
cat large_data.csv \
| tee \
>(wc -l > /tmp/row_count.txt) \
>(cut -d',' -f2 > /tmp/col2.txt) \
>(cut -d',' -f3 | awk '{sum+=$1} END{print sum}' > /tmp/col3_sum.txt) \
> /dev/null
echo "Rows:" $(cat /tmp/row_count.txt)
echo "Col3 sum:" $(cat /tmp/col3_sum.txt)Sammanföringsmönstret: många producenter, en konsument
Motsatsen till förgrening är sammanföring: flera oberoende källor strömmar data till en enda konsument. Namngivna FIFO:er gör detta enkelt.
Ett vanligt användningsfall är att slå samman loggströmmar från flera servrar i realtid eller att samla delresultat från parallella arbetare.
Observera att konsumenten ser sammanflätad utdata när det finns flera skrivare — det fungerar bra för radorienterade data där varje rad är självständig, men om ordningen är viktig måste ni hantera den själva.
#!/usr/bin/env bash
mkfifo /tmp/fanin_pipe
# Three producers write concurrently into the same FIFO
for host in web1 web2 web3; do
ssh "$host" 'tail -n 500 /var/log/app.log' > /tmp/fanin_pipe &
done
# Single consumer reads all merged output
grep 'ERROR' /tmp/fanin_pipe | sort | uniq -c | sort -rn
wait
rm /tmp/fanin_pipeAnvända mkfifo för parallell komprimering
Ett av de mest praktiska användningsområdena för FIFO:er är parallell komprimering. Verktyg som pigz (parallell gzip) eller pbzip2 läser en ström; ni kan skicka rådata direkt genom en pipeline utan att först skapa en okomprimerad fil.
Mönstret nedan arkiverar en katalog, komprimerar den med alla CPU-kärnor och strömmar resultatet till en fjärrvärd — allt samtidigt:
#!/usr/bin/env bash
# Tar + parallel compress + stream to remote — no temp files
# Requires: pigz (parallel gzip)
tar cf - /data/large_dir \
| pigz -p 4 \
| ssh backup-host 'cat > /backups/large_dir.tar.gz'
# Verify the remote file exists
ssh backup-host 'ls -lh /backups/large_dir.tar.gz'Styra buffertstorlek och blockering
Rör har en buffert i kärnan (vanligen 64 KB). När bufferten är full blockeras skrivaren; när den är tom blockeras läsaren. Detta är vanligtvis vad ni vill, men i vissa fall kan blockeringen orsaka ett dödläge.
Risk för dödläge: om process A skriver till FIFO1 och läser från FIFO2, medan process B skriver till FIFO2 och läser från FIFO1, kan båda blockeras i väntan på att den andra ska läsa först.
Lösningar:
- Kör minst den ena sidan i bakgrunden (
&) så att den inte blockerar skalet. - Använd
mbufferellerpvför att lägga till en större buffert i minnet mellan stegen. - Använd
pv -q -B 128mför att lägga in en buffert på 128 MB och jämna ut tillfälliga genomströmningsökningar.
#!/usr/bin/env bash
# pv adds a 64 MB buffer and shows throughput
# Useful when producer and consumer have bursty speeds
dd if=/dev/urandom bs=1M count=200 \
| pv -B 64m \
| gzip \
| wc -cPraktiskt exempel: loggaggregator i realtid
Här är ett komplett och realistiskt mönster: följ flera loggfiler, slå samman strömmarna genom ett namngivet rör, filtrera efter fel och skriv en sammanfattning i realtid — allt utan mellanliggande filer och med alla steg körande parallellt.
Detta är den typ av pipeline som skulle köras som ett övervakningsskript i bakgrunden på en produktionsserver.
#!/usr/bin/env bash
FIFO=/tmp/log_aggregator
mkfifo "$FIFO"
cleanup() { rm -f "$FIFO"; }
trap cleanup EXIT INT TERM
# Fan-in: tail multiple logs into the FIFO
tail -F /var/log/syslog /var/log/auth.log > "$FIFO" &
TAIL_PID=$!
# Consumer: filter and timestamp errors in real time
grep --line-buffered -i 'error\|fail\|crit' "$FIFO" \
| while IFS= read -r line; do
printf '[%s] %s\n' "$(date '+%H:%M:%S')" "$line"
done
kill "$TAIL_PID" 2>/dev/nullJämföra pipeline:er med temporära filer
Ni kan mäta den faktiska skillnaden i genomströmning mellan metoderna med strömning och temporära filer med time. Pipeline-metoden vinner på stora datamängder eftersom:
- Stegen körs samtidigt — CPU och I/O överlappar.
- Ingen disk-I/O behövs för mellanliggande data — endast det slutliga resultatet skrivs till disken.
- Minnesåtgången förblir konstant oavsett indatafilens storlek (data strömmas i stället för att buffras).
En enkel benchmark för att jämföra de båda metoderna:
#!/usr/bin/env bash
# Approach 1: Temp file (sequential)
time bash -c '
seq 1 5000000 > /tmp/nums.txt
sort -n /tmp/nums.txt > /tmp/sorted.txt
uniq /tmp/sorted.txt | wc -l
rm /tmp/nums.txt /tmp/sorted.txt
'
echo '---'
# Approach 2: Streaming pipeline (concurrent)
time bash -c 'seq 1 5000000 | sort -n | uniq | wc -l'Kunskapskontroll: blockeringsbeteende hos namngivna rör
Betrakta följande skript:
mkfifo /tmp/mypipe
echo 'hello' > /tmp/mypipe
echo 'done'Vad händer när skriptet körs utan bakgrundsprocesser eller läsare?
Repetition: strömningspipelines och namngivna pipes
I den här lektionen har Ni utforskat hur data kan flyttas effektivt mellan processer utan mellanliggande filer:
- Anonyma pipes (
|) kopplar samman intilliggande kommandon och kör alla steg samtidigt med automatisk backpressure. - Namngivna pipes (
mkfifo) skapar en FIFO-post i filsystemet som låter orelaterade processer eller bakgrundsprocesser strömma data till varandra — skrivningar blockeras tills en läsare finns. - Processubstitution (
<(cmd),>(cmd)) gör att kommandon som förväntar sig filnamn transparent kan läsa från eller producera strömmar. tee+>()förgrenar en ström till flera samtidiga konsumenter utan att källan behöver läsas igen.- Fan-in sammanfogar flera producenter till en konsument via en gemensam FIFO.
- Backpressure och blockering är funktioner, inte buggar — men kör alltid minst ena sidan av ett FIFO-par i bakgrunden för att undvika dödläge.
- Använd
pvellermbufferför att lägga till större buffertar och övervaka genomströmningen när stegen arbetar i ryck.
Dessa tekniker utgör grunden för Bash-baserad datahantering med hög genomströmning: bearbeta data i GB-skala med konstant minnesanvändning och maximal parallellitet för CPU och I/O.
Lär dig DevOps-bootcamp med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 142
- Lektioner
- 568
Vanliga frågor
Är lektionen ”Strömmande pipelines och namngivna pipes för genomströmning” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen DevOps-bootcamp, inklusive ”Strömmande pipelines och namngivna pipes för genomströmning”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i DevOps-bootcamp innehåller totalt 4 lektioner.
Vad lär jag mig i ”Strömmande pipelines och namngivna pipes för genomströmning”?
Använd FIFO:er och processubstitution för att strömma data mellan steg utan mellanliggande filer. Ni övar på DevOps-bootcamp med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig DevOps-bootcamp?
Du behöver inga förkunskaper. Utbildningen i DevOps-bootcamp på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.
Hur lång tid tar lektionen ”Strömmande pipelines och namngivna pipes för genomströmning”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här DevOps-bootcamp-lektionen?
Ja. Varje DevOps-bootcamp-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Profilera skript och undvik onödiga subshells
- Parallellism med xargs -P och bakgrundsjobb
- Orkestrera arbetsbelastningar med GNU parallel
- Strömmande pipelines och namngivna pipes för genomströmning