【问题标题】:Caching to a local SQL instance on a web server缓存到 Web 服务器上的本地 SQL 实例
【发布时间】:2009-10-28 23:39:00
【问题描述】:

我运行着一个非常高的流量(每天 1000 万次展示)/使用 .net 构建的高收入网站。核心元数据存储在 SQL 服务器上。我和我的团队有一个独特的缓存策略,包括定期从中间层服务器查询数据库中的新元数据,将数据序列化为文件并将其发送到 Web 节点。 Web 应用程序使用这些文件中的数据(有些实际上是序列化对象)来实例化对象并将其缓存在内存中以用于实时请求。

这种模式的优势在于:

  1. 允许 Web 节点将所有数据缓存在内存中,并且查询数据库时不会产生任何 IO 开销。
  2. 如果数据库意外停机或因维护时段停机,Web 服务器将继续运行并产生收益。您甚至可以启动 Web 服务器,而无需从数据库中检索其初始数据,因为它需要的所有数据都在其自己磁盘上的文件中。
  3. 允许我们完全水平扩展。如果吞吐量受到影响,我们可以添加一个 Web 服务器。

缺点是这种缓存和持久层增加了查询数据库、打包数据和在 Web 服务器上解包的代码的复杂性。任何时候我们的领域模型需要我们添加实体,更多的这种“管道”必须被编码。这种架构已经存在了四年,可能有更好的方法来解决这个问题。

我一直在考虑的一个策略是使用复制将我们的主 sql 服务器数据库复制到安装在每个 Web 服务器上的本地数据库实例。 Web 服务器应用程序将使用普通的 sql/ORM 技术来实例化对象。在这里,我们仍然可以维持主数据库中断,我们不必编写专门的缓存代码,而是可以使用 nHibernate 来处理持久性。

这似乎是一个更优雅的解决方案,想看看其他人的想法,或者其他人是否有任何替代建议。

【问题讨论】:

    标签: sql-server architecture caching


    【解决方案1】:

    我认为你想多了。 SQL Server 已经为您提供了处理此类事情的机制。

    首先,实施 SQL Server 集群来保护您的主数据库。您可以在集群中从一个节点到另一个节点进行故障转移而不会丢失数据,停机时间最多只需几秒钟。

    其次,实施数据库镜像以防止集群故障。根据您使用的是同步镜像还是异步镜像,您的镜像服务器将实时更新或几分钟后更新。如果您实时执行此操作,您可以在应用程序内自动故障转移到镜像 - SQL Server 2005 及更高版本支持将镜像服务器的名称嵌入到连接字符串中,因此您甚至无需费力。该应用程序只是连接到任何正在运行的服务器。

    在这两件事之间,除了数据中心范围的停电或网络中断之外,您几乎不会出现任何主数据库故障,并且没有复制内容的复杂性。这涵盖了您的高可用性问题,并允许您单独回答扩展问题。

    我最喜欢的扩展起点是在您的应用程序中使用三个单独的连接字符串,并根据您的查询需要选择正确的一个:

    • 实时 - 直接指向一台主服务器。所有写入都转到此连接字符串,只有最关键的读取会转到此处。
    • 近实时 - 指向通过复制或日志传送更新的只读 SQL Server 的负载平衡池。在您的原始设计中,它们存在于 Web 服务器上,但这是一种危险的做法,也是维护的噩梦。 SQL Server 需要大量内存(更不用说许可费用),而且您不希望为每台 Web 服务器添加数据库服务器。
    • 延迟报告 - 目前在您的环境中,它将指向同一个负载平衡的订阅者池,但在未来,您可以使用日志传送等技术将服务器池延迟 8 到 24 小时。这些扩展非常好,但数据远远落后。它非常适合报告、搜索、长期历史记录和其他非实时需求。

    如果您将应用设计为从一开始就使用这 3 个连接字符串,则缩放会容易得多,并且不会涉及任何编码复杂性 - 只需选择正确的连接字符串即可。

    【讨论】:

      【解决方案2】:

      您考虑过 memcached 吗?既然是:

      1. 在内存中
      2. 可以在本地运行
      3. 完全可横向扩展
      4. 无需在每个 Web 服务器上重新缓存

      它可能符合要求。查看Google for lots of details 和使用案例。

      【讨论】:

      • 我对 memcached 的担忧是最初填充它的问题。尚未在缓存中的所有对象都必须转到数据库,如果数据库已关闭并且 memcached 集群同时失败。启动惩罚可能是巨大的。
      【解决方案3】:

      只是对 RickNZ 上述建议的一些补充。 由于您当前正在缓存的主数据不会如此频繁地更改并且可能会在某个维护时段内更改,因此您应该首先在数据库端执行以下操作:

      为要缓存的主表创建一个 SNAPSHOT 复制。添加新实体同样容易。 在所有网络服务器上,安装 SQL Express 并订阅此出版物。 由于这不是一个经常变化的数据,因此您可以放心,除了主数据的网络访问之外,没有太多的服务器资源使用问题。

      您通过以前的机制获得的所有缓存仍然可用,但在添加新实体时会出现所有令人头疼的问题。

      接下来,您可以利用上述建议的 .NET 机制。除非您的网络服务器本身出现故障,否则您不会面临 memcached 集群故障。 .NET 中有很多可用的东西,.NET 专业人士可以在此阶段之后指出。

      【讨论】:

        【解决方案4】:

        在我看来,Windows Server AppFabric 正是您要找的。 (又名“速度”)。来自introductory documentation

        Windows Server AppFabric 提供了一个 分布式内存应用 用于开发的缓存平台 可扩展、可用和 高性能应用。 AppFabric 融合多个内存 电脑给一个统一的 缓存视图到应用程序。 应用程序可以存储任何 可序列化的 CLR 对象 担心物体在哪里 存储。可扩展性可以通过 只需添加更多计算机 要求。缓存还允许 要存储的数据副本 集群,从而保护数据免受 失败。它作为服务运行 通过网络访问。在 此外,Windows Server AppFabric 提供无缝集成 启用 ASP.NET 会话的 ASP.NET 要存储的对象 分布式缓存,无需 写入数据库。这增加了 性能和可扩展性 ASP.NET 应用程序。

        【讨论】:

          【解决方案5】:

          您是否考虑过使用 SqlDependency 缓存?

          如果您担心初始启动时间或数据库中断,您也可以将数据写入 Web 层的本地磁盘。但至少使用 SqlDependency,您不必轮询数据库来查找更改。它也可以做得相对透明。

          根据我的经验,从可扩展性或性能的角度来看,在 Web 服务器上添加数据库实例通常效果不佳。

          如果您担心性能和可扩展性,可以考虑对数据层进行分区。具体情况取决于您的应用,但作为示例,您可以将只读数据移动到几个填充有复制的 SQL Express 服务器上。

          如果有帮助,我会在我的书中 (Ultra-Fast ASP.NET) 详细讨论这个主题。

          【讨论】:

            猜你喜欢
            • 2014-07-11
            • 2021-01-26
            • 2013-02-21
            • 1970-01-01
            • 2010-11-05
            • 2018-06-10
            • 1970-01-01
            • 2013-08-20
            • 2023-01-31
            相关资源
            最近更新 更多