内部 SharePoint 为 SharePoint 创建外部的存储解决方案

Pav Cherny

可在代码下载: ChernySharePoint2009_06.exe(2,006 KB)

内容

内部二进制存储
外部的二进制存储
生成非托管的 EBS 提供程序
生成托管的 EBS 提供程序
在 SharePoint 中注册的 EBS 提供程序
实现垃圾回收
结论

将多达 80%的数据存储在 Microsoft Windows SharePoint Services (WSS) 3.0 和 Microsoft Office SharePoint Server (MOSS) 2007 内容数据库的 Microsoft 估计值为非关系的二进制大对象 (BLOB) 数据如 Microsoft Office Word 文档、 Microsoft Office Excel 电子表格和 Microsoft Office PowerPoint 演示文稿。 只有 20%是意味着 suboptimal 利用在数据库后端的 Microsoft SQL Server 资源的关系元。 SharePoint 会不利用 SQL Server 2008 中, 引入如 FILESTREAM 属性或远程 BLOB 存储 API 的非结构化数据的最新 SQL Server 创新但提供自己的选项来提高存储效率和可管理性大容量数据卷。

具体来说,SharePoint 包括提供外部的二进制存储程序 API 的第一次为中的修复程序发布的 Microsoft 可能 2007 的 ISPExternalBinaryProvider 和更高版本到 Service Pack 1 的并入。 在 ISPExternalBinaryProvider API 是独立于远程的 BLOB 存储 API。 第三方供应商使用该 API 可以 SharePoint 集成高级的存储解决方案如内容可寻址存储 (CAS) 系统。 可以使用此 API,如果您想构建自定义解决方案以提高存储效率和可伸缩性在 SharePoint 集群中的维护外部的内容数据库中心文件服务器上的 SharePoint BLOB 数据。 请注意,但是,此 API 是特定于 WSS 3.0 和 MOSS 2007。 它会更改这意味着您将不得不更新您的提供程序在下一个 SharePoint 版本中。

在本专栏,我将讨论如何扩展 SharePoint 存储体系结构使用包括优点和缺点,实现详细信息、 性能方面的考虑和垃圾回收的 ISPExternalBinaryProvider API。 我还讨论了 64 位兼容性问题可能导致 SharePoint 无法加载 Microsoft Visual Studio 托管 ISPExternalBinaryProvider 组件,尽管一个正确的接口实现。 在适当,我请参阅 ISPExternalBinaryProvider 文档,WSS 3.0 SDK 中。 值得一提的另一个引用的是 Kyle Tillman 博客.

Kyle 会很好的作业,说明如何他掌握在托管代码,实现障碍,但 WSS 3.0 SDK 既 Kyle 的博客张贴内容包括在 Visual Studio 示例项目,以便我决定提供在本专栏附带材料的非托管和托管代码中的 ISPExternalBinaryProvider 示例。 这些示例旨在帮助您如果您有兴趣与 SharePoint 集成外部的存储解决方案。 但是记住,这些示例是未经测试,并且不准备生产目的。

内部二进制存储

默认情况下, SharePoint 存储 BLOB 数据内容的数据库中,AllDocStreams 表的内容的列中。 此方法的明显优点是关系数据和关联的非关系文件内容之间的简单事务一致性。 也是例如它的不复杂内容的数据库中插入 Word 文档以及与非结构化内容的元数据不是复杂关联与选择,更新中, 相应的非结构化内容的元数据,或删除操作。 但是,默认方法的最明显的缺点是存储资源的效率很低使用。 尽管适合高性能的 I / O 子系统,SQL Server 存储引擎不完全是文件服务器替换。

SQL Server 数据库包含的事务日志和数据文件,如 图 1 所示。 为了确保可靠的事务行为,SQL Server 首先写入所有交易记录在日志文件之前它将 8KB 页中相应的数据刷新到磁盘上的数据文件。 根据所选的恢复模式,这要求多个 BLOB 倍中存储容量直到执行备份并清除事务日志。 此外,SQL Server 不会直接在数据页中存储非结构化的 SharePoint 内容。 相反,SQL Server 会使用不同的文本 / 图像页的集合,并仅存储数据行中的一个 16 字节文本指针,指向 BLOB 的根节点。 文本 / 图像页组织在一个平衡的树中,但没有为每个表的文本 / 图像页的只有一个集合。 对于 AllDocStreams 表,这意味着所有文件的内容分布相同的文本 / 图像页集合。 单个文本 / 图像页可以包含从多个 BLOB,数据片段或它可能会保存中间节点的 BLOB 超过 32KB 的大小。

