You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过C# Windows服务定期带时间戳将Aerospike数据备份为JSON格式?

如何用C# Windows服务定期将Aerospike数据备份为JSON

我来帮你一步步实现这个需求——用C# Windows服务定期把Aerospike数据备份成带时间戳的JSON文件,下面是详细的方案和代码示例:

一、核心思路概述

整体流程分为三部分:

  1. 使用Aerospike官方C#客户端读取集群指定namespace/set的数据
  2. 将读取到的记录序列化为JSON格式,并用时间戳命名备份文件
  3. 基于Windows服务搭建定时任务框架,定期执行备份逻辑

二、准备工作

首先安装必要的NuGet包:

  • Aerospike.Client:官方Aerospike C#客户端,用于连接和读取数据
  • Newtonsoft.Json:成熟的JSON序列化库,处理Aerospike记录到JSON的转换
  • Quartz(可选):如果需要复杂定时规则(比如每天固定时段执行),推荐用这个;简单定时用System.Timers.Timer即可

同时确保:

  • Aerospike集群网络可访问,服务账户有读取目标namespace/set的权限
  • 备份目录提前创建(或让代码自动创建),服务运行账户有读写权限

三、核心备份逻辑实现

先写读取Aerospike数据并转存为JSON的核心类:

using Aerospike.Client;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System;

public class AerospikeBackupHandler : IDisposable
{
    private readonly AerospikeClient _aerospikeClient;
    private readonly string _targetNamespace;
    private readonly string _targetSet;

    public AerospikeBackupHandler(string host, int port, string ns, string set)
    {
        _aerospikeClient = new AerospikeClient(host, port);
        _targetNamespace = ns;
        _targetSet = set;
    }

    public void PerformBackup(string backupRootDir)
    {
        // 生成带UTC时间戳的备份文件名,避免时区冲突
        string timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
        string backupFilePath = Path.Combine(backupRootDir, $"aerospike_backup_{timestamp}.json");

        var recordsList = new List<Dictionary<string, object>>();

        // 扫描指定namespace和set的所有记录
        using (var recordScanner = _aerospikeClient.ScanAll(null, _targetNamespace, _targetSet))
        {
            while (recordScanner.Next())
            {
                Record currentRecord = recordScanner.Record;
                var recordDict = new Dictionary<string, object>
                {
                    ["RecordKey"] = currentRecord.Key.ToString(),
                    ["ExpirationTimestamp"] = currentRecord.Expiration,
                    ["Generation"] = currentRecord.Generation
                };

                // 把所有bin数据加入字典
                foreach (var bin in currentRecord.Bins)
                {
                    recordDict[bin.Key] = bin.Value;
                }

                recordsList.Add(recordDict);
            }
        }

        // 序列化并写入文件
        string jsonContent = JsonConvert.SerializeObject(recordsList, Formatting.Indented);
        File.WriteAllText(backupFilePath, jsonContent);

        // 可选:自动清理7天前的旧备份,避免磁盘满
        CleanupOldBackups(backupRootDir, 7);
    }

    private void CleanupOldBackups(string dirPath, int daysToRetain)
    {
        DateTime cutoff = DateTime.UtcNow.AddDays(-daysToRetain);
        foreach (var file in Directory.GetFiles(dirPath, "aerospike_backup_*.json"))
        {
            var fileInfo = new FileInfo(file);
            if (fileInfo.CreationTimeUtc < cutoff)
            {
                fileInfo.Delete();
            }
        }
    }

    public void Dispose()
    {
        _aerospikeClient?.Close();
    }
}

四、Windows服务与定时任务实现

这里提供两种定时方案,按需选择:

方案1:简单定时(System.Timers.Timer)

适合固定间隔执行(比如每天一次、每6小时一次):

using System.ServiceProcess;
using System.Timers;
using System;
using System.IO;

public class AerospikeAutoBackupService : ServiceBase
{
    private Timer _backupTimer;
    private AerospikeBackupHandler _backupHandler;

    // 可将这些配置移到App.config,避免硬编码
    private const string AerospikeHost = "192.168.1.100";
    private const int AerospikePort = 3000;
    private const string TargetNamespace = "production";
    private const string TargetSet = "user_profiles";
    private const string BackupDir = @"D:\AerospikeBackups";
    private const int BackupIntervalHours = 24; // 每天备份一次

    public AerospikeAutoBackupService()
    {
        ServiceName = "AerospikeAutoBackupService";
    }

    protected override void OnStart(string[] args)
    {
        // 初始化备份处理器
        _backupHandler = new AerospikeBackupHandler(AerospikeHost, AerospikePort, TargetNamespace, TargetSet);
        // 创建备份目录(如果不存在)
        Directory.CreateDirectory(BackupDir);

        // 初始化定时器
        _backupTimer = new Timer
        {
            Interval = BackupIntervalHours * 60 * 60 * 1000 // 转换为毫秒
        };
        _backupTimer.Elapsed += ExecuteBackup;
        // 服务启动时立即执行一次备份
        ExecuteBackup(null, null);
        _backupTimer.Start();

        WriteServiceLog("Service started successfully");
    }

