--ADDED performance matrix for db
This commit is contained in:
george committed 2026-09-23 00:59:58 +05:30
1 parent 0313fbfee0
commit 39507a1a8d
2 files changed
+236 -1

No files matched your search

+42
View File
@@ -50,3 +50,45 @@ Using my uploaded photo, show me what I would have looked like around 1985. Pres
| **Zabbix** | Infrastructure monitoring | Servers, databases, network, disk, CPU, alerts | | **Zabbix** | Infrastructure monitoring | Servers, databases, network, disk, CPU, alerts |
| **Datadog** | Commercial monitoring | DB + server + application monitoring | | **Datadog** | Commercial monitoring | DB + server + application monitoring |
| **New Relic** | Application + DB | Slow SQL, response times, application/database relationship | | **New Relic** | Application + DB | Slow SQL, response times, application/database relationship |
DASHBOARD
| Metric | What it tells you | Good dashboard display |
| ------------------------ | --------------------------------------------------------- | ------------------------ |
| **Database Status** | PostgreSQL reachable or not | 🟢 Online / 🔴 Offline |
| **Uptime** | How long PostgreSQL has been running | `12d 7h 32m` |
| **Active Connections** | Connections currently executing queries | Gauge |
| **Total Connections** | Connections in use | `42 / 100` |
| **Connection Usage %** | How close you are to `max_connections` | Gauge / % |
| **Idle Connections** | Connections sitting idle | Number |
| **TPS** | Transactions per second | Time-series graph |
| **Commits/sec** | Successful transaction rate | Graph |
| **Rollbacks/sec** | Failed/aborted transaction rate | Graph |
| **Cache Hit Ratio** | How often PostgreSQL serves data from RAM instead of disk | % |
| **Query Latency** | Average query execution time | ms |
| **Slow Queries** | Queries exceeding threshold, e.g. >1s | Table |
| **Long Running Queries** | Queries running unusually long | Table |
| **Blocked Queries** | Queries waiting on another transaction | Number/Table |
| **Locks** | Current DB locks | Gauge |
| **Deadlocks** | Deadlocks detected | Counter |
| **Database Size** | Total database disk usage | GB |
| **Table Size** | Largest tables | Bar chart |
| **Index Size** | Storage consumed by indexes | GB |
| **Tuple Reads / Writes** | Database activity | Graph |
| **Rows Inserted/sec** | INSERT activity | Graph |
| **Rows Updated/sec** | UPDATE activity | Graph |
| **Rows Deleted/sec** | DELETE activity | Graph |
| **Sequential Scans** | Potentially expensive full-table scans | Counter |
| **Index Scans** | Index usage | Counter |
| **Dead Tuples** | Rows VACUUM needs to clean | Number |
| **Autovacuum Activity** | Whether cleanup is working | Status |
| **WAL Generated/sec** | Write workload / replication workload | MB/s |
| **WAL Size** | WAL storage usage | GB |
| **Replication Lag** | Delay between nodes | ms / MB |
| **Replication Status** | Whether link is healthy | 🟢 Replicating / 🔴 Down |
| **Replication Slot Lag** | WAL retained because subscriber hasn't consumed it | MB |
| **CPU Usage** | DB server CPU load | % |
| **RAM Usage** | Server memory pressure | % |
| **Disk Usage** | Remaining DB server disk | % |
| **Disk I/O** | Storage read/write activity | MB/s |
+194 -1
View File
@@ -8,7 +8,7 @@ import jwt
from pydantic import BaseModel from pydantic import BaseModel
from psycopg2.extras import RealDictCursor from psycopg2.extras import RealDictCursor
import asyncio import asyncio
import time
load_dotenv() load_dotenv()
app = FastAPI() app = FastAPI()
@@ -590,12 +590,205 @@ async def database_active_connections_monitor(websocket: WebSocket):
) )
#TPS
def get_database_tps(data: DatabaseRequest):
conn = None
cursor = None
try:
conn = psycopg2.connect(
host=data.host,
port=data.port,
dbname=data.dbname,
user=data.user,
password=data.password,
connect_timeout=3
)
conn.autocommit = True
cursor = conn.cursor()
# First sample
cursor.execute("""
SELECT
xact_commit + xact_rollback
FROM pg_stat_database
WHERE datname = %s;
""", (data.dbname,))
first_count = cursor.fetchone()[0]
start_time = time.monotonic()
time.sleep(1)
# Second sample
cursor.execute("""
SELECT
xact_commit + xact_rollback
FROM pg_stat_database
WHERE datname = %s;
""", (data.dbname,))
second_count = cursor.fetchone()[0]
end_time = time.monotonic()
elapsed_time = end_time - start_time
transactions = second_count - first_count
tps = round(
transactions / elapsed_time,
2
)
return {
"database_name": data.dbname,
"tps": tps
}
except psycopg2.Error as e:
return {
"database_name": data.dbname,
"tps": None,
"error": str(e)
}
finally:
if cursor:
cursor.close()
if conn:
conn.close()
# CACHE HIT RATIO
def get_cache_hit_ratio(data: DatabaseRequest):
conn = None
cursor = None
try:
conn = psycopg2.connect(
host=data.host,
port=data.port,
dbname=data.dbname,
user=data.user,
password=data.password,
connect_timeout=3
)
cursor = conn.cursor()
cursor.execute("""
SELECT
CASE
WHEN (blks_hit + blks_read) = 0 THEN 0
ELSE ROUND(
(blks_hit::numeric /
(blks_hit + blks_read)) * 100,
2
)
END AS cache_hit_ratio
FROM pg_stat_database
WHERE datname = %s;
""", (data.dbname,))
row = cursor.fetchone()
cache_hit_ratio = float(row[0]) if row else 0.0
return {
"database_name": data.dbname,
"cache_hit_ratio": cache_hit_ratio
}
except psycopg2.Error as e:
return {
"database_name": data.dbname,
"cache_hit_ratio": None,
"error": str(e)
}
finally:
if cursor:
cursor.close()
if conn:
conn.close()
#TPS AND CACHE HIT RATIO WEB SOCKET
@app.websocket("/ws/database/performance")
async def database_performance_monitor(websocket: WebSocket):
await websocket.accept()
try:
raw_data = await websocket.receive_json()
data = DatabaseRequest(**raw_data)
while True:
try:
(
tps_result,
cache_hit_result
) = await asyncio.wait_for(
asyncio.gather(
asyncio.to_thread(
get_database_tps,
data
),
asyncio.to_thread(
get_cache_hit_ratio,
data
)
),
timeout=5
)
result = {
"database_name": data.dbname,
"tps": tps_result[
"tps"
],
"cache_hit_ratio": cache_hit_result[
"cache_hit_ratio"
]
}
except asyncio.TimeoutError:
result = {
"database_name": data.dbname,
"tps": None,
"cache_hit_ratio": None
}
await websocket.send_json(result)
await asyncio.sleep(2)
except WebSocketDisconnect:
print("Database performance WebSocket disconnected")
if __name__ == "__main__": if __name__ == "__main__":