读/写分裂休眠

Sac*_*rma 20 java postgresql replication hibernate jpa

我有一个非常繁重的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

请关注.提前致谢.

Vla*_*cea 10

你应该有:

  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属性:

    <property name="hibernate.order_updates" value="true"/>
    <property name="hibernate.order_inserts" value="true"/>
    <property name="hibernate.jdbc.batch_versioned_data" value="true"/>
    <property name="hibernate.jdbc.fetch_size" value="25"/>
    <property name="hibernate.jdbc.batch_size" value="25"/>
    
    Run Code Online (Sandbox Code Playgroud)

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

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

  • 既然 vlad-mihalcea 删除了评论,那么对话就没有意义了。包括 vlad-mihalcea 评论的完整记录可以在 https://github.com/reda-alaoui/ro-rw-routing/blob/master/so-transcript.md 找到。 (4认同)

Bra*_*rad 5

你是说你的应用程序 URL 只有 10% 是只读的,所以其他 90% 至少有某种形式的数据库写入。

10% 阅读

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

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

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

90% 写

至于其他 90% 的情况,您不希望在某些写入逻辑期间从辅助数据库读取(在写入主数据库时),因为您不希望涉及潜在的陈旧数据。

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

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

石英

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

数据库分区

如果每秒 1,000 个请求写入大量数据,请查看对数据库进行分区。您可能会发现您的表一直在增长。分区是一种无需存档数据即可解决此问题的方法。

有时,您几乎不需要更改应用程序代码。

存档显然是另一种选择

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