自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用Spring對Postgres實(shí)現(xiàn)可擴(kuò)展寫入

譯文
數(shù)據(jù)庫 PostgreSQL
本文著重介紹了我們公司如何應(yīng)對基礎(chǔ)架構(gòu)擴(kuò)展方面的諸多挑戰(zhàn)之一:使用Spring和 Spring Data對Postgres數(shù)據(jù)庫實(shí)現(xiàn)可擴(kuò)展寫入。

?譯者 | 布加迪

審校 | 孫淑娟

每個(gè)與客戶產(chǎn)生共鳴的技術(shù)型組織最終都會(huì)遇到擴(kuò)展問題。擴(kuò)展產(chǎn)品和組織對您的流程和基礎(chǔ)架構(gòu)提出了新的要求。本文著重介紹了我們公司如何應(yīng)對基礎(chǔ)架構(gòu)擴(kuò)展方面的諸多挑戰(zhàn)之一:使用Spring和Spring Data對Postgres數(shù)據(jù)庫實(shí)現(xiàn)可擴(kuò)展寫入。

隨著用戶群越來越龐大,我們開始遇到一些性能問題,主要是受到我們的上游Postgres 數(shù)據(jù)庫的制約。我們的RPS(每秒請求)在短短幾個(gè)月內(nèi)就從<50增加到了超過180,我們開始遇到SQL連接超時(shí)、連接斷開和延遲顯著增加等問題。這導(dǎo)致客戶體驗(yàn)下降,這是不可接受的。

因此,我們著手研究如何消除這些Postgres瓶頸。我們很快意識(shí)到耗費(fèi)太多的周期進(jìn)行數(shù)據(jù)庫寫入,這阻塞了系統(tǒng)。對Postgres的每次寫入都是一次調(diào)用,這意味著如果我們想將50行保存到數(shù)據(jù)庫中,每行將調(diào)用1次,而不是執(zhí)行一次SQL調(diào)用來保存所有這50行!

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

為什么我們無法進(jìn)行批量更新?事實(shí)證明,問題與我們?nèi)绾问褂肏ibernate為數(shù)據(jù)庫中的實(shí)體生成標(biāo)識(shí)符值(即主鍵)有關(guān)。

我們使用的方法需要從IDENTITY列檢索值,新實(shí)體插入數(shù)據(jù)庫時(shí)??,Hibernate動(dòng)態(tài)維護(hù)這些列。我們針對新資源寫入數(shù)據(jù)庫是在沒有指定id(主鍵)的情況下完成的,改而使用GenerationType.IDENTITY。

這是我們的Spring實(shí)體的樣子:

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

采用這種策略后,使用ORM來創(chuàng)建和更新現(xiàn)有資源顯得非常簡單:

  • 如果沒有傳遞id,會(huì)創(chuàng)建一個(gè)新行。
  • 如果傳遞了id,會(huì)更新現(xiàn)有行。

是不是聽起來很簡單?我們也是這么想的!而且似乎效果良好,直到后來我們意識(shí)到使用IDENTITY帶來了嚴(yán)重的性能問題。這種策略的缺點(diǎn)是批量更新不起作用。

這給我們帶來了一個(gè)大問題,因?yàn)槲覀兊乃袑?shí)體都使用IDENTITY標(biāo)識(shí)符值生成。對于每個(gè)現(xiàn)有的表及對應(yīng)的實(shí)體,我們必須將策略從IDENTITY換成支持批量插入語句的不同策略。

從IDENTITY遷移到基于序列的ID生成

我們研究可用于支持批處理的實(shí)體的其他生成類型后,遇到了Hibernate基于序列的標(biāo)識(shí)符值生成。這個(gè)策略得到底層數(shù)據(jù)庫序列的支持。Hibernate從序列中請求下一個(gè)可用的id,為資源獲取新的id。

雖然該策略的底層機(jī)制超出了本文的討論范圍,但結(jié)論是,這種基于序列的策略將為我們實(shí)現(xiàn)批量插入。

現(xiàn)在我們需要弄清楚如何從現(xiàn)有的IDENTITY策略遷移到基于序列的新方法。

進(jìn)一步調(diào)查后,我們意識(shí)到現(xiàn)有的表已經(jīng)有一個(gè)Postgres序列。所以如果我們有一個(gè)這樣定義的表:

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

將創(chuàng)建一個(gè)名為entity_id_seq的序列!

您可以運(yùn)行以下SQL命令來檢查序列是否存在:

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

由于我們能夠輕松訪問Postgres表的序列,因此可以進(jìn)行非常本地化的更改,改而使用基于序列的策略來生成id。

對于每個(gè)實(shí)體,我們只需更改幾行代碼即可解決性能瓶頸。更新后的實(shí)體如下所示:

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和序列增量大小

這里需要說明的一點(diǎn)是,Hibernate中的allocationSize屬性需要與Postgres中底層序列的增量大小相同。

這是為了讓Hibernate和底層序列在它們擁有的id方面“同步”。這還可以防止多臺(tái)服務(wù)器寫入到同一個(gè)表的分布式架構(gòu)出現(xiàn)任何問題。

默認(rèn)情況下,Postgres序列的增量大小為1。我們寫了一個(gè)非??焖俚倪w移來更改它,以便與我們的allocationSize匹配:

ALTER SEQUENCE entity_id_seq INCREMENT 50;

現(xiàn)在,Hibernate只需要進(jìn)行1次調(diào)用,即可獲取每50次插入的id列表。

它也只需要1次調(diào)用即可插入這50行。

以下是我們從這個(gè)問題中得出的總結(jié):

  • 如使用Hibernate,盡快開始使用基于數(shù)據(jù)庫序列的身份值生成,尤其是在您預(yù)見到寫入次數(shù)會(huì)增加的情況下。
  • 保持allocationSize和底層Postgres序列增量大小參數(shù)相同,避免id沖突,并支持分布式系統(tǒng)。

最后,這是我們實(shí)施該更改后RPS從近180變成約90的屏幕截圖。

原文標(biāo)題:??Scalable Writes to Postgres With Spring??,作者:Aditya Bansal?

責(zé)任編輯:華軒 來源: 51CTO
相關(guān)推薦

2023-11-09 08:31:56

Spring微服務(wù)網(wǎng)關(guān)

2024-01-23 18:53:04

PostgreSQL關(guān)系數(shù)據(jù)庫

2023-12-12 07:30:54

IstioWasm前端

2025-02-10 10:54:53

PostgresDBpgvector數(shù)據(jù)庫

2021-05-17 07:28:23

Spring可擴(kuò)展性項(xiàng)目

2020-02-12 09:00:48

數(shù)據(jù)網(wǎng)格Apache Igni數(shù)據(jù)管理

2015-04-23 13:29:02

Flume分布式服務(wù)HDFS

2009-03-16 09:16:13

行為擴(kuò)展WCF.NET

2016-08-24 19:22:10

Docker SwarPython應(yīng)用

2019-05-20 13:20:36

Python編程語言情感分析

2024-09-23 00:00:10

2013-06-25 21:08:33

Active PoweDatum環(huán)保

2017-05-09 10:34:21

Spring BootDubbo Activ擴(kuò)展

2017-04-28 08:32:40

Spring BootDubbo Activ使用

2024-02-01 08:28:28

2022-05-30 09:32:07

Spring容器

2016-10-31 11:26:13

ReactRedux前端應(yīng)用

2011-09-15 10:15:30

Spring

2009-08-31 14:45:10

C#擴(kuò)展方法

2011-09-20 17:08:21

JavaScript
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號