return the on disk size actually used by meilisearch

This commit is contained in:
Tamo 2023-05-25 18:30:30 +02:00
parent 35d5556f1f
commit c9b65677bf
No known key found for this signature in database
GPG Key ID: 20CD8020AFA88D69
8 changed files with 169 additions and 92 deletions

View File

@ -52,71 +52,6 @@
"title": "Web application metrics", "title": "Web application metrics",
"type": "row" "type": "row"
}, },
{
"datasource": {
"type": "prometheus"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "continuous-GrYlRd"
},
"decimals": 0,
"mappings": [],
"min": 0,
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
}
]
},
"unit": "bytes"
},
"overrides": []
},
"gridPos": {
"h": 6,
"w": 4,
"x": 0,
"y": 1
},
"id": 2,
"interval": "5s",
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": [
"lastNotNull"
],
"fields": "",
"values": false
},
"textMode": "auto"
},
"pluginVersion": "9.5.2",
"targets": [
{
"datasource": {
"type": "prometheus"
},
"editorMode": "builder",
"exemplar": true,
"expr": "meilisearch_db_size_bytes{job=\"meilisearch\", instance=\"$instance\"}",
"interval": "",
"legendFormat": "",
"range": true,
"refId": "A"
}
],
"title": "Database Size",
"type": "stat"
},
{ {
"datasource": { "datasource": {
"type": "prometheus" "type": "prometheus"
@ -145,7 +80,7 @@
"gridPos": { "gridPos": {
"h": 6, "h": 6,
"w": 4, "w": 4,
"x": 4, "x": 0,
"y": 1 "y": 1
}, },
"id": 22, "id": 22,
@ -206,7 +141,7 @@
"gridPos": { "gridPos": {
"h": 6, "h": 6,
"w": 4, "w": 4,
"x": 8, "x": 4,
"y": 1 "y": 1
}, },
"id": 18, "id": 18,
@ -431,10 +366,11 @@
"type": "prometheus", "type": "prometheus",
"uid": "c4085c47-f6d3-45dd-b761-6809055bb749" "uid": "c4085c47-f6d3-45dd-b761-6809055bb749"
}, },
"description": "",
"fieldConfig": { "fieldConfig": {
"defaults": { "defaults": {
"color": { "color": {
"mode": "continuous-YlBl" "mode": "palette-classic"
}, },
"custom": { "custom": {
"axisCenteredZero": false, "axisCenteredZero": false,
@ -443,7 +379,7 @@
"axisPlacement": "auto", "axisPlacement": "auto",
"barAlignment": 0, "barAlignment": 0,
"drawStyle": "line", "drawStyle": "line",
"fillOpacity": 15, "fillOpacity": 25,
"gradientMode": "none", "gradientMode": "none",
"hideFrom": { "hideFrom": {
"legend": false, "legend": false,
@ -456,18 +392,18 @@
"scaleDistribution": { "scaleDistribution": {
"type": "linear" "type": "linear"
}, },
"showPoints": "never", "showPoints": "auto",
"spanNulls": false, "spanNulls": false,
"stacking": { "stacking": {
"group": "A", "group": "A",
"mode": "none" "mode": "normal"
}, },
"thresholdsStyle": { "thresholdsStyle": {
"mode": "off" "mode": "off"
} }
}, },
"decimals": 2,
"mappings": [], "mappings": [],
"min": 0,
"thresholds": { "thresholds": {
"mode": "absolute", "mode": "absolute",
"steps": [ "steps": [
@ -480,7 +416,8 @@
"value": 80 "value": 80
} }
] ]
} },
"unit": "bytes"
}, },
"overrides": [] "overrides": []
}, },
@ -490,13 +427,13 @@
"x": 0, "x": 0,
"y": 7 "y": 7
}, },
"id": 1, "id": 2,
"interval": "5s", "interval": "5s",
"options": { "options": {
"legend": { "legend": {
"calcs": [], "calcs": [],
"displayMode": "list", "displayMode": "list",
"placement": "right", "placement": "bottom",
"showLegend": true "showLegend": true
}, },
"tooltip": { "tooltip": {
@ -504,6 +441,7 @@
"sort": "none" "sort": "none"
} }
}, },
"pluginVersion": "9.5.2",
"targets": [ "targets": [
{ {
"datasource": { "datasource": {
@ -511,14 +449,26 @@
}, },
"editorMode": "builder", "editorMode": "builder",
"exemplar": true, "exemplar": true,
"expr": "rate(meilisearch_http_requests_total{instance=\"$instance\", job=\"meilisearch\"}[5m])", "expr": "meilisearch_db_size_bytes{job=\"meilisearch\", instance=\"$instance\"}",
"interval": "", "interval": "",
"legendFormat": "{{method}} {{path}}", "legendFormat": "Database size on disk",
"range": true, "range": true,
"refId": "A" "refId": "DB Size on disk"
},
{
"datasource": {
"type": "prometheus",
"uid": "c4085c47-f6d3-45dd-b761-6809055bb749"
},
"editorMode": "builder",
"expr": "meilisearch_used_db_size_bytes{job=\"meilisearch\", instance=\"$instance\"}",
"hide": false,
"legendFormat": "Used bytes",
"range": true,
"refId": "Actual used bytes"
} }
], ],
"title": "HTTP requests per second (All Indexes)", "title": "Database Size in bytes",
"type": "timeseries" "type": "timeseries"
}, },
{ {
@ -616,6 +566,101 @@
"title": "Mean response time (All Indexes)", "title": "Mean response time (All Indexes)",
"type": "timeseries" "type": "timeseries"
}, },
{
"datasource": {
"type": "prometheus",
"uid": "c4085c47-f6d3-45dd-b761-6809055bb749"
},
"fieldConfig": {
"defaults": {
"color": {
"mode": "continuous-YlBl"
},
"custom": {
"axisCenteredZero": false,
"axisColorMode": "text",
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 15,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "never",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"decimals": 2,
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 11,
"w": 12,
"x": 0,
"y": 18
},
"id": 1,
"interval": "5s",
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "right",
"showLegend": true
},
"tooltip": {
"mode": "single",
"sort": "none"
}
},
"targets": [
{
"datasource": {
"type": "prometheus"
},
"editorMode": "builder",
"exemplar": true,
"expr": "rate(meilisearch_http_requests_total{instance=\"$instance\", job=\"meilisearch\"}[5m])",
"interval": "",
"legendFormat": "{{method}} {{path}}",
"range": true,
"refId": "A"
}
],
"title": "HTTP requests per second (All Indexes)",
"type": "timeseries"
},
{ {
"cards": {}, "cards": {},
"color": { "color": {
@ -648,7 +693,7 @@
"h": 11, "h": 11,
"w": 24, "w": 24,
"x": 0, "x": 0,
"y": 18 "y": 29
}, },
"heatmap": {}, "heatmap": {},
"hideZeroBuckets": false, "hideZeroBuckets": false,
@ -790,7 +835,7 @@
"h": 11, "h": 11,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 29 "y": 40
}, },
"id": 23, "id": 23,
"interval": "5s", "interval": "5s",
@ -883,7 +928,7 @@
"h": 11, "h": 11,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 29 "y": 40
}, },
"id": 24, "id": 24,
"interval": "5s", "interval": "5s",
@ -976,7 +1021,7 @@
"h": 11, "h": 11,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 40 "y": 51
}, },
"id": 25, "id": 25,
"interval": "5s", "interval": "5s",
@ -1020,7 +1065,7 @@
"h": 1, "h": 1,
"w": 24, "w": 24,
"x": 0, "x": 0,
"y": 51 "y": 62
}, },
"id": 12, "id": 12,
"panels": [], "panels": [],
@ -1098,7 +1143,7 @@
"h": 11, "h": 11,
"w": 12, "w": 12,
"x": 0, "x": 0,
"y": 52 "y": 63
}, },
"id": 4, "id": 4,
"interval": "5s", "interval": "5s",
@ -1201,7 +1246,7 @@
"h": 11, "h": 11,
"w": 12, "w": 12,
"x": 12, "x": 12,
"y": 52 "y": 63
}, },
"id": 5, "id": 5,
"interval": "5s", "interval": "5s",
@ -1323,6 +1368,6 @@
"timezone": "", "timezone": "",
"title": "Meilisearch", "title": "Meilisearch",
"uid": "7wcZ94dnz", "uid": "7wcZ94dnz",
"version": 3, "version": 4,
"weekStart": "" "weekStart": ""
} }

