如何通过C# Windows服务定期带时间戳将Aerospike数据备份为JSON格式?
如何用C# Windows服务定期将Aerospike数据备份为JSON
我来帮你一步步实现这个需求——用C# Windows服务定期把Aerospike数据备份成带时间戳的JSON文件,下面是详细的方案和代码示例:
一、核心思路概述
整体流程分为三部分:
- 使用Aerospike官方C#客户端读取集群指定namespace/set的数据
- 将读取到的记录序列化为JSON格式,并用时间戳命名备份文件
- 基于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服务
- 编译项目为Release版本,找到生成的exe文件
- 以管理员身份打开命令提示符,执行以下命令安装服务:
sc create AerospikeAutoBackupService binPath= "C:\Path\To\Your\Service.exe" start= auto - 启动服务:
sc start AerospikeAutoBackupService - 可通过
sc query AerospikeAutoBackupService查看服务状态
六、关键注意事项
- 性能优化:如果数据量极大,
ScanAll可能影响集群性能,建议在低峰期执行,或通过ScanPolicy设置并发度、超时时间等参数 - 配置管理:将硬编码的Aerospike地址、备份目录等配置移到
App.config,方便后续修改 - 权限问题:确保服务运行账户有Aerospike集群的读取权限,以及备份目录的读写权限
- 错误告警:可扩展代码添加邮件告警或Windows事件日志记录,备份失败时及时通知管理员
内容的提问来源于stack exchange,提问作者Ajaykumar Singh
相关产品推荐
相关产品推荐

