Compare commits

...

17 Commits

Author SHA1 Message Date
Alexey Kondratov
00b41a5520 Calm clippy 2022-09-29 20:51:52 +03:00
Alexey Kondratov
4b5cf917e5 Return all columns from pg_stat_statements 2022-09-29 18:40:54 +03:00
Eduard Dyckman
d9e14fdcfb Collect pg_stat_statements to insights 2022-09-29 17:54:19 +03:00
Eduard Dyckman
95cfd7f229 Added insights route 2022-09-29 16:49:10 +03:00
Anastasia Lubennikova
414ca54823 fix Dockerfile.compute-node-v14 2022-09-29 15:56:21 +03:00
Anastasia Lubennikova
d4dda80ed4 fix Dockerfile.compute-node-v14 2022-09-29 15:55:32 +03:00
Anastasia Lubennikova
fa648997d0 fix Dockerfile.compute-node-v14 2022-09-29 15:50:32 +03:00
Alexey Kondratov
3fba7ea8c0 Create and load pg_state_statements on compute start 2022-09-29 15:36:56 +03:00
Anastasia Lubennikova
8c873c381b fix Dockerfile.compute-node-v14 2022-09-29 15:35:45 +03:00
Anastasia Lubennikova
86090fb48c fix Dockerfile.compute-node-v14 2022-09-29 15:31:46 +03:00
Anastasia Lubennikova
bce90c6290 fix Dockerfile.compute-node-v14 2022-09-29 15:11:01 +03:00
Anastasia Lubennikova
ab64824d00 Add pg_query_state shared preload library to local control_plane 2022-09-29 14:36:36 +03:00
Anastasia Lubennikova
6e4e4baab0 Bump vendor/postgres-v14 - use pg_stat_contribs branch 2022-09-29 14:36:03 +03:00
Anastasia Lubennikova
2b08d3dd1b mark pg_stat_statements contrib as trusted in Dockerfile.compute-node-v14 2022-09-29 13:15:16 +03:00
Anastasia Lubennikova
db62d30751 Add stat-contribs to Dockerfile.compute-node-v14 2022-09-29 13:08:16 +03:00
Anastasia Lubennikova
7bae3d75d3 Add pg_query_state to Makefile 2022-09-29 12:59:39 +03:00
Anastasia Lubennikova
f6ab7df5a7 Add pg_stat_statements and pg_wait_sampling extensions to Makefile 2022-09-29 11:50:59 +03:00
9 changed files with 125 additions and 7 deletions

View File

@@ -57,6 +57,31 @@ RUN wget https://download.osgeo.org/postgis/source/postgis-3.3.0.tar.gz && \
echo 'trusted = true' >> /usr/local/pgsql/share/extension/postgis_tiger_geocoder.control && \
echo 'trusted = true' >> /usr/local/pgsql/share/extension/postgis_topology.control
# Layer "pg-stat-contribs-build"
# Build pg_stat_statements, pg_wait_sampling, pg_query_state
FROM build-deps AS pg-query-state-build
COPY --from=pg-build /usr/local/pgsql/ /usr/local/pgsql/
RUN wget https://github.com/postgrespro/pg_query_state/archive/refs/heads/master.tar.gz && \
tar xvzf master.tar.gz && \
cd pg_query_state-master && \
export PATH="/usr/local/pgsql/bin:$PATH" && \
USE_PGXS=true PG_CONFIG=/usr/local/pgsql/bin/pg_config make -j $(getconf _NPROCESSORS_ONLN) && \
USE_PGXS=true PG_CONFIG=/usr/local/pgsql/bin/pg_config make -j $(getconf _NPROCESSORS_ONLN) install && \
echo 'trusted = true' >> /usr/local/pgsql/share/extension/pg_query_state.control
FROM build-deps AS pg-wait-sampling-build
COPY --from=pg-build /usr/local/pgsql/ /usr/local/pgsql/
RUN wget https://github.com/postgrespro/pg_wait_sampling/archive/refs/heads/master.tar.gz && \
tar xvzf master.tar.gz && \
cd pg_wait_sampling-master && \
export PATH="/usr/local/pgsql/bin:$PATH" && \
USE_PGXS=true PG_CONFIG=/usr/local/pgsql/bin/pg_config make -j $(getconf _NPROCESSORS_ONLN) && \
USE_PGXS=true PG_CONFIG=/usr/local/pgsql/bin/pg_config make -j $(getconf _NPROCESSORS_ONLN) install && \
echo 'trusted = true' >> /usr/local/pgsql/share/extension/pg_wait_sampling.control
#
# Layer "plv8-build"
# Build plv8
@@ -116,6 +141,8 @@ RUN wget https://github.com/zachasme/h3-pg/archive/refs/tags/v4.0.1.tar.gz -O h3
#
FROM build-deps AS neon-pg-ext-build
COPY --from=postgis-build /usr/local/pgsql/ /usr/local/pgsql/
COPY --from=pg-query-state-build /usr/local/pgsql/ /usr/local/pgsql/
COPY --from=pg-wait-sampling-build /usr/local/pgsql/ /usr/local/pgsql/
# plv8 still sometimes crashes during the creation
# COPY --from=plv8-build /usr/local/pgsql/ /usr/local/pgsql/
COPY --from=h3-pg-build /usr/local/pgsql/ /usr/local/pgsql/

