【问题标题】:SSIS internet connectivity issueSSIS 互联网连接问题
【发布时间】:2016-01-18 23:52:28
【问题描述】:

所以我们有多个 SSIS 包,它们并行运行以对多个多维数据集执行增量加载。这个包每天晚上运行。有时我们会遇到网络问题。现在,如果 SSIS 失去连接哪怕是片刻,它也会使所有包都失败。

即使连接已激活并再次可用,它也不会自动尝试重新连接。它继续使用它在开始执行期间获取的相同连接信息来执行包。现在由于这个原因,所有剩余的包都失败了。为了再次连接,允许完成执行,然后有人必须手动重新处理包以获得新的连接信息。

所以我的问题是,我能否实现一个系统,如果 SSIS 失去网络连接,它会尝试自动检查连接是否在处理过程中可用,并尝试重新连接而不是使所有包失败?

【问题讨论】:

  • 我没有遇到过您在连接丢失但在包出错之前重新启用连接方面遇到的挑战。对于可能存在连接问题的包,我在其他地方所做的是告诉包的调用者,通常是 SQL 代理,在正式宣布该作业步骤失败之前重试 N 次。只要您已经很好地设计了您的包,在第 X 步重新开始处理应该只涉及第 X 步主包开始,但只有 SSAS 处理开始,因为暂存和 DW 加载已完成。
  • 我们实际上正在努力添加重试 n 次尝试以进行重新处理。但这并不能解决主要问题,因为将尝试使用相同的 Internet 连接信息重新处理这些包。失去互联网连接后,我需要一种方法来更新互联网连接信息。
  • 你能否为你的问题做一个可重现的例子?
  • 好的,所以我可能没有正确解释它。现在我们有超过 300 个立方体,我们每晚都在执行增量加载。每个立方体增量加载都是一个单独的包,所有这些都同时运行,其中 12 个彼此并行运行。可以说其他所有内容都已加载并正常工作。让我们假设成功执行了 125 个立方体包,但随后 SSIS 出现了连接中断。现在发生的情况是 175 个立方体包的其余部分将失败。我该如何解决这个问题?

标签: sql ssis ssas


【解决方案1】:

一种包依赖和可重启性的方法,@billinkc

我赞成一种非常精简的执行框架方法——它是一个两表系统,但已经足够了。在每个包的开头,都会触发一个执行 SQL 任务来启动日志记录。当 SSIS 包成功完成后,最后一步是关闭进程的审核行 - 另一个执行 SQL 任务。

由于没有关闭时间以及 SSIS 没有正确运行现在的事实,我知道包异常结束。也许它抛出了外键违规,也许网络掉线了。我真的不喜欢这张桌子。唯一的功能是完成/未完成。如果它没有完成,那么当我们重新启动它时,它就会成为处理的候选对象。

你说的处理候选人?是的,工人包是愚蠢的——他们只做我上面概述的事情。 Orchestrator/parent/master 包有责任担心哪些包需要运行以及以什么顺序运行。如果子包开始运行,那是因为它被告知要运行。它不“知道”它是否已经完成了它的工作。

包的执行历史都在一个表中完成。它不是替代 SSIS 将记录到的 sysdtslog90/sysssislog/catalog.operation_messages 表。根据您的版本,这些表格将包含有关软件包启动但未完成的实际详细信息。

要让master知道什么没跑,它需要知道三件事

  • 刷新间隔是多少
  • 应该运行哪些进程
  • 已经成功运行的内容。

刷新间隔 - 您的业务需求和/或数据可用性决定了这一点,但我认为它需要每天运行一次。魔鬼在细节中,你如何定义那一天——从午夜开始,或者在过去的 24 小时内,或者其他一些规则。不管是什么,您都需要知道在部分重试变成中止并执行完整运行之前多长时间。

需要运行的内容 - 至少,这是父级将调用的所有子包的列表。我喜欢做的事情听起来与您的方法相似,我并行运行许多包,但在该并行块内串行执行。我在那里得到了很好的并行化,而不会淹没盒子。

什么已经成功运行——你已经知道答案了!我们会查看任何已开始运行但没有结束日期的包的包执行历史记录。这些记录中的任何一个都需要重新启动(减少刷新间隔所需的摆弄)。

这是高级概念,希望不是 tl;dr

实施

选择一个数据库,任何数据库来保存这些信息。在某些地方我会创建一个专用的 SSISAudit 数据库,有时我会将其与其他元数据存储库相结合。

这将在您的数据库中创建 3 个对象(不包括表的插入/更新/删除方法)。这两个表和一个存储过程确定需要运行哪些包。将主程序包命名为您需要为其工作的容器,然后输出需要工作的程序包记录集(也就是自午夜以来未成功运行)。

-- This is my package execution history table
CREATE TABLE 
    dbo.PackageHistory
(
    PackageName sysname NOT NULL
,   PackageID uniqueidentifier NOT NULL
,   ParentPackageID uniqueidentifier NULL
,   ExecutionID bigint NULL
,   StartTime datetime NOT NULL
,   StopTime datetime NULL
,   Duration_s AS (DATEDIFF(SECOND, StartTime, StopTime))
);

CREATE TABLE dbo.PackageDependency
(
    MasterPackageName sysname NOT NULL
,   ContainerName sysname NOT NULL
,   ChildPackageName sysname NOT NULL
,   ExecutionOrderSequence int NOT NULL
,   CONSTRAINT PK_PackageDependency PRIMARY KEY 
    CLUSTERED
    (
        MasterPackageName ASC
    ,   ContainerName ASC
    ,   ChildPackageName ASC
    )
);

