C#实现自动下载阿里云数据库RDS,附转储阿里云OSS服务器

本文属于个人原创作品、个人总结,谢绝转载、抄袭。如果您有疑问或者希望沟通交流,可以联系QQ:865562060。

一、简述

现阶段服务器、数据库上云的选择越来越多,但不是说服务器和数据库上云管理之后就可以安心睡觉了。做好云服务器和云数据库的备份管理也尤为重要。

最近用C#做阿里云数据库RDS的自动备份,感觉受到了很深的歧视。因为.Net模块里阿里云提供的demo是Java的,.Net SDK文档里的调用示例居然也是Java的。真是不让人省心的调用,经过几个小时的努力总算是摸索着dll弄好了。

我这里实现的思路是这样的:云数据库RDS我们是设置的云上保存7天的备份,每隔一天全量备份、隔一天增量备份,这些备份都有外链和内链支持下载(外网连接阿里云下载使用外链,但速度较慢;阿里云内网下载使用内链,速度非常快)。我要做一个定时运行的程序(我选择控制台应用程序,并在一台windows服务器上添加任务计划,定时运行这个控制台应用程序),自动下载云数据库备份的文件,并转储到指定地点。这里我转储两个地方,一个是公司磁盘(使用外链),另外一个是阿里云对象存储服务OSS(使用内链)。这样即使RDS和OSS都崩了,我本地也还有备份(虽然完全不可能出现这种情况)。

二、代码实现

1、创建控制台应用程序AliyunRDS(可以根据业务选择不同的程序),添加以下三个服务引用:aliyun-net-sdk-Core、aliyun-net-sdk-rds、Aliyun.OSS。

下载地址:https://develop.aliyun.com/tools/sdk?spm=a2c4g.11186623.2.10.7eea5234QGc6PP#/dotnet

主要下载以下三个:

2、 Program.cs中引用

using Aliyun.Acs.Rds;
using Aliyun.Acs.Rds.Model.V20140815;
using Aliyun.Acs.Rds.Transform.V20140815;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Http;
using Aliyun.OSS;
using Aliyun.OSS.Common;

3、主要代码实现

