SSIS互联网连接问题

时间:2016-01-18 23:52:28

标签: sql ssis ssas

因此,我们有一个多个SSIS包,它们并行运行以对多个多维数据集执行增量加载。这个套餐每晚都有。偶尔我们会遇到网络问题。现在,如果SSIS连接失去连接,它会使所有软件包失败。

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

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

1 个答案:

答案 0 :(得分:8)

@billinkc

的包依赖和可重启性方法

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

由于没有关闭时间以及SSIS现在正在> ,我知道包裹异常结束。也许它抛出了外键违规,也许网络掉线了。我真的不在乎这张桌子。唯一的功能是完成/未完成。如果它没有完成,那么当我们重新启动它时,它就是一个可供处理的候选人。

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

包执行历史记录全部在一个表中完成。 是SSIS将登录的sysdtslog90 / sysssislog / catalog.operation_messages表的替代品。根据您的版本,这些表格将包含有关包裹开始但未完成的实际详细信息。

让主人知道什么没有运行,它需要知道三件事

  • 什么是刷新间隔
  • 应该运行哪些流程
  • 已成功运行的内容。

刷新间隔 - 您的业务要求和/或数据可用性有助于规定这一点,但我认为它需要每天运行一次。但是,细节中的魔鬼,你如何定义那一天 - 从午夜,或过去24小时,或其他一些规则。无论是什么,你需要知道在部分重试变成中止并完全运行之前多久。

需要运行什么 - 至少,这是父母将调用的所有子包的列表。我喜欢做的听起来与你的方法类似,我并行运行了很多包,但在并行块中执行了串行执行。我在那里得到了很好的并行化而没有淹没盒子。

什么运行成功 - 你已经知道了答案!我们会查看我们的软件包执行历史记录,了解任何已开始运行的软件包,但这些软件包的结束日期并非如此。任何这些记录都需要重新启动(减少刷新间隔所需的烦恼)。

那是高级概念,希望不是;博士

实施

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

这将在您的数据库中创建3个对象(不包括表的insert / update / delete方法)。这两个表和一个存储过程确定了需要运行的包。将程序包主程序包名称输入需要工作的容器以及需要工作的程序包记录集(也就是自午夜以来未成功运行)。

-- 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

enter image description here

SQL Begin Audit

这是PackageHistory表的插入。我在整个板上指定系统变量,没有为ParentPackageID或StopTime指定值。 ExecutionID将来自System::ServerExecutionID,我认为其余的是不言而喻的。

SEQC Do Work X

这是一个序列容器。根据需要制作尽可能多的内容并行运行。 但是,只有在完成第一个完成后才能复制和粘贴,以使您的生活更轻松。

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

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

3个变量。

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

SQL获取工作列表

我们需要获取此容器应运行的所有包的列表。请记住我们创建的存储过程,让我们使用它。 SQL语句是,您需要指定执行SQL任务将返回完整结果集。

EXECUTE dbo.PackageProcesssingControlListGet ?, ?;

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

FELC Shred Work List

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

EPT Run Package

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

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

SQL结束审核

如果我们完成此任务,我们会更新ExecutionID和PackageID匹配的PackageHistory行以及StopTime IS NULL。

子包

这实际上只是父包,除了在中间没有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来自动化日光。今晚太晚了,让我写下来,但是在我太分心之前我会完成它。