sentry-nodestore-opensearch
Sentry nodestore OpenSearch backend
Supported Sentry 24.x & OpenSearch 2.x versions
Use OpenSearch cluster to store node objects from Sentry.
By default, self-hosted Sentry uses a PostgreSQL database for settings and nodestore, which under high load becomes a bottleneck, causing the database size to grow rapidly and slowing down the entire system.
Switching nodestore to a dedicated OpenSearch cluster provides better scalability:
- OpenSearch clusters can be scaled horizontally by adding more data nodes (PostgreSQL cannot).
- Data in OpenSearch can be sharded and replicated between data nodes, which increases throughput.
- OpenSearch automatically rebalances when new data nodes are added.
- Scheduled Sentry cleanup performs much faster and more stably when using OpenSearch nodestore, as it relies on simple deletion of old indices (cleanup in a terabyte-sized PostgreSQL nodestore is very challenging).
Installation
Rebuild the Sentry Docker image with the nodestore package installation.
FROM getsentry/sentry:24.4.1
RUN pip install sentry-nodestore-opensearch \
Configuration
Set SENTRY_NODESTORE at your sentry.conf.py
from opensearchpy import OpenSearch
os_client = OpenSearch(
['https://username:password@opensearch:9200'],
http_compress=True,
request_timeout=60,
max_retries=3,
retry_on_timeout=True,
# ❯ openssl s_client -connect opensearch:9200 < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin
ssl_assert_fingerprint=(
"PUT_FINGERPRINT_HERE"
)
)
SENTRY_NODESTORE = 'sentry_nodestore_opensearch.OpenSearchNodeStorage'
SENTRY_NODESTORE_OPTIONS = {
'es': os_client,
'refresh': False, # ref: https://opensearch.org/docs/latest/opensearch/rest-api/index-apis/refresh/
# other OpenSearch-related options
}
from sentry.conf.server import * # Default for sentry.conf.py
INSTALLED_APPS = list(INSTALLED_APPS)
INSTALLED_APPS.append('sentry_nodestore_opensearch')
INSTALLED_APPS = tuple(INSTALLED_APPS)
Usage
Setup opensearch index template
Ensure OpenSearch is up and running before this step. This will create an index template in OpenSearch.
sentry upgrade --with-nodestore
Or you can prepare the index template manually with this JSON. It may be customized for your needs, but the template name must be sentry because of the nodestore initialization script.
{
"template": {
"settings": {
"index": {
"number_of_shards": "3",
"number_of_replicas": "0",
"routing": {
"allocation": {
"include": {
"_tier_preference": "data_content"
}
}
}
}
},
"mappings": {
"dynamic": "false",
"dynamic_templates": [],
"properties": {
"data": {
"type": "text",
"index": false,
"store": true
},
"timestamp": {
"type": "date",
"store": true
}
}
},
"aliases": {
"sentry": {}
}
}
}
Migrate Data from Default PostgreSQL Nodestore to OpenSearch
PostgreSQL and OpenSearch must be accessible from the machine where you run this code.
from opensearchpy import OpenSearch
from opensearchpy.helpers import bulk
import psycopg2
os_client = OpenSearch(
['https://username:password@opensearch:9200'],
http_compress=True,
request_timeout=60,
max_retries=3,
retry_on_timeout=True,
# ❯ openssl s_client -connect opensearch:9200 < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin
ssl_assert_fingerprint=(
"PUT_FINGERPRINT_HERE"
)
)
conn = psycopg2.connect(
dbname="sentry",
user="sentry",
password="password",
host="hostname",
port="5432"
)
cur = conn.cursor()
cur.execute("SELECT reltuples AS estimate FROM pg_class WHERE relname = 'nodestore_node'")
result = cur.fetchone()
count = int(result[0])
print(f"Estimated rows: {count}")
cur.close()
cursor = conn.cursor(name='fetch_nodes')
cursor.execute("SELECT * FROM nodestore_node ORDER BY timestamp ASC")
while True:
records = cursor.fetchmany(size=2000)
if not records:
break
bulk_data = []
for r in records:
id = r[0]
data = r[1]
date = r[2].strftime("%Y-%m-%d")
ts = r[2].isoformat()
index = f"sentry-{date}"
doc = {
'data': data,
'timestamp': ts
}
action = {
"_index": index,
"_id": id,
"_source": doc
}
bulk_data.append(action)
bulk(os_client, bulk_data)
count -= len(records)
print(f"Remaining rows: {count}")
cursor.close()
conn.close()
Release files for sentry-nodestore-opensearch 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sentry_nodestore_opensearch-1.0.1.tar.gz | 9.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sentry_nodestore_opensearch-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 19.6 kB
Release files / sentry_nodestore_opensearch-1.0.1.tar.gz
| Download URL | sentry_nodestore_opensearch-1.0.1.tar.gz |
|---|---|
| Size | 9.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
41a7783a869ca7f77cbd402b8f7a3b2ac98d9bd63a3333a7ec540effc61b8706
|
|
BLAKE2b-256 checksum How to use checksums |
4b1e4eddec9e16f0b47fde9c3d3b0b4bd2504496670f9d0f0641b0a6696279fc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 14, 2025.
Transparency logRelease files / sentry_nodestore_opensearch-1.0.1-py3-none-any.whl
| Download URL | sentry_nodestore_opensearch-1.0.1-py3-none-any.whl |
|---|---|
| Size | 10.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e9c4c0344b1b97bcb025a627349858f6e5e6e780b817840fb2df65e498c8377d
|
|
BLAKE2b-256 checksum How to use checksums |
14e6ba3e82286d05044920e4fd8f767b37be6fb3446aee7cc0de4f30091a5796
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 14, 2025.
Transparency log