SaaS应用程序需要将数据导出/备份到各个客户站点

时间:2012-02-08 18:01:23

标签: c# .net sql-server-2008 saas

我们有一个基于云的SaaS应用程序,我们的许多客户(学校系统)要求将他们的数据备份存储在现场。

我们所有的应用程序数据都存储在一个MS SQL数据库中。在“层次结构”的最顶端,我们有一个“组织”。该组织代表我们系统中的单个客户。每个组织都有许多子表/对象/数据。每个人都有FK关系,最终以“组织”结束。

我们需要一种方法从数据库中提取 SINGLE 客户的数据,并以某种方式将其捆绑,以便将其下载到客户站点。最好是在SQL Express,SQLite或访问数据库中。

例如:Organization -> Skill Area -> Program -> Target -> Target Data是系统中的所有表。每个人都通过FK链接回父母。我需要获得每个组织的所有目标数据,目标,程序和技能领域,并导出该数据。

有没有人对如何在SQL Server,C#服务或第三方工具中执行此操作有任何建议?

我希望这个解决方案能够轻松复制给每个想要“启用”此功能的客户

想法?

9 个答案:

答案 0 :(得分:4)

我非常喜欢使用消息传递来传播数据,因此这里有一个基于消息的解决方案,允许外部客户保持您在网络上提供的数据的本地同步副本。

基本体系结构将是系统中发生的在线,密码保护和用户特定的更改列表。 在服务器端,只要对与特定客户相关的实体进行了更改,该列表就会附加到该列表中。 在客户端将运行一个应用程序,该应用程序检查尚未收到的任何更改列表,然后将它们应用到其本地数据库(按它们发生的顺序)。

有许多不同的方法来处理基于列表的系统组件,但我的直觉是你最好使用像RSS之类的东西来做到这一点。

下面是一个如何运作的实际场景:

  1. 为组织“我的组织”
  2. 创建了一个新技能区域
  3. 该技能被添加到中央数据库并与“我的组织”记录相关联
  4. 同时将SkillAreaExists事件添加到“my org”RSS中,其中包含指定新技能区域属性的JSON或XML数据
  5. 新计划将添加到刚刚创建的技能领域
  6. 该程序已添加到中央数据库并与技能领域相关联
  7. 同时将ProgramExists事件添加到“my org”RSS中,其中包含指定新程序属性的JSON或XML数据
  8. SkillAreaHasProgram事件也同时添加到“my org”RSS中,其中JSON或XML数据指定了技能领域和程序的标识符
  9. 客户端代理检查RSS提要并查看新消息并按顺序处理它们
  10. 处理SkillAreaExists事件时,新的技能区域将添加到本地数据库
  11. 处理ProgramExists事件时,会将新程序添加到本地数据库
  12. 处理SkillAreaHasProgram事件时,程序将链接到技能区域
  13. 与传统的时间点复制相比,这种方法有很多好处。

    • 在线,消费者可以根据需要获得实时更新
    • 如果您停止接收事件,您可以在事件流中的任何时间点按顺序维护合规性,您可以在某个时间点准确反映中央数据库的本地数据库。
    • 基于差异,您只需要接收更改
    • 它的可审计性,你可以看到实际上发生的事情不仅仅是现状。
    • 它很容易恢复,如果存在数据一致性问题,您可以通过重播事件流来恢复整个数据库。
    • 它允许多个消费者,客户信息的大量单独副本可以存在并自动运行。

    我们在网站之间复制数据的技术取得了很大的成功,特别是当它们有时只是在线时。

答案 1 :(得分:1)

虽然已经提出了一些非常有趣的企业解决方案,但我认为我的方法是开发一个平面旧的计划备份解决方案,只需使用存储过程或只是一些select语句为每个组织导出数据。

不可否认,当数据库架构发生变化时,您必须保持最新状态,但如果这是一个生产应用程序,我无法想象这种情况会发生很大的变化。

有许多技术可以做到这一点,无论是SSIS,自定义Windows服务,还是作为从命令行启动存储过程的计划任务的基本内容。