fig01.gif

图 1 SQL Server 中的默认 SharePoint BLOB 存储

让我们不深入太深 SQL Server 内部,但。 关键是在读取非结构化的内容,SQL Server 必须要获取的文本指针数据行,然后通过 BLOB 的根节点和可能是其他中间节点,以定位所有的数据片段分布在任意数量的文本 / 图像页的 SQL Server 必须加载到完全将所有的数据块的内存。 这是因为 SQL Server 可以执行在页级别的 I / O 操作。 这些复杂情况会影响与通过文件系统的直接访问相比的流文件的性能。 SQL Server 还实施硬盘大小限制为 SharePoint 上的 2GB,因为这是图像数据类型的最大容量。 AllDocStreams 表的该内容列是一个图像列,因此您无法将大于 2GB 的文件存储在 SharePoint 内容数据库。

外部的二进制存储

ISPExternalBinaryProvider API 提供了 SharePoint 内容数据库中的内部 BLOB 存储的智能化除了。 它是一简单的 COM 接口,只有两个方法 (StoreBinary 和 RetrieveBinary) 可以使用若要实现的外部二进制存储 (EBS) 提供程序。 有关体系结构的详细信息请参阅相关主题" 外部 BLOB 存储的体系结构"中 WSS 3.0 SDK 中。

SharePoint 提供程序的 COM 类标识符 (CLSID) 加载您 EBS 提供程序在设置本地 SPFarm 对象 (SPFarm.local.ExternalBinaryStoreClassId) 的 ExternalBinaryStoreClassId 属性时。 只要您提交 BLOB 数据 (如) 时您正在上载文件到文档库,请 SharePoint 将调用提供程序的 StoreBinary 方法。 EBS 提供程序可以决定将 BLOB 存储在其关联的外部存储系统并向 SharePoint 中, 返回相应 BLOB 标识符 (BLOB ID),或者可以设置 pfAccepted 参数为 False,则表示未处理 BLOB StoreBinary 方法中。 在后一种情况下 SharePoint 同往常一样存储内容数据库中的 BLOB。 而在另一方面,如果 EBS 提供程序接受 BLOB,SharePoint 仅 BLOB ID 内容列插入在 AllDocStreams 表的 图 2 所示。 在 BLOB ID 不能启用 EBS 提供程序,在外部存储系统如文件名、 文件路径、 一个全局唯一的标识符 (GUID),或内容的摘要中查找内容的任何值。 该助理材料中包含该示例提供程序对于是实例用作 GUID 文件名的 BLOB 的可靠标识,在文件服务器上。

fig02.gif

图 2 存储外部存储系统中的 SharePoint BLOB

SharePoint 也跟踪的外部存储的文件通过最高的 DocFlags 位,这些文件的设置为 1。 DocFlags 是 AllDocs 表的列。 当用户请求下载的外部存储的文件时,SharePoint 将检查 DocFlags,并将 AllDocStreams 表中的内容的值传递给 EBS 提供程序的该 RetrieveBinary 方法。 在到 RetrieveBinary 呼叫的响应 EBS 提供程序必须从外部存储系统中检索指定的 BLOB,并返回到 SharePoint 实现 ILockBytes 接口的 COM 对象形式的二进制内容。 请注意,SharePoint 的存储直接在内容数据库的 BLOB 不调用 RetrieveBinary 方法。

注意还存储和检索进程是对用户透明,只要用户不会尝试绕过 SharePoint。 因此,不必替换领带文档列表中的元数据存储外部 ; 生产力的应用程序,如 Microsoft Office 不需要知道如何将元数据存储在一个位置,然后另 ; 文档和搜索不需要处理不同于文档的元数据的自定义版本的内置 Web 部件。 此外,这是我喜欢 EBS 提供程序体系结构优点之一,用户必须通过 SharePoint 访问外部存储的 BLOB 数据。 用户绕过 SharePoint 并直接通过 SQL Server 连接访问内容的数据库最终下载 BLOB ID 而不是实际的文件内容如 图 3 所示。 可以验证此问题,如果您在测试环境中部署 SQL 下载 Web 部件 (我用于在 4 月 2009 列演示如何绕过 SharePoint AD RMS 保护)。 此外,不需要用户,并且不应) 访问外部的 BLOB 存储的权限。 仅 SharePoint 的安全帐户需要访问,因为 SharePoint 站点的应用程序池帐户的安全上下文中调用 EBS 提供程序方法。

fig03.gif