GO
-----------------------------------------------------------------------------
-- Function: AUD.PackageProcesssingControlListGet
-- Author: Bill Fellows
-- Date: 2016-01-18
--
-- This procedure will return a list of outstanding pacakges that need to 
-- be processed for a given container. Assumes that processing is done daily
--
-- Recordsets:
-- 0 to N rows will be returned to the caller
--
-- Side-effects:
-- None
--
-- See also:
--
-- Modified:
--
-----------------------------------------------------------------------------
CREATE PROCEDURE dbo.PackageProcesssingControlListGet
(
    @MasterPackageName sysname
,   @ContainerName sysname
)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT
        PD.ChildPackageName
    FROM
        dbo.PackageDependency AS PD
        LEFT OUTER JOIN
            -- Find packages that have not completed
            AUD.PackageControl AS PC
            ON PC.PackageName = PD.ChildPackageName
            -- Since midnight
            AND PC.StartTime > CAST(CURRENT_TIMESTAMP AS date)
            -- StopTime is only populated when package completes successfully
            AND PC.StopTime IS NOT NULL
    WHERE
        PD.MasterPackageName = @MasterPackageName
        AND PD.ContainerName = @ContainerName 
        AND PC.PackageName IS NULL
    ORDER BY 
        PD.ExecutionOrderSequence ASC;
END
GO

现在呢?让我们举一个简单的例子

这是主包的外观。原谅上面没有注释,我没有安装 Snagit,我对 mspaint 很烂

SQL 开始审计

这是对 PackageHistory 表的插入。我全面指定系统变量,没有为 ParentPackageID 或 StopTime 指定值。 ExecutionID 将是来自System::ServerExecutionID 的值,我认为其余部分是不言而喻的。

SEQC 工作 X

这是一个序列容器。尽可能多地制作这些,以使事情并行运行。 但是,只有在你完成第一个之后才能复制和粘贴,以使你的生活更轻松。

请注意,我定义了 3 个变量,它们的作用域是序列容器。默认情况下,在 2012+ 中,变量是在包级别范围内创建的。在 2005/2008 年,变量是在鼠标焦点所在的位置创建的。对于 2012+,正常创建变量,然后单击变量列表中的第二个图标,即“移动变量”。将这三个移到序列容器中。

这将允许我们使用范围规则来保持变量对其他容器隐藏。并且变得懒惰 - 我是懒惰的粉丝

3 个变量。

  • ContainerName - 这是您将存储在 PackageDependency 表的 ContainerName 列中的值。
  • CurrentPackageName - 这是当前项目中有效 SSIS 包的名称。没关系,因为它会被覆盖,但有 .dtsx 扩展名
  • rsWorkList - 这是一个 Object 类型的变量。它将保存我们存储过程调用的结果。

SQL 获取工作列表

我们需要得到这个容器应该运行的所有包的列表。记住我们创建的存储过程,让我们使用它。 SQL 语句是,你需要指定执行 SQL 任务将返回一个完整的结果集。

EXECUTE dbo.PackageProcesssingControlListGet ?, ?;

在结果集选项卡中,将名称 0 映射到 User::rwWorkList

FELC 粉碎工作清单

这是一个标准的shredding of a recordset。我们在上一步中填充了变量,所以让我们枚举结果。我们的结果集中将有一列,您将其映射到 User::CurrentPackageName

EPT 运行包

序列的最后一步是实际运行我们刚刚从工作列表中弹出的包,因此执行包任务具有基于变量 @[User::CurrentPackageName] 的 PackageName 表达式。

此外,我将使用 Parameter Bindings 选项卡 (2012+) 将当前 System::ExecutionID 作为参数 ParentExecutionID 传递给子包。

SQL 结束审计

如果我们完成此任务,我们将更新 ExecutionID 和 PackageID 匹配且 StopTime 为 NULL 的 PackageHistory 行。

子包

这实际上只是父包,除了中间没有 0 到 N 个序列容器之外,我们只是做子包所做的任何事情。我确实有一个包级别参数来接受父包 ID,但您不必这样做。

看起来很合理?如果是这样,那么您所要做的就是在 dbo.PackageDependency 表上做一些簿记。

INSERT INTO
    dbo.PackageDependency
(   MasterPackageName
,   ContainerName
,   ChildPackageName
,   ExecutionOrderSequence
)
SELECT
*
FROM
(
    VALUES
    (
        'so_34866238.dtsx'
    ,   'List0'
    ,   'C1.dtsx'
    ,   10
    )
    ,
    (
        'so_34866238.dtsx'
    ,   'List0'
    ,   'C2.dtsx'
    ,   20
    )
    ,
    (
        'so_34866238.dtsx'
    ,   'List1'
    ,   'D1.dtsx'
    ,   10 
    )
) D (MasterPackageName, ContainerName, ChildPackageName, ExecutionOrderSequence);

GO
-- Test we get expected results
-- 2 rows
EXECUTE dbo.PackageProcesssingControlListGet 'so_34866238.dtsx', 'List0';
-- 1 row
EXECUTE dbo.PackageProcesssingControlListGet 'so_34866238.dtsx', 'List1';
-- NULL rows
EXECUTE dbo.PackageProcesssingControlListGet 'so_34866238.dtsx', 'List2';

最后,虽然这还不错,但有点乏味。如果我要这样做,我会用一些 Biml 自动化日光。今晚我写的太晚了,但我会在我分心之前完成它。

【讨论】:

  • 感谢您提供如此详细的答案。虽然实现起来对我来说太复杂了。(请原谅我的愚蠢)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-14
  • 2013-08-16
  • 1970-01-01
  • 1970-01-01
  • 2019-03-16
  • 1970-01-01
相关资源
最近更新 更多