服务器之家:专注于服务器技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - PostgreSQL - 使用Spring对Postgres实现可扩展写入

使用Spring对Postgres实现可扩展写入

2023-05-07 03:03未知服务器之家 PostgreSQL

​译者 |布加迪 审校 |孙淑娟 每个与客户产生共鸣的技术型组织最终都会遇到扩展问题。扩展产品和组织对您的流程和基础架构提出了新的要求。本文着重介绍了我们公司如何应对基础架构扩展方面的诸多挑战之一:使用Spring和

​译者 | 布加迪

审校 | 孙淑娟

每个与客户产生共鸣的技术型组织最终都会遇到扩展问题。扩展产品和组织对您的流程和基础架构提出了新的要求。本文着重介绍了我们公司如何应对基础架构扩展方面的诸多挑战之一:使用Spring和Spring Data对Postgres数据库实现可扩展写入。

使用Spring对Postgres实现可扩展写入

随着用户群越来越庞大,我们开始遇到一些性能问题,主要是受到我们的上游Postgres 数据库的制约。我们的RPS(每秒请求)在短短几个月内就从<50增加到了超过180,我们开始遇到SQL连接超时、连接断开和延迟显著增加等问题。这导致客户体验下降,这是不可接受的。

因此,我们着手研究如何消除这些Postgres瓶颈。我们很快意识到耗费太多的周期进行数据库写入,这阻塞了系统。对Postgres的每次写入都是一次调用,这意味着如果我们想将50行保存到数据库中,每行将调用1次,而不是执行一次SQL调用来保存所有这50行!

根本原因:在Hibernate中使用IDENTITY生成ID值

为什么我们无法进行批量更新?事实证明,问题与我们如何使用Hibernate为数据库中的实体生成标识符值(即主键)有关。

我们使用的方法需要从IDENTITY列检索值,新实体插入数据库时​​,Hibernate动态维护这些列。我们针对新资源写入数据库是在没有指定id(主键)的情况下完成的,改而使用GenerationType.IDENTITY。

这是我们的Spring实体的样子:

Kotlin
@Entity
@Table(name = "entity")
data class Entity(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long? = null,
val metadata: String,
) : TenantEntity()

采用这种策略后,使用ORM来创建和更新现有资源显得非常简单:

  • 如果没有传递id,会创建一个新行。
  • 如果传递了id,会更新现有行。

是不是听起来很简单?我们也是这么想的!而且似乎效果良好,直到后来我们意识到使用IDENTITY带来了严重的性能问题。这种策略的缺点是批量更新不起作用。

这给我们带来了一个大问题,因为我们的所有实体都使用IDENTITY标识符值生成。对于每个现有的表及对应的实体,我们必须将策略从IDENTITY换成支持批量插入语句的不同策略。

从IDENTITY迁移到基于序列的ID生成

我们研究可用于支持批处理的实体的其他生成类型后,遇到了Hibernate基于序列的标识符值生成。这个策略得到底层数据库序列的支持。Hibernate从序列中请求下一个可用的id,为资源获取新的id。

虽然该策略的底层机制超出了本文的讨论范围,但结论是,这种基于序列的策略将为我们实现批量插入。

现在我们需要弄清楚如何从现有的IDENTITY策略迁移到基于序列的新方法。

进一步调查后,我们意识到现有的表已经有一个Postgres序列。所以如果我们有一个这样定义的表:

SQL
CREATE TABLE IF NOT EXISTS entity (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
...
)

将创建一个名为entity_id_seq的序列!

您可以运行以下SQL命令来检查序列是否存在:

SELECT
*
FROM
pg_sequence
WHERE
seqrelid = 'entity_id_seq'::regclass;

由于我们能够轻松访问Postgres表的序列,因此可以进行非常本地化的更改,改而使用基于序列的策略来生成id。

对于每个实体,我们只需更改几行代码即可解决性能瓶颈。更新后的实体如下所示:

