脚本如何统一存储写入数据

wen 实用脚本 35

本文目录导读:

脚本如何统一存储写入数据

  1. 方案一:基于文件的统一存储(最简单,适合单机)
  2. 方案二:基于数据库的统一存储(适合复杂结构、需要查询)
  3. 方案三:基于消息队列 + 消费者(适合高并发、分布式)
  4. 方案四:基于外部 API / 微服务(最灵活,适合跨语言)
  5. 选择建议表
  6. 最佳实践(通用配置建议)

针对“脚本如何统一存储写入数据”这个问题,核心需求通常是为了避免并发冲突简化日志/结果收集以及便于外部系统消费

根据你的脚本类型(Shell、Python、批处理)和应用场景,这里有几种主流的统一存储方案:

基于文件的统一存储(最简单,适合单机)

核心思路:所有脚本都向同一个文件(或同一类前缀的文件)追加写入,通过文件锁来避免并发写入混乱。

推荐工具flock (Linux) 或 文件句柄复用。

  • Shell 脚本示例

      #!/bin/bash
      OUTPUT_FILE="/var/log/scripts_unified_result/output.csv"
      # 使用 flock 实现原子写入
      (
          flock -x 200  # 获取排他锁
          echo "$(date '+%Y-%m-%d %H:%M:%S'),$JOB_NAME,$RESULT" >> "$OUTPUT_FILE"
      ) 200>"$OUTPUT_FILE.lock"
  • Python 脚本示例

      import filelock
      import json
      def write_unified(data: dict):
          lock_path = '/tmp/unified_store.lock'
          store_path = '/tmp/unified_store.jsonl'  # 使用 JSON Lines 格式
          lock = filelock.FileLock(lock_path)
          with lock:
              with open(store_path, 'a') as f:
                  f.write(json.dumps(data) + '\n')

适用场景:日志汇总、简单任务结果收集、单机多进程脚本。


基于数据库的统一存储(适合复杂结构、需要查询)

核心思路:所有脚本连接同一个数据库(MySQL、PostgreSQL、SQLite),通过数据库的事务(ACID)机制保证数据一致性。

  • 推荐实践:使用队列表流水表

  • Python 示例 (使用 SQLite + 连接池)

      import sqlite3
      from contextlib import closing
      # 初始化
      conn = sqlite3.connect('/data/unified.db', check_same_thread=False)
      def insert_data(table: str, data: dict):
          with closing(conn.cursor()) as cur:
              # 使用参数化查询防止注入
              cur.execute(f"INSERT INTO {table} (column1, column2) VALUES (?, ?)", 
                         (data['key1'], data['key2']))
              conn.commit()

适用场景:需要后续分析、查询、报表生成;数据字段结构复杂且经常变化。


基于消息队列 + 消费者(适合高并发、分布式)

核心思路:脚本只负责把数据推到消息队列(Redis List、Kafka、RabbitMQ),由后台一个消费者进程统一处理写入数据库或文件。

优点:解耦、缓冲、削峰填谷。

典型架构

[脚本A] -> Redis List -> [统一写入消费者] -> 数据库/文件
[脚本B] -> Redis List -> [统一写入消费者] -> 数据库/文件
[脚本C] -> Redis List -> [统一写入消费者] -> 数据库/文件
  • Python 示例 (Producer 端)

      import redis
      r = redis.Redis(host='localhost', port=6379)
      # 脚本只需 push,不关心写入
      r.lpush('data_pipeline', json.dumps({"script": "A", "data": "value"}))
  • Consumer 端

      while True:
          msg = r.brpop('data_pipeline')  # 阻塞直到有数据
          data = json.loads(msg[1])
          # 在这里统一写入数据库或文件(支持重试、去重)
          save_to_db(data)

适用场景:大规模分布式脚本系统、微服务架构、需要流量控制。


基于外部 API / 微服务(最灵活,适合跨语言)

核心思路:运行一个“数据写入微服务”(API Server),所有脚本通过 HTTP/gRPC 调用此 API 写入数据。

优点:语言无关、权限集中管理、可扩展。

  • API Server 示例 (Flask)

      from flask import Flask, request, jsonify
      app = Flask(__name__)
      @app.route('/log', methods=['POST'])
      def unified_log():
          data = request.json
          source = data.get('source_script')
          value = data.get('value')
          # 统一写入核心逻辑
          with open('log.txt', 'a') as f:
              f.write(f"{source}:{value}\n")
          return jsonify({"status": "ok"}), 201

调用方式

  • Shell: curl -X POST -H "Content-Type: application/json" -d '{"source":"script1","value":"done"}' http://localhost:5000/log
  • Python: requests.post('http://localhost:5000/log', json=...)

适用场景:脚本语言混杂(Bash、Python、PowerShell、Node.js)、需要统一鉴权/限流。


选择建议表

场景 推荐方案 理由
单机、简单数据、偶尔运行 方案一(文件 + flock) 零依赖,部署简单
单机、结构复杂、需要查询 方案二(SQLite) 支持 SQL,无需安装数据库服务
多机、脚本量级大 方案三(Redis/MQ) 解耦,防止数据库被打死
多语言、多团队 方案四(API) 接口统一,便于管理和审计
需要实时分析、流处理 方案三(Kafka) 高吞吐、持久化、可回溯消费

最佳实践(通用配置建议)

  1. 统一时间格式:建议统一使用 ISO 8601 格式(2024-05-20T10:30:00Z),避免时区混乱。
  2. 增加版本号:在写入的数据前面前置一个字段(如 "ver": "1.0"),方便后续格式变更。
  3. 错误处理:每个写入操作都应该有 try...except|| true,避免因为存储本身问题导致脚本失败。
  4. 数据分片/轮转:如果是文件存储,可以按天生成文件(output_20240520.log),避免单文件过大。

如果你能提供具体的脚本语言(如 Bash、PowerShell、Python)和部署环境(单机、Kubernetes、Crontab 集群),我可以给出更精确的代码示例。

抱歉,评论功能暂时关闭!