1

在研究 nhibernate 中二级缓存提供的可能性时,我测试了一些实现。目前结果出乎意料,我怀疑我的期望是否错误。

  1. 场景(重读)

首先将 4 * 20000 个具有一个字符串属性的简单对象插入数据库,然后四个线程通过对象 ID ( session.Get<SimpleObj>(id)) 获取它们。每个线程只访问它创建的 ID。访问模式是随机的,获取 1000 个对象,然后重新创建会话。

while (true)
{
    using (var session = sf.OpenSession())
    using (var tx = session.BeginTransaction())
    {
        for (int i3 = 0; i3 < 1000; i3++)
        {
            long id = (long)ids[rnd.Next(19999)];
            var t = session.Get<SimpleObject>(id);

            var no = t.StringProperty;
        }

        Interlocked.Add(ref ops, 1000);

        tx.Commit();
    }
}

结果

  1. Redis 每秒 5000 次读取
  2. MemCached 每秒 8000 次读取 (EnyimMemcached)
  3. 无缓存每秒 15000 次读取(同一台机器,TCP-IP)
  4. 无缓存每秒 25000 次读取(同一台机器,共享内存)
  5. SysCache2 每秒 200000 次读取
  6. HashtableCacheProvider 每秒 380000 次读取

使用的版本

这些提供程序和 SysCache2 实现之间的不同性能是否可以预期?

更新 1

正如 Frederic 指出的那样,测试场景没有太大意义,因为比较了具有两种不同用例的两种不同类别的缓存架构。第一类(5 和 6)不能水平缩放,而 1 和 2 可以。目前 SQL-Server 在同一台机器上运行,因此使用共享内存作为 IPC 机制,因此我禁用了所有 IPC 连接可能性,并将其配置为使用 TCP/IP 连接到数据库。结果,no-cache-scenario 的性能下降了大约 10000 op/s,这使最快的分布式缓存提供程序进入了合理的距离。

通过比较缓存提供程序,我想测试这些提供程序是否可以在每个请求的会话设置中用于缓存参考数据,例如国家、货币或资产负债表结构。由于性能最好的分布式缓存的性能仍然只有普通 NHibernate 版本的 op/s 的一半,我不确定这是否是要走的路。

4

2 回答 2

1

这并不奇怪SysCache(2)(或者RtMemoryCache如果你也尝试另一个)表现得比Redisor好得多MemCached。前者是进程内内存缓存,它们的使用不会产生任何网络 IO 或任何进程间通信。后者是分布式缓存,它们至少意味着进程间通信,并且在大多数情况下是网络IO,这会产生相当高的使用成本。

将分布式缓存性能与非分布式缓存性能进行比较没有任何意义。仅当您需要在多个进程之间共享缓存时才应使用分布式缓存。如果您有此要求,您将无法使用非分布式缓存。

令人惊讶的是,“无缓存”场景(即 SQL 查询)的性能比分布式缓存好得多。

在我看来,您的测试描述中缺少一个关键点:在您的场景中,是什么驱动了 SQL 查询的性能成本?如果 db 服务器与 Web 服务器托管在同一物理主机上,则与更常见的设置相比,此成本相当低。一些数据库解决方案(如 SQL Server)甚至可以跳过任何网络 IO,并在与 Web 服务器托管在同一主机上时进行内存通信(通过命名管道)的进程间通信。

旁注:如果您不考虑配置SysCache2为通过 SQL Server 数据更改通知失效,则应SysCache改为进行测试,这样更轻松。(不过,这可能不会真正改变您的测试场景中的结果。)

解决更新 1:

第一点是确保您确实需要分发缓存。如果满足以下条件,每个进程都可以安全地拥有自己的缓存:

  1. 缓存的数据是只读的(或者最终,如果某些进程提供过时的缓存数据不会在您的应用程序案例中造成问题)。
  2. 这不会导致过多的内存消耗。(缓存数据并不重,在许多进程中复制它不是问题。)

当然,非分布式缓存的数据缓存预热会更慢,但如果分布式缓存性能太差,这不是重点。

如果您需要分发它,那么您应该评估您的 SQL Server 是否是负载下的瓶颈。如果负载不足,您的 SQL Server 可能会成为应用程序的瓶颈,那么分布式缓存将有助于卸载它。否则,如果在您的设置中,分布式缓存的性能始终比您的数据库服务器差,最好不要使用它们。

旁注:如果仅满足条件(2.),您还可以尝试使用 SQL Server 通知失效的非分布式缓存,从而避免过时的数据。请参阅此处了解如何配置SysCache2SQL Server 通知。

于 2016-04-01T08:38:55.463 回答
1

Frederic 已经写过你测试了两种完全不同类型的缓存,所以我不会再重复了。但我将添加一些关于 NH 缓存如何工作的信息并回答 Frederic 的评论:

令人惊讶的是,“无缓存”场景(即 SQL 查询)的性能比分布式缓存好得多。

实际上,这并不奇怪 :) 您需要记住:

  1. NHibernate 尝试使用缓存来保证安全,并在每个缓存实体上模拟“事务”。根据其实现,分布式(NHibernate)缓存可以向缓存服务器(锁定和释放实体)发送两个额外的请求,从而导致严重的性能下降
  2. 不同的缓存使用不同的序列化器。例如,Redis 缓存使用内置的 .NET XML 序列化程序,它的速度并不出名;)
  3. 根据配置的过期策略,如果您使用分布式缓存,您可能还会有额外的性能下降
  4. 一些缓存服务器(如 Redis)可能会由于资源压力而删除缓存条目,从而导致严重的性能问题(在这种情况下,NH 将访问缓存服务器,获取缓存未命中,然后才尝试从数据库中检索实体 => 2x网络通话)

另外我必须说你的测试不是很有代表性。在运行这些性能测试之前,您需要

  • 检查有多少实体将存储在缓存中
  • 您对这些实体有多少“看跌”与“获得”
  • 您在缓存实体中有多少个链接集合
  • 平均有多少项目存储在链接集合中
  • 你有什么样的实体(只读的,主要是不可变的还是所有的都是可更新的?)
  • ETC

而且,当然,对您的数据而不是在虚拟数据集上运行测试;)

于 2016-06-07T17:07:57.847 回答