作为面向数字基础设施的开源操作系统,OpenEuler在边缘计算领域展现出了独特优势。本文将通过实战演示,在单机OpenEuler环境搭建完整的边缘计算节点,体验其在资源受限环境下的卓越表现。
一、环境准备与系统优化
系统环境检查:
Bash # 检查系统版本和内核 cat /etc/os-release uname -r # 检查资源情况 free -h df -h lscpu
系统性能优化配置:
Bash # 创建性能优化脚本 cat > edge-optimize.sh << 'EOF' #!/bin/bash echo "🔧 边缘计算节点优化配置" # 优化内核参数 echo "1. 优化内核参数..." sudo tee -a /etc/sysctl.conf << 'SYS' # 边缘计算优化 net.core.rmem_max = 134217728 net.core.wmem_max = 134217728 net.ipv4.tcp_rmem = 4096 65536 134217728 net.ipv4.tcp_wmem = 4096 65536 134217728 net.core.netdev_max_backlog = 250000 vm.swappiness = 10 vm.dirty_ratio = 15 vm.dirty_background_ratio = 5 SYS # 应用配置 sudo sysctl -p # 优化服务配置 echo "2. 优化系统服务..." # 禁用不必要的服务 sudo systemctl disable bluetooth sudo systemctl disable cups sudo systemctl disable avahi-daemon # 配置日志轮转,避免磁盘写满 sudo tee /etc/logrotate.d/edge-logs << 'LOG' /var/log/edge/*.log { daily rotate 7 compress delaycompress missingok notifempty create 644 root root } LOG echo "✅ 优化完成" EOF chmod +x edge-optimize.sh ./edge-optimize.sh
二、轻量级边缘服务框架部署
安装必要的软件包:
Bash # 安装基础开发工具和网络工具 sudo dnf install -y python3 python3-pip git curl wget net-tools # 安装轻量级Web服务器 sudo dnf install -y lighttpd # 配置lighttpd sudo systemctl start lighttpd sudo systemctl enable lighttpd
创建边缘服务目录结构:
Bash # 创建边缘服务目录 mkdir -p ~/edge-services/{sensors,api,logs,config} cd ~/edge-services # 目录结构说明 tree .
三、传感器数据模拟服务
创建模拟传感器数据生成器:
Bash cat > sensors/temperature_sensor.py << 'EOF' #!/usr/bin/env python3 """ 温度传感器模拟器 模拟边缘设备的温度传感器数据 """ import time import json import random import logging from datetime import datetime # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('logs/temperature.log'), logging.StreamHandler() ] ) class TemperatureSensor: def __init__(self, sensor_id="temp_sensor_001"): self.sensor_id = sensor_id self.base_temp = 25.0 # 基础温度 self.temperature = self.base_temp def read_temperature(self): """模拟读取温度数据""" # 模拟温度波动 (-2°C 到 +3°C) variation = random.uniform(-2.0, 3.0) self.temperature = round(self.base_temp + variation, 2) data = { "sensor_id": self.sensor_id, "temperature": self.temperature, "timestamp": datetime.now().isoformat(), "unit": "celsius", "status": "normal" } logging.info(f"温度传感器读数: {self.temperature}°C") return data def simulate_fault(self): """模拟传感器故障""" return { "sensor_id": self.sensor_id, "temperature": -999.0, "timestamp": datetime.now().isoformat(), "unit": "celsius", "status": "fault", "error": "sensor_malfunction" } def main(): sensor = TemperatureSensor() print("🌡️ 温度传感器模拟器启动") print("按 Ctrl+C 停止模拟") try: while True: # 95%的概率正常读数,5%的概率模拟故障 if random.random() > 0.05: data = sensor.read_temperature() else: data = sensor.simulate_fault() logging.warning("传感器故障模拟") # 保存数据到文件 with open('sensors/temperature_data.json', 'w') as f: json.dump(data, f, indent=2) # 正常情况3秒一次读数,故障时10秒恢复 delay = 10 if data.get('status') == 'fault' else 3 time.sleep(delay) except KeyboardInterrupt: print("\n传感器模拟器已停止") if __name__ == "__main__": main() EOF chmod +x sensors/temperature_sensor.py
创建湿度传感器模拟器:
Bash cat > sensors/humidity_sensor.py << 'EOF' #!/usr/bin/env python3 """ 湿度传感器模拟器 模拟边缘设备的湿度传感器数据 """ import time import json import random import logging from datetime import datetime logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('logs/humidity.log'), logging.StreamHandler() ] ) class HumiditySensor: def __init__(self, sensor_id="humidity_sensor_001"): self.sensor_id = sensor_id self.base_humidity = 60.0 # 基础湿度 60% def read_humidity(self): """模拟读取湿度数据""" variation = random.uniform(-15.0, 20.0) humidity = max(0, min(100, self.base_humidity + variation)) data = { "sensor_id": self.sensor_id, "humidity": round(humidity, 2), "timestamp": datetime.now().isoformat(), "unit": "percent", "status": "normal" } logging.info(f"湿度传感器读数: {humidity}%") return data def main(): sensor = HumiditySensor() print("💧 湿度传感器模拟器启动") print("按 Ctrl+C 停止模拟") try: while True: data = sensor.read_humidity() # 保存数据到文件 with open('sensors/humidity_data.json', 'w') as f: json.dump(data, f, indent=2) time.sleep(5) # 5秒一次读数 except KeyboardInterrupt: print("\n湿度传感器模拟器已停止") if __name__ == "__main__": main() EOF chmod +x sensors/humidity_sensor.py
四、边缘数据 API 服务
创建轻量级 API 服务:
Bash cat > api/edge_api.py << 'EOF' #!/usr/bin/env python3 """ 边缘计算数据API服务 提供传感器数据的RESTful API接口 """ from http.server import HTTPServer, BaseHTTPRequestHandler import json import os import time from datetime import datetime import threading class EdgeAPIHandler(BaseHTTPRequestHandler): def do_GET(self): """处理GET请求""" if self.path == '/api/sensors/temperature': self.get_temperature() elif self.path == '/api/sensors/humidity': self.get_humidity() elif self.path == '/api/sensors/all': self.get_all_sensors() elif self.path == '/api/health': self.get_health() elif self.path == '/api/system': self.get_system_info() else: self.send_error(404, "接口不存在") def get_temperature(self): """获取温度数据""" try: with open('sensors/temperature_data.json', 'r') as f: data = json.load(f) self.send_json_response(data) except FileNotFoundError: self.send_error(503, "温度数据暂不可用") def get_humidity(self): """获取湿度数据""" try: with open('sensors/humidity_data.json', 'r') as f: data = json.load(f) self.send_json_response(data) except FileNotFoundError: self.send_error(503, "湿度数据暂不可用") def get_all_sensors(self): """获取所有传感器数据""" sensors_data = {} try: with open('sensors/temperature_data.json', 'r') as f: sensors_data['temperature'] = json.load(f) except FileNotFoundError: sensors_data['temperature'] = {"error": "数据不可用"} try: with open('sensors/humidity_data.json', 'r') as f: sensors_data['humidity'] = json.load(f) except FileNotFoundError: sensors_data['humidity'] = {"error": "数据不可用"} sensors_data['timestamp'] = datetime.now().isoformat() sensors_data['edge_node'] = os.uname().nodename self.send_json_response(sensors_data) def get_health(self): """健康检查接口""" health_data = { "status": "healthy", "timestamp": datetime.now().isoformat(), "services": { "temperature_sensor": os.path.exists('sensors/temperature_data.json'), "humidity_sensor": os.path.exists('sensors/humidity_data.json'), "api_server": True }, "system": { "node": os.uname().nodename, "os": "OpenEuler 25.09" } } self.send_json_response(health_data) def get_system_info(self): """获取系统信息""" import psutil system_info = { "cpu_percent": psutil.cpu_percent(interval=1), "memory_percent": psutil.virtual_memory().percent, "disk_usage": psutil.disk_usage('/').percent, "boot_time": datetime.fromtimestamp(psutil.boot_time()).isoformat(), "timestamp": datetime.now().isoformat() } self.send_json_response(system_info) def send_json_response(self, data): """发送JSON响应""" self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(json.dumps(data, indent=2).encode()) def log_message(self, format, *args): """自定义日志格式""" print(f"🌐 API请求: {self.client_address[0]} - {format % args}") def start_sensor_simulators(): """启动传感器模拟器""" def start_temperature_sensor(): os.system('python3 sensors/temperature_sensor.py') def start_humidity_sensor(): os.system('python3 sensors/humidity_sensor.py') # 在后台启动传感器 temp_thread = threading.Thread(target=start_temperature_sensor, daemon=True) humidity_thread = threading.Thread(target=start_humidity_sensor, daemon=True) temp_thread.start() humidity_thread.start() print("✅ 传感器模拟器已启动") def main(): # 启动传感器模拟器 start_sensor_simulators() # 启动API服务器 PORT = 8080 HOST = '0.0.0.0' server = HTTPServer((HOST, PORT), EdgeAPIHandler) print("🚀 边缘计算API服务启动") print(f"📍 服务地址: http://{HOST}:{PORT}") print("🛣️ 可用接口:") print(" GET /api/sensors/temperature - 温度数据") print(" GET /api/sensors/humidity - 湿度数据") print(" GET /api/sensors/all - 所有传感器数据") print(" GET /api/health - 健康检查") print(" GET /api/system - 系统信息") print("\n按 Ctrl+C 停止服务") try: server.serve_forever() except KeyboardInterrupt: print("\n🛑 服务已停止") server.shutdown() if __name__ == "__main__": main() EOF chmod +x api/edge_api.py
五、边缘监控面板
创建 Web 监控界面:
Bash cat > monitor/dashboard.html << 'EOF' <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>OpenEuler 边缘节点监控</title> <style> :root { --primary: #1890ff; --success: #52c41a; --warning: #faad14; --error: #f5222d; --text: #333; --background: #f0f2f5; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--background); color: var(--text); line-height: 1.6; } .container { max-width: 1200px; margin: 0 auto; padding: 20px; } .header { text-align: center; margin-bottom: 30px; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .status-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-bottom: 30px; } .card { background: white; padding: 25px; border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .sensor-card { text-align: center; border-left: 4px solid var(--primary); } .system-card { border-left: 4px solid var(--success); } .value { font-size: 2.5em; font-weight: bold; margin: 10px 0; } .unit { font-size: 1em; color: #666; } .timestamp { color: #999; font-size: 0.9em; } .status-badge { display: inline-block; padding: 4px 12px; border-radius: 20px; font-size: 0.8em; font-weight: bold; } .status-normal { background: #f6ffed; color: var(--success); border: 1px solid #b7eb8f; } .status-fault { background: #fff2f0; color: var(--error); border: 1px solid #ffccc7; } .chart-container { height: 200px; margin-top: 20px; } .controls { display: flex; gap: 10px; margin-top: 20px; } button { padding: 10px 20px; border: none; border-radius: 5px; background: var(--primary); color: white; cursor: pointer; font-size: 14px; } button:hover { opacity: 0.8; } .log-container { background: #1e1e1e; color: #d4d4d4; padding: 15px; border-radius: 5px; font-family: 'Courier New', monospace; font-size: 12px; max-height: 200px; overflow-y: auto; } </style> </head> <body> <div class="container"> <div class="header"> <h1>🐧 OpenEuler 边缘计算节点监控</h1> <p>实时监控边缘设备传感器数据和系统状态</p> </div> <div class="status-grid"> <div class="card sensor-card"> <h3>🌡️ 温度传感器</h3> <div class="value" id="temperature-value">--</div> <div class="unit">摄氏度 °C</div> <div class="status-badge status-normal" id="temperature-status">正常</div> <div class="timestamp" id="temperature-time">--</div> </div> <div class="card sensor-card"> <h3>💧 湿度传感器</h3> <div class="value" id="humidity-value">--</div> <div class="unit">百分比 %</div> <div class="status-badge status-normal" id="humidity-status">正常</div> <div class="timestamp" id="humidity-time">--</div> </div> <div class="card system-card"> <h3>🖥️ 系统状态</h3> <div id="cpu-usage">CPU: --%</div> <div id="memory-usage">内存: --%</div> <div id="disk-usage">磁盘: --%</div> <div class="timestamp" id="system-time">--</div> </div> </div> <div class="card"> <h3>📊 实时数据日志</h3> <div class="controls"> <button onclick="startMonitoring()">开始监控</button> <button onclick="stopMonitoring()">停止监控</button> <button onclick="clearLogs()">清空日志</button> </div> <div class="log-container" id="log-output"> <div>等待数据...</div> </div> </div> <div class="card"> <h3>🔧 节点信息</h3> <div id="node-info"> <div>节点名称: <span id="node-name">--</span></div> <div>操作系统: <span id="node-os">--</span></div> <div>服务状态: <span id="service-status">--</span></div> <div>运行时间: <span id="uptime">--</span></div> </div> </div> </div> <script> let monitorInterval; const API_BASE = 'http://' + window.location.hostname + ':8080'; function updateSensorData() { // 获取温度数据 fetch(API_BASE + '/api/sensors/temperature') .then(response => response.json()) .then(data => { if (data.status !== 'fault') { document.getElementById('temperature-value').textContent = data.temperature; document.getElementById('temperature-time').textContent = new Date(data.timestamp).toLocaleString(); document.getElementById('temperature-status').textContent = '正常'; document.getElementById('temperature-status').className = 'status-badge status-normal'; } else { document.getElementById('temperature-value').textContent = '故障'; document.getElementById('temperature-status').textContent = '故障'; document.getElementById('temperature-status').className = 'status-badge status-fault'; } }) .catch(error => { console.error('获取温度数据失败:', error); }); // 获取湿度数据 fetch(API_BASE + '/api/sensors/humidity') .then(response => response.json()) .then(data => { document.getElementById('humidity-value').textContent = data.humidity; document.getElementById('humidity-time').textContent = new Date(data.timestamp).toLocaleString(); }) .catch(error => { console.error('获取湿度数据失败:', error); }); // 获取系统信息 fetch(API_BASE + '/api/system') .then(response => response.json()) .then(data => { document.getElementById('cpu-usage').textContent = `CPU: ${data.cpu_percent}%`; document.getElementById('memory-usage').textContent = `内存: ${data.memory_percent}%`; document.getElementById('disk-usage').textContent = `磁盘: ${data.disk_usage}%`; document.getElementById('system-time').textContent = new Date(data.timestamp).toLocaleString(); }); // 获取健康状态 fetch(API_BASE + '/api/health') .then(response => response.json()) .then(data => { document.getElementById('node-name').textContent = data.system.node; document.getElementById('node-os').textContent = data.system.os; document.getElementById('service-status').textContent = data.status; const bootTime = new Date(data.system.boot_time || data.timestamp); const uptime = Math.floor((new Date() - bootTime) / 1000 / 60); // 分钟 document.getElementById('uptime').textContent = `${uptime} 分钟`; }); // 更新日志 addLog('数据更新: ' + new Date().toLocaleTimeString()); } function addLog(message) { const logContainer = document.getElementById('log-output'); const logEntry = document.createElement('div'); logEntry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`; logContainer.appendChild(logEntry); logContainer.scrollTop = logContainer.scrollHeight; } function startMonitoring() { if (monitorInterval) { clearInterval(monitorInterval); } monitorInterval = setInterval(updateSensorData, 3000); updateSensorData(); // 立即执行一次 addLog('监控已启动'); } function stopMonitoring() { if (monitorInterval) { clearInterval(monitorInterval); monitorInterval = null; addLog('监控已停止'); } } function clearLogs() { document.getElementById('log-output').innerHTML = '<div>日志已清空</div>'; } // 页面加载时自动开始监控 window.onload = function() { startMonitoring(); }; </script> </body> </html> EOF
六、启动和管理脚本
创建边缘服务管理脚本:
Bash cat > edge-manager.sh << 'EOF' #!/bin/bash EDGE_DIR="$HOME/edge-services" LOG_DIR="$EDGE_DIR/logs" PID_DIR="$EDGE_DIR/pid" # 创建必要的目录 mkdir -p $LOG_DIR $PID_DIR start_services() { echo "🚀 启动边缘计算服务..." # 启动API服务 cd $EDGE_DIR nohup python3 api/edge_api.py > $LOG_DIR/api.log 2>&1 & echo $! > $PID_DIR/api.pid # 等待服务启动 sleep 3 # 检查服务状态 if curl -s http://localhost:8080/api/health > /dev/null; then echo "✅ 边缘API服务启动成功" # 获取访问地址 IP_ADDR=$(hostname -I | awk '{print $1}') echo "" echo "🌐 监控面板: http://$IP_ADDR:8080/monitor/dashboard.html" echo "🔧 API文档:" echo " 温度数据: http://$IP_ADDR:8080/api/sensors/temperature" echo " 湿度数据: http://$IP_ADDR:8080/api/sensors/humidity" echo " 系统信息: http://$IP_ADDR:8080/api/system" echo " 健康检查: http://$IP_ADDR:8080/api/health" else echo "❌ 服务启动失败,请检查日志: $LOG_DIR/api.log" fi } stop_services() { echo "🛑 停止边缘计算服务..." # 停止API服务 if [ -f $PID_DIR/api.pid ]; then kill $(cat $PID_DIR/api.pid) 2>/dev/null rm -f $PID_DIR/api.pid echo "✅ API服务已停止" fi # 停止传感器进程 pkill -f "temperature_sensor.py" pkill -f "humidity_sensor.py" echo "✅ 传感器模拟器已停止" } status_services() { echo "📊 边缘服务状态:" # 检查API服务 if [ -f $PID_DIR/api.pid ] && kill -0 $(cat $PID_DIR/api.pid) 2>/dev/null; then echo "✅ API服务: 运行中 (PID: $(cat $PID_DIR/api.pid))" else echo "❌ API服务: 未运行" fi # 检查传感器 if pgrep -f "temperature_sensor.py" > /dev/null; then echo "✅ 温度传感器: 运行中" else echo "❌ 温度传感器: 未运行" fi if pgrep -f "humidity_sensor.py" > /dev/null; then echo "✅ 湿度传感器: 运行中" else echo "❌ 湿度传感器: 未运行" fi # 检查API端点 if curl -s http://localhost:8080/api/health > /dev/null; then echo "✅ API连接: 正常" else echo "❌ API连接: 失败" fi } case "$1" in start) start_services ;; stop) stop_services ;; restart) stop_services sleep 2 start_services ;; status) status_services ;; *) echo "使用方法: $0 {start|stop|restart|status}" echo "" echo "边缘计算服务管理脚本" echo " start - 启动所有服务" echo " stop - 停止所有服务" echo " restart - 重启所有服务" echo " status - 查看服务状态" exit 1 esac EOF chmod +x edge-manager.sh
七、部署和测试
部署监控面板:
Bash # 将监控面板部署到lighttpd sudo cp monitor/dashboard.html /var/www/lighttpd/monitor.html sudo chown lighttpd:lighttpd /var/www/lighttpd/monitor.html # 启动lighttpd服务 sudo systemctl restart lighttpd
启动边缘服务:
Bash cd ~/edge-services # 启动所有服务 ./edge-manager.sh start # 检查服务状态 ./edge-manager.sh status
测试 API 接口:
Bash # 测试健康检查接口 curl http://localhost:8080/api/health # 测试温度传感器接口 curl http://localhost:8080/api/sensors/temperature # 测试所有传感器数据 curl http://localhost:8080/api/sensors/all # 测试系统信息 curl http://localhost:8080/api/system
八、性能监控和优化
创建性能监控脚本:
Bash cat > performance-monitor.sh << 'EOF' #!/bin/bash echo "📈 边缘节点性能监控" echo "===================" # 系统资源监控 echo "1. 系统资源使用:" echo " 内存使用:" free -h | head -2 echo -e "\n 磁盘使用:" df -h / | tail -1 echo -e "\n CPU使用:" top -bn1 | grep "Cpu(s)" | awk '{print " CPU使用率: " $2 "%"}' # 服务资源占用 echo -e "\n2. 服务资源占用:" echo " API服务:" ps aux | grep "edge_api.py" | grep -v grep | awk '{print " 内存: " $6/1024 " MB, CPU: " $3 "%"}' echo " 温度传感器:" ps aux | grep "temperature_sensor.py" | grep -v grep | awk '{print " 内存: " $6/1024 " MB, CPU: " $3 "%"}' echo " 湿度传感器:" ps aux | grep "humidity_sensor.py" | grep -v grep | awk '{print " 内存: " $6/1024 " MB, CPU: " $3 "%"}' # 网络连接 echo -e "\n3. 网络连接:" netstat -tlnp | grep :8080 # 服务响应时间测试 echo -e "\n4. API响应时间测试:" time curl -s -o /dev/null http://localhost:8080/api/health time curl -s -o /dev/null http://localhost:8080/api/sensors/all # 日志文件大小 echo -e "\n5. 日志文件大小:" ls -lh ~/edge-services/logs/ echo -e "\n🎯 性能总结:" total_memory=$(ps aux | grep -e "edge_api.py" -e "temperature_sensor.py" -e "humidity_sensor.py" | grep -v grep | awk '{sum += $6} END {print sum/1024}') echo " 总内存占用: ${total_memory%.*} MB" echo " 服务数量: 3个核心服务" echo " 数据更新频率: 温度3秒/次, 湿度5秒/次" EOF chmod +x performance-monitor.sh ./performance-monitor.sh
体验总结
通过这个完整的边缘计算实战,我们在OpenEuler 25.09上成功构建了一个功能完备的边缘计算节点:
技术成果:
性能表现:
OpenEuler 优势体现:
轻量高效 - 基础系统资源占用极低,适合资源受限的边缘环境
稳定可靠 - 企业级内核保障服务长时间稳定运行
生态完善 - 丰富的软件包支持快速部署边缘应用
安全可控 - 完善的安全机制保障边缘数据安全
实际应用价值:
这个边缘计算节点演示了在工业物联网、智能农业、环境监测等场景的典型应用。OpenEuler的轻量级特性和稳定性使其成为边缘计算的理想选择,特别是在网络条件差、资源有限的边缘环境中。
通过本次实战,我们验证了OpenEuler在边缘计算场景的出色表现,其轻量、稳定、安全的特性为数字化转型提供了坚实的技术底座。