图 3 The EBS 提供商可以是要绕过文件下载的 SharePoint 权限的 roadblock

请注意,但是,EBS 提供程序还具有维护 SharePoint场的内容数据库中的元数据和外部的 BLOB 存储之间的完整性的复杂性由于的缺点。 有关优点和缺点好讨论检查出主题" 操作的限制和 Trade-Off 分析"中 WSS 3.0 SDK 中。 请确保您在 SharePoint 环境中实施 EBS 提供程序之前阅读本非常重要的主题。

生成非托管的 EBS 提供程序

现在让我们解决构建 EBS 提供程序的挑战。 ISPExternalBinaryProvider 接口是完善在 WSS 3.0 SDK 中的" BLOB 访问接口: ISPExternalBinaryProvider." 但是,似乎 Microsoft 忘了涵盖 EBS 提供程序详细信息。 别是忘我们不只占用现有的 COM 服务器接口。 我们将承担任务自己生成的 COM 服务器,和实现 ISPExternalBinaryProvider 接口。 最重要的是,WSS 3.0 SDK 无法告诉我们应该能够构建和所需的线程模型的 COM 服务器的类型。 传统的 COM 服务器将可以运行,进程外或的进程,可以支持单线程单元 (STA) 模型和/或在多线程的单元 (MTA) 模型或自由线程模型。 对于 EBS 提供程序才能正常工作,请确保您生成线程安全的进程 COM 服务器支持线程模型"同时"STA 和 MTA。