    private void ExecuteBackup(object sender, ElapsedEventArgs e)
    {
        try
        {
            _backupHandler.PerformBackup(BackupDir);
            WriteServiceLog("Backup completed successfully");
        }
        catch (Exception ex)
        {
            WriteServiceLog($"Backup failed: {ex.Message}", isError: true);
        }
    }

    protected override void OnStop()
    {
        _backupTimer?.Stop();
        _backupTimer?.Dispose();
        _backupHandler?.Dispose();
        WriteServiceLog("Service stopped");
    }

    private void WriteServiceLog(string message, bool isError = false)
    {
        string logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ServiceLogs");
        Directory.CreateDirectory(logDir);
        string logFilePath = Path.Combine(logDir, $"BackupLog_{DateTime.UtcNow:yyyyMMdd}.txt");
        string logEntry = $"[{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}] {(isError ? "ERROR" : "INFO")}: {message}";
        File.AppendAllText(logFilePath, logEntry + Environment.NewLine);
    }
}

// 服务入口
static class Program
{
    static void Main()
    {
        ServiceBase[] servicesToRun = new ServiceBase[]
        {
            new AerospikeAutoBackupService()
        };
        ServiceBase.Run(servicesToRun);
    }
}

方案2:精准定时(Quartz)

适合需要固定时段执行的场景(比如每天凌晨2点):

首先安装Quartz NuGet包,然后修改服务的OnStart逻辑:

using Quartz;
using Quartz.Impl;
using System.Threading.Tasks;

protected override void OnStart(string[] args)
{
    Directory.CreateDirectory(BackupDir);
    WriteServiceLog("Initializing Quartz scheduler...");

    // 初始化Quartz调度器
    ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
    IScheduler scheduler = schedulerFactory.GetScheduler().Result;
    scheduler.Start().Wait();

    // 定义备份任务
    IJobDetail backupJob = JobBuilder.Create<AerospikeBackupQuartzJob>()
        .WithIdentity("AerospikeBackupJob", "BackupGroup")
        .UsingJobData("Host", AerospikeHost)
        .UsingJobData("Port", AerospikePort)
        .UsingJobData("Namespace", TargetNamespace)
        .UsingJobData("Set", TargetSet)
        .UsingJobData("BackupDir", BackupDir)
        .Build();

    // 创建Cron触发器:每天凌晨2点执行(UTC时间)
    ITrigger dailyTrigger = TriggerBuilder.Create()
        .WithIdentity("DailyBackupTrigger", "BackupGroup")
        .WithCronSchedule("0 0 2 * * ?") // Cron表达式:分 时 日 月 周 年(可选)
        .Build();

    scheduler.ScheduleJob(backupJob, dailyTrigger).Wait();
    WriteServiceLog("Daily backup scheduled for 2 AM UTC");
}

// Quartz任务实现类
public class AerospikeBackupQuartzJob : IJob
{
    public Task Execute(IJobExecutionContext context)
    {
        JobDataMap jobData = context.JobDetail.JobDataMap;
        try
        {
            using (var backupHandler = new AerospikeBackupHandler(
                jobData.GetString("Host"),
                jobData.GetIntValue("Port"),
                jobData.GetString("Namespace"),
                jobData.GetString("Set")))
            {
                backupHandler.PerformBackup(jobData.GetString("BackupDir"));
                WriteJobLog("Backup completed successfully");
            }
        }
        catch (Exception ex)
        {
            WriteJobLog($"Backup failed: {ex.Message}", isError: true);
        }
        return Task.CompletedTask;
    }

    private void WriteJobLog(string message, bool isError = false)
    {
        string logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ServiceLogs");
        Directory.CreateDirectory(logDir);
        string logFilePath = Path.Combine(logDir, $"BackupLog_{DateTime.UtcNow:yyyyMMdd}.txt");
        string logEntry = $"[{DateTime.UtcNow:yyyy-MM-dd HH:mm:ss}] {(isError ? "ERROR" : "INFO")}: {message}";
        File.AppendAllText(logFilePath, logEntry + Environment.NewLine);
    }
}

五、部署Windows服务

  1. 编译项目为Release版本,找到生成的exe文件
  2. 以管理员身份打开命令提示符,执行以下命令安装服务:
    sc create AerospikeAutoBackupService binPath= "C:\Path\To\Your\Service.exe" start= auto
    
  3. 启动服务:
    sc start AerospikeAutoBackupService
    
  4. 可通过sc query AerospikeAutoBackupService查看服务状态

六、关键注意事项

  • 性能优化:如果数据量极大,ScanAll可能影响集群性能,建议在低峰期执行,或通过ScanPolicy设置并发度、超时时间等参数
  • 配置管理:将硬编码的Aerospike地址、备份目录等配置移到App.config,方便后续修改
  • 权限问题:确保服务运行账户有Aerospike集群的读取权限,以及备份目录的读写权限
  • 错误告警:可扩展代码添加邮件告警或Windows事件日志记录,备份失败时及时通知管理员

内容的提问来源于stack exchange,提问作者Ajaykumar Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:14:03