Kotlin
private const val TABLE = "entity"
private const val SEQUENCE = "${TABLE}_id_seq"
@Entity
@Table(name = TABLE)
data class Entity(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SEQUENCE)
@SequenceGenerator(name = SEQUENCE, sequenceName = SEQUENCE, allocationSize = 50)
@Column(name = "id")
val id: Long? = null,
val metadata: String,
) : TenantEntity()

AllocationSize和序列增量大小

这里需要说明的一点是,Hibernate中的allocationSize属性需要与Postgres中底层序列的增量大小相同。

这是为了让Hibernate和底层序列在它们拥有的id方面“同步”。这还可以防止多台服务器写入到同一个表的分布式架构出现任何问题。

默认情况下,Postgres序列的增量大小为1。我们写了一个非常快速的迁移来更改它,以便与我们的allocationSize匹配:

ALTER SEQUENCE entity_id_seq INCREMENT 50;

现在,Hibernate只需要进行1次调用,即可获取每50次插入的id列表。

它也只需要1次调用即可插入这50行。

以下是我们从这个问题中得出的总结:

  • 如使用Hibernate,尽快开始使用基于数据库序列的身份值生成,尤其是在您预见到写入次数会增加的情况下。
  • 保持allocationSize和底层Postgres序列增量大小参数相同,避免id冲突,并支持分布式系统。

最后,这是我们实施该更改后RPS从近180变成约90的屏幕截图。

使用Spring对Postgres实现可扩展写入

原文标题:​​Scalable Writes to Postgres With Spring​​,作者:Aditya Bansal​

延伸 · 阅读

精彩推荐
  • PostgreSQLpostgresql 中的to_char()常用操作

    postgresql 中的to_char()常用操作

    这篇文章主要介绍了postgresql 中的to_char()常用操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    J符离13432021-04-12
  • PostgreSQLpostgresql 数据库中的数据转换

    postgresql 数据库中的数据转换

    postgres8.3以后,字段数据之间的默认转换取消了。如果需要进行数据变换的话,在postgresql数据库中,我们可以用"::"来进行字段数据的类型转换。...

    postgresql教程网12482021-10-08
  • PostgreSQLPostgresql开启远程访问的步骤全纪录

    Postgresql开启远程访问的步骤全纪录

    postgre一般默认为本地连接,不支持远程访问,所以如果要开启远程访问,需要更改安装文件的配置。下面这篇文章主要给大家介绍了关于Postgresql开启远程...

    我勒个去6812020-04-30
  • PostgreSQLPostgresql查询效率计算初探

    Postgresql查询效率计算初探

    这篇文章主要给大家介绍了关于Postgresql查询效率计算的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Postgresql具有一定的参考学习价...

    轨迹4622020-05-03
  • PostgreSQLRDS PostgreSQL一键大版本升级技术解密

    RDS PostgreSQL一键大版本升级技术解密

    一、PostgreSQL行业位置 (一)行业位置 在讨论PostgreSQL(下面简称为PG)在整个数据库行业的位置之前,我们先看一下阿里云数据库在全球的数据库行业里的...

    未知1192023-05-07
  • PostgreSQL分布式 PostgreSQL之Citus 架构

    分布式 PostgreSQL之Citus 架构

    节点 Citus 是一种 PostgreSQL 扩展,它允许数据库服务器(称为节点)在“无共享(shared nothing)”架构中相互协调。这些节点形成一个集群,允许 PostgreSQL 保存比单...

    未知802023-05-07
  • PostgreSQL深入理解PostgreSQL的MVCC并发处理方式

    深入理解PostgreSQL的MVCC并发处理方式

    这篇文章主要介绍了深入理解PostgreSQL的MVCC并发处理方式,文中同时介绍了MVCC的缺点,需要的朋友可以参考下 ...

    PostgreSQL教程网3622020-04-25
  • PostgreSQLPostgreSQL标准建表语句分享

    PostgreSQL标准建表语句分享

    这篇文章主要介绍了PostgreSQL标准建表语句分享,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    码上得天下7962021-02-27