还需要考虑要使用的编程语言。 这是重要的因为 ISPExternalBinaryProvider 接口与 SharePoint 最低级别 API。 性能问题会影响整个 SharePoint 服务器场。 由于这个原因,我建议使用使您能够生成小并快速 COM 对象,(如 Visual C++ 和活动模板库 (ATL) 的语言。 ATL 提供有用的 C++ 类,来简化开发的非托管代码中的线程安全 COM 服务器使用正确的线程处理支持级别。

Visual Studio 还包括各种 ATL 向导。 只需创建一个 ATL 项目,服务器类型,WSS 3.0 SDK 中的接口定义到 ATL 项目的接口定义语言 (IDL) 文件,添加一个新类的一个简单 ATL 宏对象选择的 ISPExternalBinaryProvider"同时"线程模型和聚合函数,然后右键单击新类别,指向添加,单击实现接口和副本选择 ISPExternalBinaryProvider 中选择动态链接库 (DLL)。 就是这样 ! 实现接口向导执行所有的必要管道,因此您可以集中精力实现 StoreBinary 和 RetrieveBinary 方法。

并不让望而生畏在非托管的 C++ 代码。 如果您分析助理材料中将 SampleStore.cpp 文件时,您可以看到 StoreBinary 和 RetrieveBinary 实现了相对简单。 实质上是,示例 StoreBinary 方法构造基于 StorePath 注册表值的文件路径站点 ID 从 SharePoint,和为该的 BLOB 生成的 GUID 传递中,然后使用 Win32 WriteFile 函数来保存从 ILockBytes 实例获取二进制数据。 而在另一方面,该示例 RetrieveBinary 方法构造基于相同的 StorePath 注册表值、 该站点 ID 和 BLOB ID 从 SharePoint,传入文件路径,,然后使用 Win 32 ReadFile 函数检索非结构化的数据 EBS 提供程序将复制到一个新的 ILockBytes 实例,然后传递回到 SharePoint。 图 4 说明了如何 EBS 提供程序构造文件路径。

fig04.gif

图 4 StoreBinary 和 RetrieveBinary 中的操作示例 EBS 提供程序创建的文件路径

生成托管的 EBS 提供程序

当然,SharePoint 开发人员可能更喜欢使用熟悉的托管的语言构建 EBS 提供程序,即使构建托管 EBS 提供程序不一定不复杂比构建提供非托管的程序由于 COM 互操作性的复杂性。 请记住在非托管代码中编写的应用程序只能加载一个公共语言运行库 (CLR) 版本,因此您的代码需要使用相同版本的 SharePoint 其余部分使用的 CLR 的否则您可能会得到意外的行为。 此外,仍必须处理非托管的接口和相应整理参数和缓冲区。 只是在助理材料中将比较与 SampleStore.cs SampleStore.cpp。 没有获得使用托管的语言的代码结构,或编程简单。

此外,应了解 64 位兼容性问题如果您开发 x 64 平台上的托管的 EBS 提供程序。 图 5 显示了典型的错误从开发计算机上的无效 COM 注册设置的。 如果您启用了注册 Visual Studio 2005 或 Visual Studio 2008 中的项目属性中的 COM 互操作复选框将得到了您 HKEY_CLASSES_ROOT\Wow6432Node\CLSID\ 注册表中的提供程序的 COM 注册设置 <providerclsid>。 Visual Studio 使用投入 x 64 平台的 32 位版本的程序集注册工具 (Regasm.exe)。

fig05.gif

图 5 由于为无效的 COM 注册设置,托管的 EBS 提供程序不能加载

但是,在 64 位版本的 SharePoint 无法加载 32 位 COM 服务器注册在的 Wow6432Node 下,因此必须使用 64 位 Regasm.exe 版本 %WINDIR%\Microsoft.NET\Framework64\v2.0.50727 目录中手动注册托管的 EBS 提供程序。 是例如命令"%WINDIR%\Microsoft.NET\Framework64\v2.0.50727\Regasm.exe ManagedProvider.dll 创建托管的示例提供程序在 HKEY_CLASSES_ROOT\CLSID\ <providerclsid> 所需的注册表设置。 另一种方法是创建安装程序,并标记 EBS 提供程序以自动的 COM 注册。

此外请记住,托管的 EBS 提供程序附带非托管 ATL 对应于明显更多的开销和性能损失。 您可以看到这如果比较 COM 注册设置在注册表中。 为 InProcServer 键显示中,COM 运行库加载托管的 EBS 提供程序 DLL 直接,而托管的 EBS 提供程序依赖 Mscoree.dll 与过程中的服务器,这是在 CLR 的核心引擎。 因此,托管的提供程序 COM 运行库加载 CLR,然后 CLR 加载 EBS 提供程序程序集注册程序集项下创建一个 COM 可调用包装 (CCW) 代理来处理非托管的 SharePoint 客户端 (Owssvr.dll) 和托管的 EBS 提供程序之间交互。

请记住,在非托管的 SharePoint 服务器不直接交互,与您的托管提供程序。 就在封送参数、 调用在托管的方法和处理 HRESULT 的 CCW。 此间是非常明显不同的返回类型与非托管方法相比的托管方法中。 非托管的方法将返回以指示托管的方法应具有 void 返回类型时是成功还是失败的 HRESULT。 因此未返回显式的 HRESULT 托管代码。 您必须提升系统或用户定义的异常,以响应错误条件。 如果托管的方法完成异常没有,在 CCW 自动返回 S _ OK 非托管客户端。

而在另一方面,如果托管的方法引发异常,在 CCW 映射错误代码和消息到 HRESULT 和错误信息。 在 CCW 实现各种错误处理接口为此件箱如 ISupportErrorInfo 和 IErrorInfo,但是 SharePoint 会不利用这些接口中。 EBS 提供程序必须实现自己错误,报告通过 Windows 事件日志、 SharePoint 诊断日志、 跟踪文件或其他方式。 SharePoint 只需要 HRESULT 值 S _ OK 成功和 E _ FAIL 任何错误的。 您可以使用 Marshal.ThrowExceptionForHR 方法向 SharePoint,返回 E _ FAIL,如 SampleStore.cs 所示。

在 SharePoint 中注册的 EBS 提供程序

轻松地最令人困惑的部分,在 WSS 3.0 SDK 中的 ISPExternalBinaryProvider 是主题" 安装和配置 BLOB 提供程序." 在撰写本文时,此部分已填充误导性的信息和错误。 即使有 Windows PowerShell 命令是不正确。 如果 EBS 提供程序给 $ yourProviderConfig 并且以后使用 $ providerConfig.ProviderCLSID,不要将惊讶当您收到错误,指出该 $ providerConfig 不存在。 当然,您不会甚至到达这一点,因为活动,ProviderCLSID 属性不会 ISPExternalBinaryProvider 接口的一部分。 这些特殊的属性属于于一个双接口,且没有覆盖文档中。 只是为了乐趣,我在同时托管和托管的代码中实现了一个示例的版本,但 ISPExternalBinaryProvider 实现根本不需要这些专用属性。

ProviderCLSID 属性可能非常方便,但 CLSID 也是可在注册表中如果您搜索 ProgID,如 UnmanagedProvider.SampleStore 或 ManagedProvider.SampleStore,并且还可以在代码文件 SampleStore.rgs 和 SampleStore.cs 中找到 CLSID。 如前文所述,将本地 SPFarm 对象的 ExternalBinaryStoreClassId 属性设置为 CLSID 注册 EBS 提供程序。 将本地 SPFarm 对象的 ExternalBinaryStoreClassId 属性设置为空的 GUID ("00000000-0000-0000-0000-000000000000"),将删除 EBS 提供程序注册。 请不要忘记调用 SPFarm 对象的更新方法,在配置数据库中保存所做的更改并重新启动 Internet Information Services (IIS)。 下面的代码清单演示了如何完成 Windows PowerShell 中的这些任务:

[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SharePoint')
$farm = [Microsoft.SharePoint.Administration.SPFarm]::Local

# Registering the CLSID of an EBS provider
$farm.ExternalBinaryStoreClassId = "C4A543C2-B7DB-419F-8C79-68B8842EC005"
$farm.Update()
IISRESET

# Removing the EBS provider registration
$farm.ExternalBinaryStoreClassId = "00000000-0000-0000-0000-000000000000"
$farm.Update()
IISRESET

实现垃圾回收

WSS 3.0 SDK featuring 的特殊组件和关键代码段中的另一部分的标题为" 实现惰性垃圾回收." 撰写本文时此部分包含对另一个特殊的实用工具类的引用 DirFromSiteId 和 FileFromBlobid 方法以及的 directory.GetFiles 结果为一个 FileInfo 数组错误分配但让我们不会太节省 WSS 3.0 文档质量。 在 DirFromSiteId 和 FileFromBlobid 帮助器方法显示通过其名称及其用途和不正确的 FileInfo 数组轻松地替换一个字符串数组,或您可以使用对 DirectoryInfo 对象的该 GetFiles 方法的调用替换 directory.GetFiles 方法。 助理材料中将垃圾回收器示例程序使用 DirectoryInfo 方法,并遵循垃圾回收的步骤的建议的顺序。

从 SDK 说明垃圾回收器示例的一个重要偏差与时间条件处理。 这是关键的问题,因为计时条件导致 misidentification 和垃圾收集期间删除有效的文件。 请看一下 图 6 ,它说明了通过枚举 EBS 存储中的所有 BLOB 文件,以及然后从该站点的 ExternalBinaryIds 集合所示仍中内容的数据库的 BLOB 列表中删除所有这些引用确定孤立的文件,WSS 3.0 SDK–recommended 方法。 BLOB 列表中剩余的引用都应该指示应删除孤立的文件。

fig06.gif

图 6 为孤立由于到一个计时条件的有效 BLOB 的 Misidentification

但是,EBS 提供程序必须当然,首先完成写入 BLOB 数据,它可以返回一个 BLOB ID 到 SharePoint 之前。 根据网络带宽和其他条件,可以 fluctuate I / O 性能。 因此,没有机会 EBS 提供程序可以创建新的 BLOB 的然后出现在您的 BLOB 列表,但完成因此 BLOB ID 不还此集合中,已确定在 ExternalBinaryIds 后中写入 BLOB 数据。 相应,对新的 BLOB 仍保留在孤立的 BLOB 列表并且如果此时清除孤立的 BLOB 意外删除有效的内容项目丢失数据 ! 为了避免此问题,示例垃圾回收器将检查文件的创建时间,并将仅这些项目添加到多个一小时旧的 BLOB 列表。

结论

通过与 SharePoint 集成的外部存储解决方案,可以提高存储效率、 系统性能和 SharePoint场的可伸缩性。 另一个优点是此强制用户以通过访问非结构化的内容的 SharePoint。 提取数据内容数据库,通过直接 SQL Server 连接只生成二进制 BLOB 标识符,而不是实际的文件。 但是,EBS 提供程序还具有维护 SharePoint场的内容数据库中的元数据和外部的 BLOB 存储之间的完整性的复杂性由于的缺点。

为了 SharePoint 集成的外部存储解决方案,您必须创建它是 COM 服务器与其 StoreBinary 和 RetrieveBinary 方法实现 ISPExternalBinaryProvider 接口的一个 EBS 提供程序。 您可以创建非托管管理 EBS 提供程序,但需要注意的性能和兼容性问题,如果您决定使用托管的代码。 此外请注意 ISPExternalBinaryProvider 接口不包含 DeleteBinary 方法。 必须显式删除孤立的 BLOB 历延迟垃圾回收的集合并小心避免计时条件导致有效 BLOB 项目在意外删除。

Pav Cherny 是 IT 专家和擅长 Microsoft 技术协作和统一的通信的作者。 他出版物包括白皮书、 产品手册和联机重点 IT 操作和系统管理。 Pav 是总裁的 Biblioso Corporation,于托管的文档和本地化服务的公司。