您选择导出的格式完全取决于您,并且可能应该由备份的使用方式驱动。我可能会考虑将数据写入多个CSV文件并压缩结果,以便在需要时将其导入其他平台。

其他选项可能是将数据复制到临时数据库,然后只创建该数据库的SQL备份。

然而,您选择了解它,我建议您确保该流程有详细记录,并尽可能自动安装和设置。具有松散耦合依赖关系的系统(例如公共文件位置或计划任务)很容易被调整并随时间发生变化。如果没有记录这些调整和更改,您可以创建一个有效但无法复制的系统。很快就没有人想触摸它,没有人记得它是如何工作的。当它最终需要改变时,或者更糟糕的是它会中断时,你必须先启动逆向工程才能修复它。

在基于云的环境中,这一点尤为重要,因为您希望能够尽快部署。如果需要完成大量配置,您可能会犯错或只是不一致。通过创建nuke-and-repave部署,您只需一个点就可以更改安装和配置,并且知道更改在任何部署中都是一致的。

答案 2 :(得分:0)

据我所知,您拥有一个适用于所有客户的大型数据库,您使用的关系可以让表组织知道哪个客户端的数据,以及您希望根据客户端=>备份数据的数据。组织。

要备份数据,您可以使用以下方法之一:

  • 根据@Phil和@Kris的评论,您可以使用SSIS进行自动备份,请检查this link for structure backup,然后查看此链接,了解如何Export a Query Result to a File using SSIS而不是文件执行此操作访问或SQL Server数据库。

  • 使用C#构建应用程序\服务以选择数据并手动导出,需要时间,但定制没有限制。

答案 3 :(得分:0)

答案 4 :(得分:0)

当我不得不处理过去关系数据的备份时(在MySQL中,你正在运行的MSSQL的功能方面并没有太大的不同)是创建一个备份“包”文件,它是本质上是一个具有不同文件扩展名的zip文件,因此Windows不允许用户打开它。

如果您真的想要获得幻想,请在压缩文件后加密文件并更改扩展名。我认为你正在为你的SaaS使用ASP,因为我是一个PHP-geek,我对代码方面的帮助太过分了,但我之前处理过的方式是一个脚本,它会打包整个Joomla站点和数据库,用于迁移到新服务器。

//open the MySQL connection
$dbc = mysql_connect($cfg->host,$cfg->user,$cfg->password);
//select the database
mysql_select_db($cfg->db,$dbc);