namespace AliyunRDS
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建DefaultAcsClient实例并初始化
            DefaultProfile profile = DefaultProfile.GetProfile(
                ConfigurationManager.AppSettings["RegionID"],// 您的可用区ID
                ConfigurationManager.AppSettings["AccessKey_ID"],// 您的AccessKey ID
                ConfigurationManager.AppSettings["AccessKey_Secret"]);// 您的AccessKey Secret
            IAcsClient client = new DefaultAcsClient(profile);
            // 创建API请求并设置参数
            CommonRequest request = new CommonRequest();
            request.Method = MethodType.POST;
            request.Domain = "rds.aliyuncs.com";
            request.Version = "2014-08-15";
            request.Action = "DescribeBackups";//查询RDS实例的日志备份文件,包括文件的下载链接。
            request.AddQueryParameters("DBInstanceId", ConfigurationManager.AppSettings["DBInstanceId"]);//实例ID
            request.AddQueryParameters("BackupStatus", "Success");//实例ID
            request.AddQueryParameters("StartTime", DateTime.Now.AddDays(-7).ToString("yyyy-MM-dd") + "T12:00Z");//查询开始时间。格式:yyyy-MM-ddTHH:mmZ,例如2018-10-31T08:40Z
            request.AddQueryParameters("EndTime", DateTime.Now.ToString("yyyy-MM-dd") + "T12:00Z");//查询结束时间。格式:yyyy-MM-ddTHH:mmZ,例如2018-10-31T08:40Z 必须晚于查询开始时间。
            request.AddQueryParameters("PageSize", "30");//每页最多显示的日志文件个数。取值:30,50,100默认值:30
            request.AddQueryParameters("PageNumber", "1");//页码。大于0且不超过Integer的最大值。默认值:1。
            // 发起请求并处理应答或异常
            CommonResponse response = new CommonResponse();
            try
            {
                response = client.GetCommonResponse(request);
                Result model = JsonConvert.DeserializeObject<Result>(response.Data);
                if (model != null)
                {
                    List<DataBaseBackupFiles> list = model.Items.Backup;
                    if (list.Count > 0)
                    {
                        //阿里云接口返回的数据库备份文件为按时间倒序排序。我们每天执行就取第一条下载
                        LogHelper.WriteProgramLog(DateTime.Now.ToString() + " 备份文件内网下载地址为:" + list[0].BackupIntranetDownloadURL);
                        //1、下载、设置参数 
                        HttpWebRequest requestFile = WebRequest.Create(list[0].BackupIntranetDownloadURL) as HttpWebRequest;
                        //发送请求并获取相应回应数据 
                        HttpWebResponse responseFile = requestFile.GetResponse() as HttpWebResponse;
                        //直到requestFile.GetResponse()程序才开始向目标网页发送Post请求 
                        Stream responseStream = responseFile.GetResponseStream();

                        //2、上传文件目录
                        string uploadPath = ConfigurationManager.AppSettings["uploadPath"];
                        if (!Directory.Exists(uploadPath))
                        {
                            Directory.CreateDirectory(uploadPath);
                        }

                        string[] strArray = list[0].BackupIntranetDownloadURL.Split(new string[] { "?" }, StringSplitOptions.RemoveEmptyEntries);
                        string fileName = "";
                        if (strArray.Length > 0)
                        {
                            string[] files = strArray[0].Split('/');
                            fileName = files[files.Length - 1];
                        }
                        else
                            fileName = DateTime.Now.ToString("yyyyMMddHHssmm") + new Random().Next(10000) + ".zip";

                        string filePath = uploadPath + "\\" + fileName;

                        //3、创建写入流 数据库备份文件可能非常大 所以这里使用分块下载
                        FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
                        byte[] bytes = new byte[1024 * 512];
                        int readCount = 0;
                        while (true)
                        {
                            readCount = responseStream.Read(bytes, 0, bytes.Length);
                            if (readCount <= 0)
                                break;
                            fs.Write(bytes, 0, readCount);
                            fs.Flush();
                        }
                        fs.Close();
                        responseStream.Close();
                        responseFile.Close();

                        string sResult = PutObject(ConfigurationManager.AppSettings["bucketName"], fileName, filePath);
                        if (!string.IsNullOrEmpty(sResult)) //Put Object请求处理成功后,OSS会将收到文件的MD5值放在返回结果的ETag中。用户可以根据ETag检验上传的文件与本地的是否一致。使用下面的方法GetMD5HashFromFile(),这里未做检验。
                        {
                            LogHelper.WriteProgramLog(DateTime.Now.ToString() + " 文件上传文件到OSS成功,删除本地文件!");
                            if (File.Exists(filePath))
                                File.Delete(filePath);

                            LogHelper.WriteProgramLog(DateTime.Now.ToString() + " 备份完成!");
                        }
                    }
                    else
                        LogHelper.WriteProgramLog(DateTime.Now.ToString() + " 查询到的备份文件列表为空!");
                }
                else
                    Console.WriteLine(DateTime.Now.ToString() + " 发生错误!");
            }
            catch (Exception ex)
            {
                LogHelper.WriteProgramLog(DateTime.Now.ToString() + " 发生错误:" + ex.Message);
                throw ex;
            }
        }

        /// <summary>
        /// 获取随机字符串
        /// </summary>
        /// <param name="length">长度</param>
        /// <param name="useNum">是否使用数字</param>
        /// <param name="useLow">是否使用小写字母</param>
        /// <param name="useUpp">是否使用大写字母</param>
        /// <param name="useSpe">是否使用特殊字符</param>
        /// <param name="custom">固定字符串</param>
        /// <returns></returns>
        public static string GetRandomString(int length, bool useNum, bool useLow, bool useUpp, bool useSpe, string custom)
        {
            byte[] b = new byte[4];
            new System.Security.Cryptography.RNGCryptoServiceProvider().GetBytes(b);
            Random r = new Random(BitConverter.ToInt32(b, 0));
            string s = null, str = custom;
            if (useNum == true) { str += "0123456789"; }
            if (useLow == true) { str += "abcdefghijklmnopqrstuvwxyz"; }
            if (useUpp == true) { str += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; }
            if (useSpe == true) { str += "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"; }
            for (int i = 0; i < length; i++)
            {
                s += str.Substring(r.Next(0, str.Length - 1), 1);
            }
            return s;
        }

        /// <summary>
        /// 上传本地的文件到指定的OSS的存储空间
        /// </summary>
        /// <param name="bucketName">指定的存储空间名称</param>
        /// <param name="key">文件的在OSS上保存的名称</param>
        /// <param name="fileToUpload">指定上传文件的本地完整路径</param>
        public static string PutObject(string bucketName, string key, string fileToUpload)
        {
            try
            {
                ClientConfiguration ossConfig = new ClientConfiguration();
                OssClient ossClient = new OssClient(
                    ConfigurationManager.AppSettings["endpoint"],
                    ConfigurationManager.AppSettings["OSSaccessKeyId"],
                    ConfigurationManager.AppSettings["OSSaccessKeySecret"],
                    ossConfig);
                var result = ossClient.PutObject(bucketName, key, fileToUpload);
                
                return result.ETag;
            }
            catch (Exception ex)
            {
                LogHelper.WriteProgramLog(DateTime.Now.ToString() + " 文件上传OSS失败!");
                LogHelper.WriteProgramLog(DateTime.Now.ToString() + ex.Message);
                throw ex;
            }
        }

        /// <summary>
        /// 获取文件的MD5码
        /// </summary>
        /// <param name="fileName">传入的文件名(含路径及后缀名)</param>
        /// <returns></returns>
        public static string GetMD5HashFromFile(string fileName)
        {
            try
            {
                FileStream file = new FileStream(fileName, System.IO.FileMode.Open);
                MD5 md5 = new MD5CryptoServiceProvider();
                byte[] retVal = md5.ComputeHash(file);
                file.Close();
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                LogHelper.WriteProgramLog(DateTime.Now.ToString() + " 获取文件的MD5码失败!");
                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
            }
        }
    }
}

 

三、实现效果

  • 1
    点赞
  • 6
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:技术黑板 设计师:CSDN官方博客 返回首页
评论

打赏作者

闷油瓶小锅

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值