View File

@@ -116,6 +116,21 @@ postgres-v14: postgres-v14-configure \
+@echo "Compiling pageinspect v14"
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/v14/contrib/pageinspect install
.PHONY: pg_wait_sampling-v14
pg_wait_sampling-v14: postgres-v14-configure
+@echo "Compiling pg_wait_sampling v14"
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/v14/contrib/pg_wait_sampling install
.PHONY: pg_stat_statements-v14
pg_stat_statements-v14: postgres-v14-configure
+@echo "Compiling pg_stat_statements v14"
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/v14/contrib/pg_stat_statements install
.PHONY: pg_query_state-v14
pg_query_state-v14: postgres-v14-configure
+@echo "Compiling pg_query_state v14"
$(MAKE) -C $(POSTGRES_INSTALL_DIR)/build/v14/contrib/pg_query_state install
.PHONY: postgres-v15
postgres-v15: postgres-v15-configure \
postgres-v15-headers # to prevent `make install` conflicts with neon's `postgres-headers`

View File

@@ -26,6 +26,7 @@ use chrono::{DateTime, Utc};
use log::info;
use postgres::{Client, NoTls};
use serde::{Serialize, Serializer};
use tokio_postgres;
use crate::checker::create_writablity_check_data;
use crate::config;
@@ -50,6 +51,19 @@ pub struct ComputeNode {
pub state: RwLock<ComputeState>,
}
#[derive(Debug, Serialize)]
pub struct InsightsRow {
pub query: String,
pub total_runtime: String,
pub mean_runtime: String,
}
#[derive(Serialize)]
pub struct Insights {
count: u64,
statements: Vec<InsightsRow>,
}
fn rfc3339_serialize<S>(x: &DateTime<Utc>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@@ -296,6 +310,7 @@ impl ComputeNode {
Ok(client) => client,
};
create_system_extensions(&mut client)?;
handle_roles(&self.spec, &mut client)?;
handle_databases(&self.spec, &mut client)?;
handle_role_deletions(self, &mut client)?;
@@ -351,4 +366,38 @@ impl ComputeNode {
self.prepare_pgdata()?;
self.run()
}
pub async fn collect_insights(&self) -> String {
let mut result_rows: Vec<String> = Vec::new();
let connect_result = tokio_postgres::connect(self.connstr.as_str(), NoTls).await;
let (client, connection) = connect_result.unwrap();
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
for message in (client
.simple_query(
"
SELECT
row_to_json(pg_stat_statements)
FROM
pg_stat_statements
WHERE
userid != 'cloud_admin'::regrole::oid
ORDER BY
(mean_exec_time + mean_plan_time) DESC
LIMIT 100",
)
.await)
.unwrap()
.iter()
{
if let postgres::SimpleQueryMessage::Row(row) = message {
result_rows.push(row.get(0).unwrap().to_string());
}
}
format!("{{\"pg_stat_statements\": [{}]}}", result_rows.join(","))
}
}

View File