output( 'Getting database tables

');

//get all the tables in the database
$tables = array();
$result = mysql_query('SHOW TABLES',$dbc);
while($row = mysql_fetch_row($result)) {
    $tables[] = $row[0];
}

output( 'Found '.count($tables).' tables to be migrated.
Exporting tables:
');

$return = "";

//cycle through the tables and get their create statements and data
foreach($tables as $table) {
    $result = mysql_query('SELECT * FROM '.$table);
    $num_fields = mysql_num_fields($result);

    $return.= 'DROP TABLE IF EXISTS '.$table.";\n";
    $row2 = mysql_fetch_row(mysql_query('SHOW CREATE TABLE '.$table));
    $return.= $row2[1].";\n";

    while($row = mysql_fetch_row($result)) {
        $return.= 'INSERT INTO '.$table.' VALUES(';
        for($j=0; $j<$num_fields; $j++) {
            $row[$j] = mysql_escape_string($row[$j]);
            $row[$j] = ereg_replace("\n","\\n",$row[$j]);
            if (!empty($row[$j])) {
                $return.= "'".$row[$j]."'" ;
            } else {
                $return.= "NULL";
            }
            if ($j<($num_fields-1)) {
                $return.= ',';
            }
        }
        $return.= ");\n";
    }
}

这是PHP中代码的相关部分,它循环数据库结构并将重新创建脚本存储在$ result中,然后可以将其输出到文件中。

在您的情况下,您不希望重新创建数据库,而是重建数据本身。您已经略微复杂化了这个问题,因为您的SaaS很容易出现数据结构变化,您需要考虑这些变化。我的建议就是这样:

使用与上述类似的系统转储各个表中的相关数据。我只是简单地提取所有数据,但是你可以通过使用JOIN语句和诸如此类的东西来仅提取与单个用户相关的部分。将每个表的insert / replace语句的内容转储到以该表命名的文件中。创建一个名为manifest.xml的文件或类似的文件,并使用当前版本的SaaS应用程序,输出数据的客户端的名称/信息,唯一ID等填充该文件。

将所有这些文件打包成ZIP文件,将扩展名更改为您想要的任何内容,如果您愿意,可以对其进行加密等。让他们下载该备份文件并进行设置。

在导入脚本中,您需要读取导出数据的版本号,并将其与某些算法进行比较,该算法可以根据您稍后进行的修订来处理数据的重新映射。这样,如果您以后需要重新导入其中一个备份,则可以正确处理从将备份拉到当前表中数据的当前结构时的数据转换。

希望有帮助;)

答案 5 :(得分:0)

由于您将所有数据保存在一个数据库中,因此始终难以根据客户导出/备份数据。

即使您现在实现了这样的场景,每次更改数据库架构(修复错误,添加新功能,优化等)时,您最终都需要维护/更改/测试两个不同的位置。

我建议您对数据进行分区,例如,每个组织使用一个数据库。然后,您只需更改一次应用程序(主要是为指定组织构建连接字符串),然后您可以以您希望的方式单独导出/备份每个数据库。

它还为您提供了许多额外的“免费”优势,例如可扩展性和为每个组织提供资源的能力(无论将来是否需要)。 比如说,您有一组小优先级(从业务角度来看)组织,以及一个高优先级的组织。因此,您将能够在一台服务器上保留一组小的低优先级数据库,但为特定的重要大型数据库专用另一台数据库。 或者,如果您当前的数据库服务器过载(可能您有大量数据和对数据库的大量请求),您可以简单地获得另一个便宜的服务器并移动一半的负载而不需要对系统进行任何更改... 您仍然需要编写一些内容才能将现有的大型数据库拆分成几个小型数据库,但是您只需执行一次,完成后可以将此“迁移工具”丢弃,这样您就不再需要支持它了

答案 6 :(得分:0)

你试过SyncFramework吗? 看看this文章吧! 它解释了如何使用Sync Framework在数据库之间同步过滤数据。 您可以同步到客户的数据库或同步到您自己的空数据库,然后将其导出为文件。

答案 7 :(得分:0)

您是否考虑过使用ORM? (对象关系映射器)

我知道并使用LLBLGen Pro(所以我只能谈谈这个特定ORM的功能)
无论如何,使用LLBLGen,您可以对数据库进行反向工程,并创建一个类层次结构,用于映射数据库的表和关系。

现在如果通过关系可以访问客户的所有数据,我可以告诉我的ORM框架加载单个客户(特定表的1行),然后在相关表中加载所有相关数据。

如果数据不太复杂,应该可以 如果您有数百个自引用表或奇怪的关系,它可能是可撤消的,它取决于您的数据。

如果单个客户的所有数据都是100个表中的10,000行,那么它可能会起作用 如果1000个表中的所有数据都是100'000行,那么如果你有一些时间和大量的内存它“可能”起作用。
如果所有数据都是10'000'000,您可能无法一次加载所有数据,并且您需要一种更有效的方式。

无论如何,如果您可以一次加载所有数据,那么您将拥有一个包含单个客户的所有数据的“内存”图表,然后您可以序列化此数据,或将其投影到数据集上(获取一组数据表/关系)然后序列化数据集。

使用ORM来加载和导出单个客户的所有数据,可能不是最有效的处理方式,但是当可行时,这是一种简单而廉价的方式。
当然,无论有没有ORM,您都可以找到数百种不同的方式来导出这些数据: - )

答案 8 :(得分:0)

对于您的设计,您应该为客户分割数据库。

但是,由于您已经开发了数据库设计,我建议您使用FK关系创建临时数据库并在此临时数据库中创建新表。

为此,您需要根据FK关系对表进行排序,并在临时数据库中创建它们。

然后,从源数据库中选择表数据并将它们插入临时数据库。

您还可以使用此技术对数据库进行分片并修改数据库设计。

阿拉汶