The HSF Conditions Database
14 May 2024
Chris Pinkenburg, Lino Gerlach, Ruslan Mashinistov,�Paul Laycock, Torre Wenaus
1
Overview
2
3
Road to HSF CDB Project - Simplified
4
In reality…
Road to HSF CDB Project - Reality
5
Features & Functionality
6
7
payload
remote�payload�store
nopayloaddb
Features & Functionality
client�side
server�side
nopayloadclient
curl http://<host>/api/payloadiovs/?gtName=test_gt&iovNum=42�-> {type_1: url_1, type_2: url_2, …}
*Example query (simplified)
REST*
Experiment-�agnostic lib
nopayloadclient
sPHENIX-�specific lib
sphenixnpc
DUNE-�specific lib
dunenpc
Implementation – Database Schema
8
Locked
Unlocked
major- & minor IOV for more flexibility
IOVs also have an end
performance optimisation
Payloads are not stored in schema
No schema evolution
Deployment on OKD
9
Easily adoptable for various HEP experiments
Performance Testing – Strategy
10
mean response frequency
mean response time
Scenario | Payload Types | Payload IOVs (per type) |
tiny | 10 | 100 (10) |
tiny-moderate | 10 | 2000 (200) |
moderate | 100 | 20000 (200) |
heavy-usage | 100 | 500000 (5000) |
worst-case | 200 | 5200000 (26000) |
All following tests:
Performance Testing – Scaling
11
Resp. freq. vs size of queried GT
1M IOVs
One Year of Successful Production in
12
Valuable Experience gathered:
Since initial bugs were fixed,�successful operations with minimal maintenance effort
Experience from
13
Successfully ran DUNE offline dummy job w/ access to our DB
Implementation Matters� - Experience from
14
nginx
Java/
Spring boot
Postgres
Payara
Helm
performance issues
Outlook & Next Steps
15
Conclusion
16
Backup
17
Conditions Data – Recommendations
18
top-level configuration of all conditions data
‘Interval of Validity’:�generalized concept of time�(begin can be time stamp, run number, lumi block, …)
configuration for each type of conditions data
actual data (e.g. in a file)
HEP Software Foundation� Community White Paper Working Group – Conditions Data
Conditions Data – Use Cases
19
Online
Reprocessing
Analysis
Development
Fast-processing
Example
Use case
Performance Testing – ORM vs Raw SQL
20
*: my_major<major_iov OR (my_major=major_iov AND my_minor<=minor_iov) **: for max major_iov, find max minor_iov
Resp. freq. vs size of queried GT
Performance Testing – Scaling
21
Resp. freq. vs size of queried GT
Resp. freq. vs DB size
Performance Testing – High Frequency
22
10k requests sent within ~1.2 secs
received all responses within ~55 sec
PostgreSQL High-Availability Cluster
23
Open source Kubernetes operator for HA PostgreSQL
PayloadIOV Read API – Raw SQL Query
24
SELECT pi.payload_url, pi.major_iov, pi.minor_iov, pt.name, …
FROM "PayloadList" pl
JOIN "GlobalTag" gt ON pl.global_tag_id = gt.id AND gt.name = %(my_gt)s
JOIN LATERAL (
SELECT payload_url, major_iov, minor_iov, …
FROM "PayloadIOV" pi
WHERE pi.payload_list_id = pl.id
AND pi.comb_iov <= CAST(%(my_major_iov)s + CAST(%(my_minor_iov)s AS DECIMAL(19,0)) / 10E18 AS DECIMAL(38,19))
ORDER BY pi.comb_iov DESC
LIMIT 1
) pi ON true
JOIN "PayloadType" pt ON pl.payload_type_id = pt.id;
For each PayloadList (Type)
Get Payloads descending ordered by combined IOV
Limit return to 1 line - latest Payload for a given IOVs
And then append the results of each subquery to create the final output
Investigating Query Plans - I
25
Hash Join (cost=7.23..90.89 rows=86 width=70) (actual time=0.309..3.244 rows=200 loops=1)
Hash Cond: (pl.payload_type_id = pt.id)
-> Nested Loop (cost=0.71..84.14 rows=86 width=69) (actual time=0.075..2.935 rows=200 loops=1)
-> Nested Loop (cost=0.15..11.70 rows=86 width=16) (actual time=0.028..0.121 rows=201 loops=1)
-> Seq Scan on "GlobalTag" gt (cost=0.00..1.09 rows=1 width=8) (actual time=0.013..0.018 rows=1 loops=1)
Filter: ((name)::text = 'worst-case'::text)
Rows Removed by Filter: 6
-> Index Scan using "PayloadList_global_tag_id_2b35c85f" on "PayloadList" pl
(cost=0.15..9.75 rows=86 width=24) (actual time=0.012..0.063 rows=201 loops=1)
Index Cond: (global_tag_id = gt.id)
-> Limit (cost=0.56..0.82 rows=1 width=61) (actual time=0.014..0.014 rows=1 loops=201)
-> Index Only Scan using combo_covering_idx on "PayloadIOV" pi
(cost=0.56..232.55 rows=876 width=61) (actual time=0.013..0.013 rows=1 loops=201)
Index Cond: ((payload_list_id = pl.id) AND (major_iov < 100000000))
Heap Fetches: 0
-> Hash (cost=4.01..4.01 rows=201 width=17) (actual time=0.073..0.074 rows=201 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 19kB
-> Seq Scan on "PayloadType" pt (cost=0.00..4.01 rows=201 width=17) (actual time=0.008..0.036 rows=201 loops=1)
Planning Time: 0.645 ms
Execution Time: 3.299 ms
Hash Join (cost=7.23..410.15 rows=86 width=70) (actual time=6.111..365.158 rows=200 loops=1)
Hash Cond: (pl.payload_type_id = pt.id)
-> Nested Loop (cost=0.71..403.40 rows=86 width=69) (actual time=6.017..364.977 rows=200 loops=1)
-> Nested Loop (cost=0.15..11.70 rows=86 width=16) (actual time=0.048..0.133 rows=201 loops=1)
-> Seq Scan on "GlobalTag" gt (cost=0.00..1.09 rows=1 width=8) (actual time=0.023..0.025 rows=1 loops=1)
Filter: ((name)::text = 'worst-case'::text)
Rows Removed by Filter: 6
-> Index Scan using "PayloadList_global_tag_id_2b35c85f" on "PayloadList" pl
(cost=0.15..9.75 rows=86 width=24) (actual time=0.022..0.083 rows=201 loops=1)
Index Cond: (global_tag_id = gt.id)
-> Limit (cost=0.56..4.53 rows=1 width=61) (actual time=1.815..1.815 rows=1 loops=201)
-> Index Only Scan using combo_covering_idx on "PayloadIOV" pi
(cost=0.56..3484.55 rows=876 width=61) (actual time=1.815..1.815 rows=1 loops=201)
Index Cond: (payload_list_id = pl.id)
Filter: ((major_iov < 100000000) OR ((major_iov = 100000000) AND (minor_iov <= 100000000)))
Rows Removed by Filter: 24669
Heap Fetches: 0
-> Hash (cost=4.01..4.01 rows=201 width=17) (actual time=0.078..0.078 rows=201 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 19kB
-> Seq Scan on "PayloadType" pt (cost=0.00..4.01 rows=201 width=17) (actual time=0.018..0.043 rows=201 loops=1)
Planning Time: 0.996 ms
Execution Time: 365.221 ms
Only majorIOV
major- & minorIOV
Investigating Query Plans - II
26
-> Limit (cost=0.56..0.82 rows=1 width=61) (actual time=0.014..0.014 rows=1 loops=201)
-> Index Only Scan using combo_covering_idx on "PayloadIOV" pi
(cost=0.56..232.55 rows=876 width=61) (actual time=0.013..0.013 rows=1 loops=201)
Index Cond: ((payload_list_id = pl.id) AND (major_iov < 100000000))
Heap Fetches: 0
-> Limit (cost=0.56..4.53 rows=1 width=61) (actual time=1.815..1.815 rows=1 loops=201)
-> Index Only Scan using combo_covering_idx on "PayloadIOV" pi
(cost=0.56..3484.55 rows=876 width=61) (actual time=1.815..1.815 rows=1 loops=201)
Index Cond: (payload_list_id = pl.id)
Filter: ((major_iov < 100000000) OR ((major_iov = 100000000) AND (minor_iov <= 100000000)))
Rows Removed by Filter: 24669
Heap Fetches: 0
Index Condition & Filter
Index Condition Only
Raw SQL - Combined IOV Column
27
bigint bigint decimal(38, 19)