View File

@ -90,6 +90,8 @@ pub struct IndexStats {
pub number_of_documents: u64, pub number_of_documents: u64,
/// Size of the index' DB, in bytes. /// Size of the index' DB, in bytes.
pub database_size: u64, pub database_size: u64,
/// Size of the index' DB, in bytes.
pub used_database_size: u64,
/// Association of every field name with the number of times it occurs in the documents. /// Association of every field name with the number of times it occurs in the documents.
pub field_distribution: FieldDistribution, pub field_distribution: FieldDistribution,
/// Creation date of the index. /// Creation date of the index.
@ -105,10 +107,10 @@ impl IndexStats {
/// ///
/// - rtxn: a RO transaction for the index, obtained from `Index::read_txn()`. /// - rtxn: a RO transaction for the index, obtained from `Index::read_txn()`.
pub fn new(index: &Index, rtxn: &RoTxn) -> Result<Self> { pub fn new(index: &Index, rtxn: &RoTxn) -> Result<Self> {
let database_size = index.on_disk_size()?;
Ok(IndexStats { Ok(IndexStats {
number_of_documents: index.number_of_documents(rtxn)?, number_of_documents: index.number_of_documents(rtxn)?,
database_size, database_size: index.on_disk_size()?,
used_database_size: index.used_size()?,
field_distribution: index.field_distribution(rtxn)?, field_distribution: index.field_distribution(rtxn)?,
created_at: index.created_at(rtxn)?, created_at: index.created_at(rtxn)?,
updated_at: index.updated_at(rtxn)?, updated_at: index.updated_at(rtxn)?,

View File

@ -554,10 +554,16 @@ impl IndexScheduler {
&self.index_mapper.indexer_config &self.index_mapper.indexer_config
} }
/// Return the real database size (i.e.: The size **with** the free pages)
pub fn size(&self) -> Result<u64> { pub fn size(&self) -> Result<u64> {
Ok(self.env.real_disk_size()?) Ok(self.env.real_disk_size()?)
} }
/// Return the used database size (i.e.: The size **without** the free pages)
pub fn used_size(&self) -> Result<u64> {
Ok(self.env.non_free_pages_size()?)
}
/// Return the index corresponding to the name. /// Return the index corresponding to the name.
/// ///
/// * If the index wasn't opened before, the index will be opened. /// * If the index wasn't opened before, the index will be opened.

View File

@ -45,6 +45,11 @@ impl AuthController {
self.store.size() self.store.size()
} }
/// Return the used size of the `AuthController` database in bytes.
pub fn used_size(&self) -> Result<u64> {
self.store.used_size()
}
pub fn create_key(&self, create_key: CreateApiKey) -> Result<Key> { pub fn create_key(&self, create_key: CreateApiKey) -> Result<Key> {
match self.store.get_api_key(create_key.uid)? { match self.store.get_api_key(create_key.uid)? {
Some(_) => Err(AuthControllerError::ApiKeyAlreadyExists(create_key.uid.to_string())), Some(_) => Err(AuthControllerError::ApiKeyAlreadyExists(create_key.uid.to_string())),

View File

@ -73,6 +73,11 @@ impl HeedAuthStore {
Ok(self.env.real_disk_size()?) Ok(self.env.real_disk_size()?)
} }
/// Return the number of bytes actually used in the database
pub fn used_size(&self) -> Result<u64> {
Ok(self.env.non_free_pages_size()?)
}
pub fn set_drop_on_close(&mut self, v: bool) { pub fn set_drop_on_close(&mut self, v: bool) {
self.should_close_on_drop = v; self.should_close_on_drop = v;
} }

View File

@ -23,7 +23,12 @@ lazy_static! {
) )
.expect("Can't create a metric"); .expect("Can't create a metric");
pub static ref MEILISEARCH_DB_SIZE_BYTES: IntGauge = pub static ref MEILISEARCH_DB_SIZE_BYTES: IntGauge =
register_int_gauge!(opts!("meilisearch_db_size_bytes", "Meilisearch Db Size In Bytes")) register_int_gauge!(opts!("meilisearch_db_size_bytes", "Meilisearch DB Size In Bytes"))
.expect("Can't create a metric");
pub static ref MEILISEARCH_USED_DB_SIZE_BYTES: IntGauge = register_int_gauge!(opts!(
"meilisearch_used_db_size_bytes",
"Meilisearch Used DB Size In Bytes"
))
.expect("Can't create a metric"); .expect("Can't create a metric");
pub static ref MEILISEARCH_INDEX_COUNT: IntGauge = pub static ref MEILISEARCH_INDEX_COUNT: IntGauge =
register_int_gauge!(opts!("meilisearch_index_count", "Meilisearch Index Count")) register_int_gauge!(opts!("meilisearch_index_count", "Meilisearch Index Count"))

View File

@ -31,6 +31,7 @@ pub async fn get_metrics(
let response = create_all_stats((*index_scheduler).clone(), auth_controller, auth_filters)?; let response = create_all_stats((*index_scheduler).clone(), auth_controller, auth_filters)?;
crate::metrics::MEILISEARCH_DB_SIZE_BYTES.set(response.database_size as i64); crate::metrics::MEILISEARCH_DB_SIZE_BYTES.set(response.database_size as i64);
crate::metrics::MEILISEARCH_USED_DB_SIZE_BYTES.set(response.used_database_size as i64);
crate::metrics::MEILISEARCH_INDEX_COUNT.set(response.indexes.len() as i64); crate::metrics::MEILISEARCH_INDEX_COUNT.set(response.indexes.len() as i64);
for (index, value) in response.indexes.iter() { for (index, value) in response.indexes.iter() {

View File

@ -231,6 +231,8 @@ pub async fn running() -> HttpResponse {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Stats { pub struct Stats {
pub database_size: u64, pub database_size: u64,
#[serde(skip)]
pub used_database_size: u64,
#[serde(serialize_with = "time::serde::rfc3339::option::serialize")] #[serde(serialize_with = "time::serde::rfc3339::option::serialize")]
pub last_update: Option<OffsetDateTime>, pub last_update: Option<OffsetDateTime>,
pub indexes: BTreeMap<String, indexes::IndexStats>, pub indexes: BTreeMap<String, indexes::IndexStats>,
@ -259,6 +261,7 @@ pub fn create_all_stats(
let mut last_task: Option<OffsetDateTime> = None; let mut last_task: Option<OffsetDateTime> = None;
let mut indexes = BTreeMap::new(); let mut indexes = BTreeMap::new();
let mut database_size = 0; let mut database_size = 0;
let mut used_database_size = 0;
for index_uid in index_scheduler.index_names()? { for index_uid in index_scheduler.index_names()? {
// Accumulate the size of all indexes, even unauthorized ones, so // Accumulate the size of all indexes, even unauthorized ones, so
@ -266,6 +269,7 @@ pub fn create_all_stats(
// See <https://github.com/meilisearch/meilisearch/pull/3541#discussion_r1126747643> for context. // See <https://github.com/meilisearch/meilisearch/pull/3541#discussion_r1126747643> for context.
let stats = index_scheduler.index_stats(&index_uid)?; let stats = index_scheduler.index_stats(&index_uid)?;
database_size += stats.inner_stats.database_size; database_size += stats.inner_stats.database_size;
used_database_size += stats.inner_stats.used_database_size;
if !filters.is_index_authorized(&index_uid) { if !filters.is_index_authorized(&index_uid) {
continue; continue;
@ -278,10 +282,14 @@ pub fn create_all_stats(
} }
database_size += index_scheduler.size()?; database_size += index_scheduler.size()?;
used_database_size += index_scheduler.used_size()?;
database_size += auth_controller.size()?; database_size += auth_controller.size()?;
database_size += index_scheduler.compute_update_file_size()?; used_database_size += auth_controller.used_size()?;
let update_file_size = index_scheduler.compute_update_file_size()?;
database_size += update_file_size;
used_database_size += update_file_size;
let stats = Stats { database_size, last_update: last_task, indexes }; let stats = Stats { database_size, used_database_size, last_update: last_task, indexes };
Ok(stats) Ok(stats)
} }