读/写分裂hibernate

我有一个非常繁重的java webapp,它服务于数千个请求/秒,它使用一个主Postgresql数据库,它使用流(异步)复制将自身复制到一个辅助(只读)数据库。

因此,我使用URL将请求从主要分配到次要(只读),以避免对错误主数据库的只读调用,因为复制时间很短。

注意我使用一个sessionFactory和一个由spring提供的RoutingDataSource,它根据一个键查找db。 我对多租户感兴趣,因为我正在使用支持它的hibernate 4.3.4。

我有两个问题:

  1. 我不认为基于URL的分割是有效的,因为我只能移动10%的流量意味着没有很多只读URL。 我应该考虑什么方法?
  2. 可能是,不知何故,在URL的基础上,我在两个节点之间实现了某种程度的分配,但是我将如何处理我的石英作业(甚至有单独的JVM)? 我应该采取什么务实的方法?

我知道我可能在这里得不到完美的答案,因为这真的很广泛,但我只是想要你的意见。

我队里的伙计们:

  • Spring4
  • Hibernate4
  • Quartz2.2
  • Java7 / Tomcat7

请关注。 提前致谢。

你应该有:

  1. 配置为连接到主节点的DataSource
  2. 配置为连接到从属节点的DataSource
  3. 路由DataSource站在这两个前面,是SessionFactory使用的路由。
  4. 您可以使用@Transactional(readOnly = true)标志来确保将只读事务路由到从属DataSource。
  5. 主数据源和从数据源都需要连接池机制,而最快的一个绝对是HikariCP 。 HikariCP是如此之快,在我的一次测试中,我获得了100us的平均连接获取时间。
  6. 您需要确保为连接池设置正确的大小,因为这可以产生巨大的差异。 为此,我建议使用flexy-pool 。 你可以在这里和这里找到更多相关信息。
  7. 您需要非常勤奋,并确保相应地标记所有只读事务。 只有10%的交易是只读的,这是不寻常的。 可能是您拥有这样一个最多的应用程序,或者您正在使用只发出查询语句的写入事务?
  8. 使用SQL日志记录框架监视所有查询执行。 查询执行时间越短,锁定获取时间越短,系统容纳的每秒事务就越多。
  9. 对于批处理,您肯定需要最多写入事务,但一般来说OLTP和特别是Hibernate不是最适合OLAP的。 如果您仍然决定将Hibernate用于您的石英作业,请确保启用JDBC批处理,并且您应该设置这些Hibernate属性:

         

对于批处理,您可以使用使用不同连接池的单独数据源(并且因为您已经说过您拥有不同的JVM,那么这就是您已有的)。 只需确保所有连接池的总连接大小小于PostgreSQL配置的连接数。

因此批处理器使用连接到master的单独HikariCPDataSource。 每个批处理作业必须使用专用事务,因此请确保使用合理的批处理大小。 您希望保持锁定并尽快完成交易。 如果批处理器使用并发处理工作程序,请确保关联的连接池大小等于工作程序数,因此它们不会等待其他人释放连接。

您说您的应用程序URL仅为10%只读,因此其他90%至少具有某种forms的数据库写入。

10%阅读

您可以考虑使用可以提高数据库读取性能的CQRS设计 。 它当然可以从辅助数据库中读取,并且可以通过专门为读取/查看层设计查询和域模型来提高效率。

您还没有说10%的请求是否昂贵(例如运行报告)

如果您要遵循CQRS设计,我宁愿使用单独的sessionFactory,因为正在加载/缓存的对象很可能与正在编写的对象不同。

90%写

对于其他90%的用户,在一些写入逻辑期间,您不希望从辅助数据库读取(在写入主数据库时),因为您不希望涉及可能过时的数据。

其中一些读取可能会查找“静态”数据。 如果Hibernate的缓存没有减少读取的数据库命中,我会考虑内存缓存,如Memcached或Redis这类数据。 10%-Read和90%-write进程都可以使用相同的缓存。

对于非静态读取(即读取您最近编写的数据),如果Hibernate的大小合适,Hibernate应该在其对象缓存中保存数据。 你能确定你的缓存命中/未命中性能吗?

石英

如果您确定预定作业不会影响与另一个作​​业相同的数据集,则可以针对不同的数据库运行它们,但是如果有疑问,则始终对一个(主)服务器执行批量更新并复制更改。 在逻辑上更正确,而不是引入复制问题。

DB分区

如果每秒1,000个请求正在编写大量数据,请查看对数据库进行分区 。 你可能会发现你有成长表。 分区是在不归档数据的情况下解决此问题的一种方法。

有时您需要很少或根本不需要更改应用程序代码。

归档显然是另一种选择

免责声明:这样的任何问题总是特定于应用程序。 始终尽量使您的架构尽可能简单。

如果我正确理解,90%的对您的webapp的HTTP请求至少涉及一次写入,并且必须在master数据库上运行。 您可以将只读事务定向到副本数据库,但这种改进只会影响全局数据库操作的10%,甚至那些只读操作也会影响数据库。

这里的常见架构是使用良好的数据库缓存(Infinispan或Ehcache)。 如果你可以提供足够大的缓存,你可以希望数据库读取的很大一部分只访问缓存并成为仅限内存的操作,或者是只读事务的一部分。 高速缓存调整是一项微妙的操作,但恕我直言是实现高性能增益所必需的。 即使配置在这种情况下有点困难,这些缓存甚至允许分布式前端(如果你想使用Ehcache,你可能必须寻找Terracotta集群)。

目前,数据库复制主要用于保护数据,并且仅当您拥有只读取数据的信息系统的高部分时才用作并发性改进机制 – 而且它不是您所描述的。