@@ -46,6 +46,13 @@ async fn routes(req: Request<Body>, compute: Arc<ComputeNode>) -> Response<Body>
Response::new(Body::from(serde_json::to_string(&compute.metrics).unwrap()))
}
// Collect Postgres current usage insights
(&Method::GET, "/insights") => {
info!("serving /insights GET request");
let insights = compute.collect_insights().await;
Response::new(Body::from(insights))
}
// DEPRECATED, use POST instead
(&Method::GET, "/check_writability") => {
info!("serving /check_writability GET request");

View File

@@ -61,7 +61,9 @@ impl GenericOption {
/// Represent `GenericOption` as configuration option.
pub fn to_pg_setting(&self) -> String {
if let Some(val) = &self.value {
if let Some(val) = self.value.as_ref() {
// XXX: such overrides don't look as they should be here, but I cannot find a better place now
// Probably, we need to add some override pass before the first compute start steps.
let name = match self.name.as_str() {
"safekeepers" => "neon.safekeepers",
"wal_acceptor_reconnect" => "neon.safekeeper_reconnect_timeout",
@@ -69,9 +71,14 @@ impl GenericOption {
it => it,
};
let mut res_val = val.to_owned();
if self.name == "shared_preload_libraries" && !res_val.contains("pg_stat_statements") {
res_val = format!("{},pg_stat_statements", res_val)
}
match self.vartype.as_ref() {
"string" => format!("{} = '{}'", name, val),
_ => format!("{} = {}", name, val),
"string" => format!("{} = '{}'", name, res_val),
_ => format!("{} = {}", name, res_val),
}
} else {
self.name.to_owned()

View File

@@ -426,3 +426,14 @@ pub fn handle_grants(node: &ComputeNode, client: &mut Client) -> Result<()> {
Ok(())
}
pub fn create_system_extensions(client: &mut Client) -> Result<()> {
for ext in ["pg_stat_statements", "neon"].iter() {
let query: String = format!("CREATE EXTENSION IF NOT EXISTS {}", ext);
info!("creating extension '{}'", ext);
client.execute(query.as_str(), &[])?;
}
Ok(())
}

View File

@@ -28,8 +28,7 @@ mod pg_helpers_tests {
assert_eq!(
spec.cluster.settings.as_pg_settings(),
"fsync = off\nwal_level = replica\nhot_standby = on\nneon.safekeepers = '127.0.0.1:6502,127.0.0.1:6503,127.0.0.1:6501'\nwal_log_hints = on\nlog_connections = on\nshared_buffers = 32768\nport = 55432\nmax_connections = 100\nmax_wal_senders = 10\nlisten_addresses = '0.0.0.0'\nwal_sender_timeout = 0\npassword_encryption = md5\nmaintenance_work_mem = 65536\nmax_parallel_workers = 8\nmax_worker_processes = 8\nneon.tenant_id = 'b0554b632bd4d547a63b86c3630317e8'\nmax_replication_slots = 10\nneon.timeline_id = '2414a61ffc94e428f14b5758fe308e13'\nshared_preload_libraries = 'neon'\nsynchronous_standby_names = 'walproposer'\nneon.pageserver_connstring = 'host=127.0.0.1 port=6400'"
);
"fsync = off\nwal_level = replica\nhot_standby = on\nneon.safekeepers = '127.0.0.1:6502,127.0.0.1:6503,127.0.0.1:6501'\nwal_log_hints = on\nlog_connections = on\nshared_buffers = 32768\nport = 55432\nmax_connections = 100\nmax_wal_senders = 10\nlisten_addresses = '0.0.0.0'\nwal_sender_timeout = 0\npassword_encryption = md5\nmaintenance_work_mem = 65536\nmax_parallel_workers = 8\nmax_worker_processes = 8\nneon.tenant_id = 'b0554b632bd4d547a63b86c3630317e8'\nmax_replication_slots = 10\nneon.timeline_id = '2414a61ffc94e428f14b5758fe308e13'\nshared_preload_libraries = 'neon,pg_stat_statements'\nsynchronous_standby_names = 'walproposer'\nneon.pageserver_connstring = 'host=127.0.0.1 port=6400'" );
}
#[test]

View File

@@ -321,7 +321,10 @@ impl PostgresNode {
// uses only needed variables namely host, port, user, password.
format!("postgresql://no_user:{password}@{host}:{port}")
};
conf.append("shared_preload_libraries", "neon");
conf.append(
"shared_preload_libraries",
"neon, pg_stat_statements, pg_wait_sampling, pg_query_state",
);
conf.append_line("");
conf.append("neon.pageserver_connstring", &pageserver_connstr);
conf.append("neon.tenant_id", &self.tenant_id.to_string());