現(xiàn)智慧園區(qū)視頻接入與自動(dòng)運(yùn)維管理)
管理一整套智慧園區(qū)的視頻接入最怕的不是攝像頭壞而是幾十路視頻流沒有統(tǒng)一管理手段。早些年我做園區(qū)項(xiàng)目時(shí)經(jīng)常是登錄服務(wù)器手工敲 FFmpeg 命令一臺(tái)一臺(tái)拉流遇到攝像頭掉線還得靠業(yè)務(wù)方反饋“畫面黑了”才知道出了問題。后來我把這套流程整理成了批量部署腳本用配置文件維護(hù)攝像頭清單一條命令啟動(dòng)、一條命令停止、一條命令看狀態(tài)斷線還能自動(dòng)拉起。這個(gè)方法不挑環(huán)境只要 Linux 服務(wù)器上有 FFmpeg 就能跑特別適合園區(qū)弱電運(yùn)維、安防集成商以及自己搭視頻中臺(tái)或數(shù)字孿生底座的開發(fā)團(tuán)隊(duì)?,F(xiàn)在把這個(gè)方案完整梳理一遍包括為什么要這么設(shè)計(jì)、腳本里每個(gè)模塊怎么實(shí)現(xiàn)、實(shí)際部署會(huì)踩到哪些坑一次性講清楚。1. 場(chǎng)景認(rèn)知與方案設(shè)計(jì)1.1 智慧園區(qū)視頻接入到底難在哪智慧園區(qū)的視頻接入跟“在監(jiān)控室看錄像”完全不是一回事。園區(qū)建設(shè)智慧化系統(tǒng)時(shí)視頻往往要接到自建的流媒體服務(wù)器、三維可視化平臺(tái)、AI 分析盒子或者對(duì)接第三方平臺(tái)。攝像頭分布在園區(qū)各個(gè)角落品牌也不統(tǒng)一海康、大華、宇視、雄邁都可能出現(xiàn)RTSP 地址格式五花八門碼率分辨率也各有差異。最直接的辦法是用 FFmpeg 把每臺(tái)攝像頭的 RTSP 流拉過來轉(zhuǎn)成 RTMP 推到流媒體服務(wù)或者切成 HLS 給網(wǎng)頁端播放再或者落盤錄制。這里就暴露出三個(gè)典型痛點(diǎn)。第一攝像頭數(shù)量多手動(dòng)啟動(dòng)進(jìn)程根本不現(xiàn)實(shí)。二十個(gè)攝像頭你還能一條條復(fù)制命令五六十個(gè)的時(shí)候光是核對(duì) IP、密碼、碼流路徑就夠頭疼。第二進(jìn)程掛在后臺(tái)之后沒人知道它什么時(shí)候退出。攝像頭偶發(fā)斷網(wǎng)、流媒體服務(wù)器重啟、磁盤寫滿任何一個(gè)原因都會(huì)讓 FFmpeg 進(jìn)程悄無聲息地消失。第三攝像頭短時(shí)無響應(yīng)時(shí)FFmpeg 進(jìn)程可能一直卡在 TCP 連接上既不退出也不產(chǎn)出數(shù)據(jù)看起來還活著實(shí)際畫面已經(jīng)全黑。所以我需要的不只是一堆啟動(dòng)命令而是一套“配置化管理工具”所有攝像頭信息集中在一個(gè)配置文件內(nèi)啟動(dòng)程序負(fù)責(zé)把所有流全部拉起停止程序負(fù)責(zé)安全退出監(jiān)控程序定期檢查運(yùn)行狀態(tài)發(fā)現(xiàn)掉線就自動(dòng)拉起。這套思路跟 Kubernetes 管理容器有點(diǎn)像攝像頭 RTSP 流就是“工作負(fù)載”腳本就是控制面負(fù)責(zé)維持期望狀態(tài)。只是我不需要那么重的平臺(tái)Shell 腳本足夠。1.2 為什么最終敲定 FFmpeg Shell 的組合市面上有 Zabbix、Prometheus、夜鶯、Grafana 這些監(jiān)控平臺(tái)也有專門的視頻監(jiān)控軟件但把它們用在“管理 FFmpeg 推流進(jìn)程”這個(gè)場(chǎng)景多少有點(diǎn)殺雞用牛刀。監(jiān)控平臺(tái)解決的是資源指標(biāo)和告警比如 CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)流量但攝像頭推流場(chǎng)景的核心監(jiān)控對(duì)象是“進(jìn)程在不在、鏈路通不通、數(shù)據(jù)動(dòng)不動(dòng)”這些用腳本就能準(zhǔn)確判斷。而且大部分園區(qū)視頻服務(wù)器都是內(nèi)網(wǎng)隔離環(huán)境裝一套 Prometheus 全家桶還要維護(hù)抓取配置對(duì)弱電運(yùn)維而言負(fù)擔(dān)不小。FFmpeg 加 Shell 的優(yōu)勢(shì)是它足夠輕、足夠直白。部署時(shí)只要拷貝腳本目錄、裝好 FFmpeg 就行不依賴數(shù)據(jù)庫、不依賴 Web 服務(wù)出問題也能直接看腳本邏輯定位。有人可能會(huì)問直接用 Python 寫不是更優(yōu)雅在實(shí)際生產(chǎn)環(huán)境里Python 版本、第三方庫、虛擬環(huán)境管理反而比 Shell 更容易出狀況。Shell 腳本在絕大多數(shù) Linux 發(fā)行版上都能直接執(zhí)行而且和 systemd、cron 等工具銜接自然哪怕?lián)Q一臺(tái)服務(wù)器也能快速部署。所以這個(gè)方案不是我拍腦袋選的是在多個(gè)園區(qū)項(xiàng)目里迭代驗(yàn)證過的結(jié)果。2. 配置設(shè)計(jì)與腳本架構(gòu)2.1 用一份 cameras.conf 管住所有攝像頭整套腳本的核心不是代碼而是那份攝像頭配置文件。我把所有接入信息抽出來放在cameras.conf里每行一臺(tái)攝像頭用豎線分隔字段。這樣做的好處是后期新增或者減少攝像頭運(yùn)維人員只需要改這一份文件完全不需要碰腳本代碼。配置格式定義如下# 攝像頭清單 # 格式: ID|RTSP源地址|輸出模式|輸出目標(biāo)|錄制時(shí)長(zhǎng)(秒)|目標(biāo)分辨率 # 輸出模式: rtmp / hls / record / rtmprecord east-gate-01|rtsp://admin:Hik12345192.168.10.21:554/Streaming/Channels/101|rtmprecord|rtmp://192.168.30.5:1935/live/east_gate_01|3600|1080p park-west-02|rtsp://admin:dh123456192.168.10.22:554/cam/realmonitor?channel1subtype0|hls|/var/www/html/live/park_west_02|0|720p building-3f-03|rtsp://user:pass192.168.10.23:554/Streaming/Channels/102|record|/data/records/building_3f_03|7200|原碼率每行最后一個(gè)分辨率字段可以在 1080p、720p 和“原碼率”之間切換。原碼率意味著 FFmpeg 直接轉(zhuǎn)封裝不做轉(zhuǎn)碼CPU 開銷極低。如果要限制碼率或者統(tǒng)一分辨率就在這里指定。這里要注意一個(gè)細(xì)節(jié)RTSP 地址里如果帶著這類字符在配置文件中不要做任何轉(zhuǎn)義腳本讀取時(shí)會(huì)用引號(hào)包裹不會(huì)觸發(fā) Shell 解析問題。我在早期版本里給 URL 加過雙引號(hào)結(jié)果讀取變量時(shí)嵌套出錯(cuò)反而把地址截?cái)嗔撕髞斫y(tǒng)一改成純地址格式踩坑才結(jié)束。每個(gè)攝像頭還要有獨(dú)立 ID也就是配置里的第一列。這個(gè) ID 同時(shí)用于 PID 文件命名、日志文件命名、錄制文件名前綴所以盡量用語義化名字比如east-gate-01、park-west-02比cam1、cam2好維護(hù)得多。2.2 FFmpeg 參數(shù)按需拼接轉(zhuǎn)發(fā) / 轉(zhuǎn)碼 / 錄制攝像頭接入之后怎么選擇 FFmpeg 參數(shù)是整個(gè)項(xiàng)目里最需要想清楚的環(huán)節(jié)。很多初次接觸的人容易直接套模板把所有攝像頭都轉(zhuǎn)碼一遍結(jié)果 CPU 跑滿畫面延遲還大。經(jīng)驗(yàn)法則是能用 copy 就絕不轉(zhuǎn)碼。H.264 編碼的攝像頭如果目標(biāo)流媒體服務(wù)器支持 H.264直接用-c:v copy轉(zhuǎn)封裝即可CPU 占用可以忽略不計(jì)。比如??档?H.264 主碼流拉到 SRS 再轉(zhuǎn)推到播放端copy 模式完全足夠。但下面這幾類場(chǎng)景必須轉(zhuǎn)碼一是平臺(tái)強(qiáng)制要求輸出分辨率統(tǒng)一比如所有接入的流必須對(duì)齊到 1080p 或 720p二是需要在畫面上疊加攝像頭名稱、時(shí)間戳水印這必須通過drawtext濾鏡三是攝像頭輸出的是 H.265 而目標(biāo)平臺(tái)或者播放器兼容性不好需要轉(zhuǎn)成 H.264。在做分辨率統(tǒng)一時(shí)我通常用這樣一個(gè)參數(shù)組合ffmpeg -hide_banner -nostats -loglevel warning \ -rtsp_transport tcp -stimeout 30000000 \ -i rtsp://... \ -vf scale1920:1080 \ -c:v libx264 -preset veryfast -tune zerolatency -b:v 2500k \ -c:a aac -ar 44100 -ac 1 \ -f flv rtmp://...重點(diǎn)解釋幾個(gè)參數(shù)。-rtsp_transport tcp強(qiáng)制走 TCP 傳輸避免 UDP 在跨網(wǎng)段時(shí)丟包花屏。-stimeout 30000000是 RTSP 套接字超時(shí)時(shí)間單位是微秒30 秒沒有數(shù)據(jù)就自動(dòng)斷開這樣攝像頭斷線時(shí) FFmpeg 進(jìn)程不至于永遠(yuǎn)掛死。-preset veryfast和-tune zerolatency是 H.264 編碼速度與延遲的平衡直播場(chǎng)景下非常關(guān)鍵。錄制場(chǎng)景我推薦用分段封裝避免單個(gè)文件無限增長(zhǎng)ffmpeg -rtsp_transport tcp -i rtsp://... \ -c:v copy -c:a copy \ -f segment -segment_time 3600 -strftime 1 \ /data/records/east-gate-01_%Y%m%d_%H%M%S.mp4分段的好處是磁盤清理策略好寫只保留最近 N 天超出部分直接按目錄時(shí)間刪除。如果你用的是-c copy MP4 封裝注意 FFmpeg 分段 MP4 時(shí)可能會(huì)因?yàn)闀r(shí)間戳問題生成.tmp文件所以我會(huì)優(yōu)先用 MKV 容器或者干脆用-f segment -segment_format mp4實(shí)測(cè)下來 MP4 分段在異常斷電時(shí)更容易損壞。3. 一鍵啟停功能的實(shí)現(xiàn)細(xì)節(jié)3.1 啟動(dòng)流程檢查 PID、拼命令、后臺(tái)拉起整個(gè)管理腳本我做成一個(gè)cam_manager.sh通過傳入 start、stop、status、watchdog 等子命令來操作這樣運(yùn)維只需要記住一個(gè)入口。啟動(dòng)函數(shù)的設(shè)計(jì)思路是先從配置文件里讀一行判斷這個(gè)攝像頭的 PID 文件是否已存在、對(duì)應(yīng)進(jìn)程是否還活著如果活著就不用重復(fù)啟動(dòng)如果沒活就按照前面的規(guī)則拼接 FFmpeg 命令用nohup放到后臺(tái)再把 PID 記錄下來。核心代碼類似下面這樣start_one() { local id$1 src$2 mode$3 target$4 seg$5 res$6 local pid_file$PID_DIR/$id.pid if [ -f $pid_file ]; then local old_pid$(cat $pid_file) if kill -0 $old_pid 2/dev/null; then echo [$id] already running, pid$old_pid return 0 fi fi local cmdffmpeg -hide_banner -nostats -loglevel warning cmd -rtsp_transport tcp -stimeout 30000000 -i \$src\ case $res in 1080p) cmd -vf scale1920:1080 -c:v libx264 -preset veryfast -tune zerolatency -b:v 2500k ;; 720p) cmd -vf scale1280:720 -c:v libx264 -preset veryfast -tune zerolatency -b:v 1500k ;; *) cmd -c:v copy ;; esac cmd -c:a aac -ar 44100 -ac 1 case $mode in rtmp) cmd -f flv \$target\ ;; rtmprecord) cmd -f flv \$target\ cmd -c:v copy -c:a copy -f segment -segment_time ${seg:-3600} -strftime 1 \$REC_DIR/${id}_%Y%m%d_%H%M%S.mp4\ ;; hls) cmd -f hls -hls_time 4 -hls_list_size 6 -hls_flags delete_segments \$target/index.m3u8\ ;; record) cmd -c:v copy -c:a copy -f segment -segment_time ${seg:-3600} -strftime 1 \$REC_DIR/${id}_%Y%m%d_%H%M%S.mp4\ ;; esac nohup bash -c $cmd $LOG_DIR/$id.log 21 echo $! $pid_file sleep 1 if kill -0 $(cat $pid_file) 2/dev/null; then echo [$id] started, pid$(cat $pid_file) else echo [$id] start failed, last log: tail -n 20 $LOG_DIR/$id.log fi }啟動(dòng)后延遲 1 秒檢查 PID是為了擋掉“命令拼錯(cuò)、密碼不對(duì)、RTSP 地址根本不可達(dá)”這一類低級(jí)錯(cuò)誤。如果 FFmpeg 啟動(dòng)瞬間就崩潰1 秒內(nèi) PID 就已經(jīng)消失這時(shí)候立刻展示日志尾部比用戶事后翻日志高效得多。啟動(dòng)所有攝像頭就是一個(gè)遍歷配置文件的過程start_all() { while IFS| read -r id src mode target seg res; do [ -z $id ] continue start_one $id $src $mode $target $seg $res done (grep -vE ^\s*(#|$) $CONF_FILE) }注意我刻意把配置解析和啟動(dòng)邏輯分開將來如果字段增加只需要改 start_one 和配置說明不需要碰循環(huán)邏輯。3.2 停止流程優(yōu)雅退出比粗暴 kill 重要停止函數(shù)看似簡(jiǎn)單但處理不好會(huì)把錄制文件搞壞或者留下“僵尸進(jìn)程”的隱患。最基本的停止邏輯是通過 PID 文件找到進(jìn)程號(hào)先發(fā)送SIGTERM然后循環(huán)等待進(jìn)程退出超過時(shí)間再發(fā)SIGKILL。stop_one() { local id$1 local pid_file$PID_DIR/$id.pid [ -f $pid_file ] || { echo [$id] no pid file; return 0; } local pid$(cat $pid_file 2/dev/null) if [ -n $pid ] kill -0 $pid 2/dev/null; then kill $pid # 最多等 5 秒 for i in $(seq 1 10); do if ! kill -0 $pid 2/dev/null; then break fi sleep 0.5 done if kill -0 $pid 2/dev/null; then echo [$id] process stuck, force kill kill -9 $pid else echo [$id] stopped gracefully fi else echo [$id] not running fi rm -f $pid_file }為什么先SIGTERM而不是直接kill -9因?yàn)?FFmpeg 收到 SIGTERM 后會(huì)正常關(guān)閉輸出文件、刷新封裝格式保證錄制文件可播放。如果你直接強(qiáng)殺錄制中的 MP4 文件大概率缺 moov box播放器打開會(huì)報(bào)錯(cuò)需要額外做索引修復(fù)。在實(shí)際運(yùn)行中有些攝像頭流因?yàn)榫W(wǎng)絡(luò)異常處于阻塞狀態(tài)FFmpeg 收到 SIGTERM 后可能遲遲不退出所以 5 秒超時(shí)后的強(qiáng)殺是必要的兜底。另外停止所有進(jìn)程時(shí)我建議不要并發(fā) kill而是逐個(gè)處理。雖然并發(fā)看起來更快但服務(wù)器上同時(shí)出現(xiàn)幾十個(gè) kill 動(dòng)作磁盤 IO 和日志寫入反而會(huì)產(chǎn)生抖動(dòng)不利于排查問題。4. 運(yùn)行監(jiān)控與自動(dòng)恢復(fù)4.1 三層巡檢邏輯進(jìn)程、連通性、日志狀態(tài)狀態(tài)監(jiān)控是這套腳本里價(jià)值最高的部分。我的巡檢思路分為三層先看進(jìn)程在不在再看攝像頭源站通不通最后看 FFmpeg 日志有沒有異常輸出。第一層進(jìn)程檢測(cè)。通過kill -0 $pid判斷 PID 是否存在。這個(gè)命令不會(huì)給進(jìn)程發(fā)信號(hào)只做存在性探測(cè)安全且高效。如果 PID 文件不存在或者進(jìn)程不存在直接判定為 down。第二層網(wǎng)絡(luò)連通性。RTSP 源站的連通性可以用nc或timeout配合ffprobe探測(cè)。我一般優(yōu)先用 nc 檢查攝像頭 554 端口是否開放timeout 3 nc -z -w3 192.168.10.21 554 /dev/null 21返回成功表示攝像頭在線返回失敗則可能是斷電、網(wǎng)線松動(dòng)或者 IP 變更。這一步能區(qū)分“FFmpeg 進(jìn)程還在但攝像頭掛了”的場(chǎng)景。第三層日志狀態(tài)。只要 FFmpeg 進(jìn)程活著不等于推流正常有些情況下進(jìn)程沒有退出但已經(jīng)陷入重連循環(huán)或者輸出的日志里全是錯(cuò)誤。我會(huì)用tail -n 5提取日志最后幾行用關(guān)鍵字匹配error、refused、timeout等異常內(nèi)容有異常就在狀態(tài)表里標(biāo)記出來。狀態(tài)輸出做成表格終端下一目了然printf %-24s %-10s %-10s %-20s %s\n 攝像頭ID PID 狀態(tài) 日志最后時(shí)間 備注每一行是一個(gè)攝像頭的完整狀態(tài)正常是 running異常會(huì)顯示具體原因。這個(gè)表格我后來還做成了定時(shí)巡檢截圖發(fā)給運(yùn)維群比打開監(jiān)控平臺(tái)刷指標(biāo)直觀得多。4.2 看門狗自動(dòng)重啟與告警上報(bào)有了 status 巡檢邏輯自動(dòng)恢復(fù)就順理成章了。我會(huì)在服務(wù)器上放一個(gè) crontab 任務(wù)每分鐘執(zhí)行一次 watchdog 子命令* * * * * /opt/cam_manager.sh watchdog /opt/cam_manager/watchdog.log 21watchdog 函數(shù)內(nèi)部會(huì)對(duì)每臺(tái)攝像頭做一遍 status 檢查發(fā)現(xiàn)進(jìn)程不存在或者攝像頭端口不可達(dá)就自動(dòng)調(diào)用 start_one 重新拉流。這里必須引入一個(gè)防抖機(jī)制。如果攝像頭因?yàn)閿嚯姵掷m(xù)離線FFmpeg 啟動(dòng)會(huì)立刻失敗如果不做限制每分鐘會(huì)被反復(fù)拉起一次日志會(huì)刷得非常難看還可能把流媒體服務(wù)器打到過載。所以我會(huì)給每臺(tái)攝像頭加一個(gè)重啟次數(shù)的內(nèi)存狀態(tài)短時(shí)間內(nèi)比如 5 分鐘超過 3 次就暫停重啟等下一個(gè)周期再說。實(shí)現(xiàn)上可以在/tmp下建一個(gè)狀態(tài)文件記錄攝像頭ID:時(shí)間戳:次數(shù)。這個(gè)做法的思路是持續(xù)失敗說明不是“進(jìn)程崩潰”而是“源端故障”這時(shí)候重復(fù)拉起沒有意義不如報(bào)警讓人去處理。告警上報(bào)可以走 Webhook 或者簡(jiǎn)單郵件腳本。我在園區(qū)項(xiàng)目里用的最多的是企業(yè)微信群機(jī)器人 Webhookwatchdog 發(fā)現(xiàn)連續(xù)多次重啟失敗后POST 一條 JSON 消息到群里值守同事馬上能收到通知。Webhook 地址不要硬編碼在腳本里單獨(dú)放一個(gè)alert.conf文件方便團(tuán)隊(duì)各自維護(hù)。5. 實(shí)戰(zhàn)中的問題排查實(shí)錄5.1 RTSP 頻繁斷流不只是網(wǎng)絡(luò)的問題接入???、大華攝像頭最常遇到的怪現(xiàn)象就是FFmpeg 起來之后能跑幾小時(shí)也可能幾分鐘就斷日志里出現(xiàn)Connection timed out或者Server returned 5xx。一開始我以為是交換機(jī)問題后來排查發(fā)現(xiàn)是某些攝像頭默認(rèn)限制單路并發(fā)連接數(shù)如果有多個(gè)人同時(shí)在瀏覽器預(yù)覽同一路流FFmpeg 的連接會(huì)被擠掉。后來我在啟動(dòng)參數(shù)里統(tǒng)一加上-stimeout 30000000確保斷流時(shí)進(jìn)程能主動(dòng)退出再配合 watchdog 自動(dòng)拉起斷流影響被控制在 1 分鐘內(nèi)。另外RTSP 地址里如果用了subtype0這種參數(shù)部分?jǐn)z像頭固件在 UDP 傳輸下會(huì)非常敏感稍微有丟包就斷開。強(qiáng)制-rtsp_transport tcp之后問題基本絕跡。網(wǎng)絡(luò)質(zhì)量不好的園區(qū)不要糾結(jié) UDP 的實(shí)時(shí)性穩(wěn)定壓倒一切。5.2 轉(zhuǎn)碼性能不夠CPU 被 FFmpeg 打滿有個(gè)園區(qū)項(xiàng)目在 ARM 架構(gòu)的邊緣服務(wù)器上接了幾十路 1080p 攝像頭我最初按照固定分辨率轉(zhuǎn)碼的思路部署結(jié)果 CPU 直接 100%攝像頭畫面全部卡頓。后來把部署方案改成“原碼率轉(zhuǎn)發(fā)為主、必要轉(zhuǎn)碼為輔”CPU 占用立刻降到 20% 以下。如果必須轉(zhuǎn)碼建議優(yōu)先用硬件編碼器。NVIDIA 顯卡可以用-c:v h264_nvencIntel 核顯可以用-c:v h264_qsvRockchip 平臺(tái)可以用-c:v h264_v4l2m2m。FFmpeg 里怎么確認(rèn)有沒有對(duì)應(yīng)編碼器執(zhí)行ffmpeg -encoders | grep 264就能看到。實(shí)際測(cè)試中在 RK3588 上使用硬件編碼轉(zhuǎn) HLS單路負(fù)載比軟編低一半還多。如果實(shí)在沒有硬件加速那就降低分辨率而不是降低幀率。720p 轉(zhuǎn)碼的 CPU 開銷不到 1080p 的一半日常安防監(jiān)控場(chǎng)景 2~4 Mbps 的 720p 碼率完全夠看。5.3 PID 文件殘留導(dǎo)致認(rèn)為“一直在線”我在狀態(tài)巡檢里漏過一種情況FFmpeg 進(jìn)程退出后 PID 文件沒有清理status 腳本只查 PID 文件存在就不管進(jìn)程死活結(jié)果把一臺(tái)已經(jīng)離線的攝像頭標(biāo)記成 running直到業(yè)務(wù)側(cè)反饋畫面丟失才發(fā)現(xiàn)。后來所有狀態(tài)判斷都改成“先讀 PID 文件再kill -0驗(yàn)證進(jìn)程”PID 文件只是輔助定位不能作為判斷依據(jù)。同時(shí)在 start_one 里如果發(fā)現(xiàn) PID 文件存在但進(jìn)程不存在會(huì)自動(dòng)清理舊 PID 文件再啟動(dòng)避免端口沖突或者狀態(tài)錯(cuò)亂。在實(shí)際腳本里處理 PID 殘留還有一個(gè)好處當(dāng)攝像頭 IP 被別的服務(wù)占用時(shí)殘留在 PID 文件里的舊進(jìn)程不會(huì)干擾新的 RTSP 連接啟動(dòng)邏輯不會(huì)因?yàn)椤案杏X進(jìn)程存在”而拒絕重新拉流。6. 踩坑后留下的一些個(gè)人心得這套腳本我迭代了三個(gè)園區(qū)項(xiàng)目最大的體會(huì)是運(yùn)維工具的價(jià)值不在代碼多復(fù)雜而在“故障發(fā)生時(shí)能否快速定位問題”。如果攝像頭畫面丟了運(yùn)維第一反應(yīng)不是去查 VLC 能不能播放而是跑一條 status 命令看到網(wǎng)絡(luò)連通性那列是 DOWN馬上就能知道是攝像頭掉線還是推流進(jìn)程退出排查路徑瞬間縮短。另一個(gè)經(jīng)驗(yàn)是配置文件一定要配上字段說明。當(dāng)時(shí)我以為只有自己維護(hù)腳本注釋寫得很隨意結(jié)果項(xiàng)目交接后半個(gè)月新同事把分辨率字段寫成了1920x1080而腳本匹配的是1080p整批攝像頭都啟動(dòng)了原碼率模式。后來我在配置頭部加了兩行備注說明取值范圍類似的低級(jí)錯(cuò)誤幾乎絕跡。最后給一個(gè)建議如果是正式項(xiàng)目不要滿足于 nohup 這種會(huì)話級(jí)的進(jìn)程管理可以把腳本生成的命令改造成 systemd 模板服務(wù)配合Restartalways和RestartSec5宿主機(jī)重啟后攝像頭流也能自動(dòng)恢復(fù)。我保留這套 Shell 腳本主要是為了日常運(yùn)維和設(shè)備變更靈活真正要保證開機(jī)自啟的還是 systemd 更穩(wěn)妥。