Version v1.5.1 of the documentation is no longer actively maintained. The site that you are currently viewing is an archived snapshot.
For up-to-date documentation, see the latest version.
How to use Pigsty to monitor existing PostgreSQL instances?
For existing Pigsty instances that Pigsty does not create, some additional configuration is required if they are monitored using Pigsty’s monitoring system.
pg-test:hosts:# Assign unique local ports to each instance10.10.10.11:{pg_seq:1, pg_role:primary , pg_exporter_port:20001}10.10.10.12:{pg_seq:2, pg_role:replica , pg_exporter_port:20002}10.10.10.13:{pg_seq:3, pg_role:offline , pg_exporter_port:20003}vars:pg_cluster:pg-test # Fill in the cluster namepg_version:14# Fill in the major version of the databasepg_databases:[{name:test }] # Fill in the database list (each database object as an array element)# Provide monitoring user passwords in global/cluster/instance configs pg_monitor_username/pg_monitor_password
Execute the playbook against the cluster: ./pgsql-monly.yml -l pg-test.
The playbook registers the target PostgreSQL data source in Grafana so that PGCAT functionality is fully available. The playbook deploys PG Exporter on the meta node to monitor remote PG instances, so pure database-related metrics in PGSQL are available. However, host node, connection pool, load balancing, and HA Patroni metrics are unavailable.
Overview
Suppose you want to use Pigsty for monitoring only. In that case, you can use monly mode. You can use Pigsty to manage and monitor other PostgreSQL instances (currently, 10+ versions are supported by default, the pg_exporter configuration file can manually modify older versions).
First, you need to complete the standard installation process of Pigsty on one meta node, and then you can connect more database instances to monitoring. According to the access rights of the target database node, there are two different cases.
Target nodes can be managed.
If the target DB node can be managed by Pigsty (ssh reachable, sudo available), you can use the pg-exporter task of the pgsql.yml playbook to deploy the monitoring component on the target node in the same way: PG Exporter. You can also use the other tasks of the playbook to deploy additional components and their monitoring on the existing instance node: connection pool Pgbouncer and load balancer HAProxy. In addition, the node-exporter and promtail tasks in nodes.yml can also be used to deploy the host node monitoring and log collection components on existing instance nodes. And log collection components.
Since the target database cluster already exists, you will need to manually create monitoring users, modes, and extensions on the target database cluster as described in this section. The rest of the process is no different from full deployment.
# Modify the pigsty config, add the yum repo to the node, and install the package via yumexporter_install: yum # none|yum|binary, none by defaultexporter_repo_url: http://<your primary ip address>/pigsty.repo
./nodes.yml -l <yourcluster> -t node-exporter # Deployment Node Metrics Monitoring./nodes.yml -l <yourcluster> -t promtail # Deployment Node Log Collection./pgsql.yml -l <yourcluster> -t pg-exporter # Deployment of PG metrics monitoring collection
Database connection string only.
If you can only access the target database using a PGURL (database connection string), consider monitoring the target database’s Monly mode/Basic mode. All monitoring components are deployed on the meta node where Pigsty is installed in this mode. The monitoring system will not have metrics related to nodes, connection pools, load balancers, and HA components, but the database and real-time status information in the Data Catalog will still be available.
To perform a lean monitoring deployment, you will also need to manually create monitoring users, modes, and extensions on the target database cluster as described in this section and ensure that the target database can be accessed from the meta node using monitoring users. After that, execute the pgsql-monly.yml playbook against the target cluster to complete the deployment.
This article focuses on this monly deployment mode.
Figure: the monly mode architecture, with multiple PG Exporter, deployed locally on the management machine for monitoring multiple remote database instances.
Difference
The Pigsty monitoring system consists of three core modules:
To include an external existing PostgreSQL instance in monitoring, a connection string that can be used to access the instance/cluster is required. It is recommended to use a dedicated monitoring user to avoid privilege leaks.
Monitor User: The default user name used is dbuser_monitor, which should belong to the pg_monitor role group or ensure that it has access to the relevant view.
Monitor Auth: Default is password access. You need to ensure the HBA policy allows the monitor user to access the database locally from the management machine or DB node.
Monitor Mode: Fixed using the name monitor for installing additional monitor views with extended plugins, optional but highly recommended.
Monitor Extensions: It is highly recommended to enable the monitor extension pg_stat_statements with PG.
This target cluster must be declared in the inventory (config file or CMDB). For example, specify the identity for the cluster with the instance. It is also necessary to manually assign a unique local port ( pg_exporter_port) to each instance at the instance level.
The following is a sample database cluster declaration.
pg-test:hosts:# Assign unique local ports to each instance10.10.10.11:{pg_seq:1, pg_role:primary , pg_exporter_port:20001}10.10.10.12:{pg_seq:2, pg_role:replica , pg_exporter_port:20002}10.10.10.13:{pg_seq:3, pg_role:offline , pg_exporter_port:20003}vars:pg_cluster:pg-test # Fill in cluster namepg_version:14# Fill in the major version of the databasepg_databases:[{name:test }] # Fill in the database list (each database object as an array element)# Provide monitoring user passwords in global/cluster/instance configs pg_monitor_username/pg_monitor_password
Even if you access the database through a domain name, you still need to declare the database cluster by filling in the actual IP.
To enable the PGCAT feature, you need to explicitly list in pg_databases the list of database names of the target cluster registered as Grafana’s data source and can access the Catalog data of that instance through Grafana. If you do not use the PGCAT function, do not set this variable or set it to an empty array.
Connect Info
Note: Pigsty will default generate the monitor connection string using the following rules. However, the pg_exporter_url will directly override the spliced connection string if it exists.
You can constantly monitor user/password globally or configure the following connection parameters on-demand at the cluster or instance level.
pg_monitor_username:dbuser_monitor # Monitor user name, no need to configure here if using the global configpg_monitor_password:DBUser.Monitor # Monitor user passwords, no need to configure here if using the global configpg_port:5432# If you use a non-standard database port, modify it here
Example: Specifying connect information at the instance-level
pg-test:hosts:# Specify the access URL for the instance10.10.10.11:pg_seq:1pg_role:primarypg_exporter_port:20001pg_monitor_username:monitor_user1pg_monitor_password:monitor_pass110.10.10.12:pg_seq:2pg_role:replicapg_exporter_port:20002# Specify pg_exporter_url directlypg_exporter_url:'postgres://someuser:[email protected]:5432/postgres?sslmode=disable''10.10.10.13:pg_seq:3pg_role:offlinepg_exporter_port:20003pg_monitor_username:monitor_user3pg_monitor_password:monitor_pass3vars:pg_cluster:pg-test # Fill in cluster namepg_version:14# Fill in the major version of the databasepg_databases:[{name:test }] # Fill in the database list (each database object as an array element)
Execute Playbook
Once the cluster declaration is complete, use the playbook pgsql-monly.yml on the meta node against the target cluster.
./pgsql-monly.yml -l <cluster> # Complete monitoring deployment on a specified cluster
Monitor Preparation
In monitor mode, the target DB nodes can be managed by Pigsty (ssh reachable, sudo available), and the user will install the following monitoring components on the existing nodes: promtail, node_exporter, pg_exporter.
You can use the node-exporter task in nodes.yml and the pg-exporter task in the pgsql.yml playbook to deploy the monitoring component on the target node: node_exporter with pg_exporter.
# Modify the pigsty config parameters, add the yum repo to the node, and install the package via yumexporter_install: yum # none|yum|binary, none by defaultexporter_repo_url: http://<your primary ip address>/pigsty.repo
./nodes.yml -l <yourcluster> -t promtail # Deployment node log collection (optional)./nodes.yml -l <yourcluster> -t node-exporter # Deployment Node Metrics Monitoring./pgsql.yml -l <yourcluster> -t pg-exporter # Deployment of PG metrics collection
When the value of exporter_install is yum, Pigsty will download from the URL specified by the exporter_repo_url Repo file to the node’s local /etc/yum.repos.d. You should fill in the Pigsty local source address on the meta node, for example, http://10.10.10.10/pigsty.repo.
Targets Config
How to configure users, modes, extensions, views, and functions required for monitoring existing instances.
Monitor user
Take the monitoring user dbuser_monitor used by Pigsty by default as an example, and create the following user in the target cluster.
CREATEUSERdbuser_monitor;GRANTpg_monitorTOdbuser_monitor;COMMENTONROLEdbuser_monitorIS'system monitor user';ALTERUSERdbuser_monitorSETlog_min_duration_statement=1000;ALTERUSERdbuser_monitorPASSWORD'DBUser.Password';-- Change monitor user password as needed
Configure the database file pg_hba.conf by adding the following rules to allow monitoring users to access the database from local, and management machines using passwords.
# allow local role monitor with passwordlocal all dbuser_monitor md5host all dbuser_monitor 127.0.0.1/32 md5host all dbuser_monitor <management machine IP address>/32 md5
Monitor mode
It is recommended to create a monitor mode and enable at least the pg_stat_statements that come with PG, which provides essential data on query performance. Note: This extension must be included in the database parameter shared_preload_libraries. Modifying this parameter requires a database restart.
Creating an extension mode.
CREATESCHEMAIFNOTEXISTSmonitor;-- Create a monitor-specific mode
GRANTUSAGEONSCHEMAmonitorTOdbuser_monitor;-- Allow monitor users to use
Monitor extensions
Create extension plugins.
-- It is highly recommended to enable the pg_stat_statements extension
CREATEEXTENSIONIFNOTEXISTS"pg_stat_statements"WITHSCHEMA"monitor";-- optional other extensions
CREATEEXTENSIONIFNOTEXISTS"pgstattuple"WITHSCHEMA"monitor";CREATEEXTENSIONIFNOTEXISTS"pg_qualstats"WITHSCHEMA"monitor";CREATEEXTENSIONIFNOTEXISTS"pg_buffercache"WITHSCHEMA"monitor";CREATEEXTENSIONIFNOTEXISTS"pageinspect"WITHSCHEMA"monitor";CREATEEXTENSIONIFNOTEXISTS"pg_prewarm"WITHSCHEMA"monitor";CREATEEXTENSIONIFNOTEXISTS"pg_visibility"WITHSCHEMA"monitor";CREATEEXTENSIONIFNOTEXISTS"pg_freespacemap"WITHSCHEMA"monitor";
Monitor Views
The monitoring view shows common preprocessing results and wraps privileges for specific monitoring metrics (e.g., shared memory allocation). It is highly recommended to create it in all databases that need to be monitored.
Monitor Views
--==================================================================--
-- Monitor Schema --
--==================================================================--
----------------------------------------------------------------------
-- cleanse
----------------------------------------------------------------------
CREATESCHEMAIFNOTEXISTSmonitor;GRANTUSAGEONSCHEMAmonitorTOdbuser_monitor;GRANTUSAGEONSCHEMAmonitorTO"{{ pg_admin_username }}";GRANTUSAGEONSCHEMAmonitorTO"{{ pg_replication_username }}";--==================================================================--
-- Monitor Views --
--==================================================================--
----------------------------------------------------------------------
-- Table bloat estimate : monitor.pg_table_bloat
----------------------------------------------------------------------
DROPVIEWIFEXISTSmonitor.pg_table_bloatCASCADE;CREATEORREPLACEVIEWmonitor.pg_table_bloatASSELECTCURRENT_CATALOGASdatname,nspname,relname,tblid,bs*tblpagesASsize,CASEWHENtblpages-est_tblpages_ff>0THEN(tblpages-est_tblpages_ff)/tblpages::FLOATELSE0ENDASratioFROM(SELECTceil(reltuples/((bs-page_hdr)*fillfactor/(tpl_size*100)))+ceil(toasttuples/4)ASest_tblpages_ff,tblpages,fillfactor,bs,tblid,nspname,relname,is_naFROM(SELECT(4+tpl_hdr_size+tpl_data_size+(2*ma)-CASEWHENtpl_hdr_size%ma=0THENmaELSEtpl_hdr_size%maEND-CASEWHENceil(tpl_data_size)::INT%ma=0THENmaELSEceil(tpl_data_size)::INT%maEND)AStpl_size,(heappages+toastpages)AStblpages,heappages,toastpages,reltuples,toasttuples,bs,page_hdr,tblid,nspname,relname,fillfactor,is_naFROM(SELECTtbl.oidAStblid,ns.nspname,tbl.relname,tbl.reltuples,tbl.relpagesASheappages,coalesce(toast.relpages,0)AStoastpages,coalesce(toast.reltuples,0)AStoasttuples,coalesce(substring(array_to_string(tbl.reloptions,' ')FROM'fillfactor=([0-9]+)')::smallint,100)ASfillfactor,current_setting('block_size')::numericASbs,CASEWHENversion()~'mingw32'ORversion()~'64-bit|x86_64|ppc64|ia64|amd64'THEN8ELSE4ENDASma,24ASpage_hdr,23+CASEWHENMAX(coalesce(s.null_frac,0))>0THEN(7+count(s.attname))/8ELSE0::intEND+CASEWHENbool_or(att.attname='oid'andatt.attnum<0)THEN4ELSE0ENDAStpl_hdr_size,sum((1-coalesce(s.null_frac,0))*coalesce(s.avg_width,0))AStpl_data_size,bool_or(att.atttypid='pg_catalog.name'::regtype)ORsum(CASEWHENatt.attnum>0THEN1ELSE0END)<>count(s.attname)ASis_naFROMpg_attributeASattJOINpg_classAStblONatt.attrelid=tbl.oidJOINpg_namespaceASnsONns.oid=tbl.relnamespaceLEFTJOINpg_statsASsONs.schemaname=ns.nspnameANDs.tablename=tbl.relnameANDs.inherited=falseANDs.attname=att.attnameLEFTJOINpg_classAStoastONtbl.reltoastrelid=toast.oidWHERENOTatt.attisdroppedANDtbl.relkind='r'ANDnspnameNOTIN('pg_catalog','information_schema')GROUPBY1,2,3,4,5,6,7,8,9,10)ASs)ASs2)ASs3WHERENOTis_na;COMMENTONVIEWmonitor.pg_table_bloatIS'postgres table bloat estimate';----------------------------------------------------------------------
-- Index bloat estimate : monitor.pg_index_bloat
----------------------------------------------------------------------
DROPVIEWIFEXISTSmonitor.pg_index_bloatCASCADE;CREATEORREPLACEVIEWmonitor.pg_index_bloatASSELECTCURRENT_CATALOGASdatname,nspname,idxnameASrelname,tblid,idxid,relpages::BIGINT*bsASsize,COALESCE((relpages-(reltuples*(6+ma-(CASEWHENindex_tuple_hdr%ma=0THENmaELSEindex_tuple_hdr%maEND)+nulldatawidth+ma-(CASEWHENnulldatawidth%ma=0THENmaELSEnulldatawidth%maEND))/(bs-pagehdr)::FLOAT+1)),0)/relpages::FLOATASratioFROM(SELECTnspname,idxname,indrelidAStblid,indexrelidASidxid,reltuples,relpages,current_setting('block_size')::INTEGERASbs,(CASEWHENversion()~'mingw32'ORversion()~'64-bit|x86_64|ppc64|ia64|amd64'THEN8ELSE4END)ASma,24ASpagehdr,(CASEWHENmax(COALESCE(pg_stats.null_frac,0))=0THEN2ELSE6END)ASindex_tuple_hdr,sum((1.0-COALESCE(pg_stats.null_frac,0.0))*COALESCE(pg_stats.avg_width,1024))::INTEGERASnulldatawidthFROMpg_attributeJOIN(SELECTpg_namespace.nspname,ic.relnameASidxname,ic.reltuples,ic.relpages,pg_index.indrelid,pg_index.indexrelid,tc.relnameAStablename,regexp_split_to_table(pg_index.indkey::TEXT,' ')::INTEGERASattnum,pg_index.indexrelidASindex_oidFROMpg_indexJOINpg_classicONpg_index.indexrelid=ic.oidJOINpg_classtcONpg_index.indrelid=tc.oidJOINpg_namespaceONpg_namespace.oid=ic.relnamespaceJOINpg_amONic.relam=pg_am.oidWHEREpg_am.amname='btree'ANDic.relpages>0ANDnspnameNOTIN('pg_catalog','information_schema'))ind_attsONpg_attribute.attrelid=ind_atts.indexrelidANDpg_attribute.attnum=ind_atts.attnumJOINpg_statsONpg_stats.schemaname=ind_atts.nspnameAND((pg_stats.tablename=ind_atts.tablenameANDpg_stats.attname=pg_get_indexdef(pg_attribute.attrelid,pg_attribute.attnum,TRUE))OR(pg_stats.tablename=ind_atts.idxnameANDpg_stats.attname=pg_attribute.attname))WHEREpg_attribute.attnum>0GROUPBY1,2,3,4,5,6)est;COMMENTONVIEWmonitor.pg_index_bloatIS'postgres index bloat estimate (btree-only)';----------------------------------------------------------------------
-- Relation Bloat : monitor.pg_bloat
----------------------------------------------------------------------
DROPVIEWIFEXISTSmonitor.pg_bloatCASCADE;CREATEORREPLACEVIEWmonitor.pg_bloatASSELECTcoalesce(ib.datname,tb.datname)ASdatname,coalesce(ib.nspname,tb.nspname)ASnspname,coalesce(ib.tblid,tb.tblid)AStblid,coalesce(tb.nspname||'.'||tb.relname,ib.nspname||'.'||ib.tblid::RegClass)AStblname,tb.sizeAStbl_size,CASEWHENtb.ratio<0THEN0ELSEround(tb.ratio::NUMERIC,6)ENDAStbl_ratio,(tb.size*(CASEWHENtb.ratio<0THEN0ELSEtb.ratio::NUMERICEND))::BIGINTAStbl_wasted,ib.idxid,ib.nspname||'.'||ib.relnameASidxname,ib.sizeASidx_size,CASEWHENib.ratio<0THEN0ELSEround(ib.ratio::NUMERIC,5)ENDASidx_ratio,(ib.size*(CASEWHENib.ratio<0THEN0ELSEib.ratio::NUMERICEND))::BIGINTASidx_wastedFROMmonitor.pg_index_bloatibFULLOUTERJOINmonitor.pg_table_bloattbONib.tblid=tb.tblid;COMMENTONVIEWmonitor.pg_bloatIS'postgres relation bloat detail';----------------------------------------------------------------------
-- monitor.pg_index_bloat_human
----------------------------------------------------------------------
DROPVIEWIFEXISTSmonitor.pg_index_bloat_humanCASCADE;CREATEORREPLACEVIEWmonitor.pg_index_bloat_humanASSELECTidxnameASname,tblname,idx_wastedASwasted,pg_size_pretty(idx_size)ASidx_size,round(100*idx_ratio::NUMERIC,2)ASidx_ratio,pg_size_pretty(idx_wasted)ASidx_wasted,pg_size_pretty(tbl_size)AStbl_size,round(100*tbl_ratio::NUMERIC,2)AStbl_ratio,pg_size_pretty(tbl_wasted)AStbl_wastedFROMmonitor.pg_bloatWHEREidxnameISNOTNULL;COMMENTONVIEWmonitor.pg_index_bloat_humanIS'postgres index bloat info in human-readable format';----------------------------------------------------------------------
-- monitor.pg_table_bloat_human
----------------------------------------------------------------------
DROPVIEWIFEXISTSmonitor.pg_table_bloat_humanCASCADE;CREATEORREPLACEVIEWmonitor.pg_table_bloat_humanASSELECTtblnameASname,idx_wasted+tbl_wastedASwasted,pg_size_pretty(idx_wasted+tbl_wasted)ASall_wasted,pg_size_pretty(tbl_wasted)AStbl_wasted,pg_size_pretty(tbl_size)AStbl_size,tbl_ratio,pg_size_pretty(idx_wasted)ASidx_wasted,pg_size_pretty(idx_size)ASidx_size,round(idx_wasted::NUMERIC*100.0/idx_size,2)ASidx_ratioFROM(SELECTdatname,nspname,tblname,coalesce(max(tbl_wasted),0)AStbl_wasted,coalesce(max(tbl_size),1)AStbl_size,round(100*coalesce(max(tbl_ratio),0)::NUMERIC,2)AStbl_ratio,coalesce(sum(idx_wasted),0)ASidx_wasted,coalesce(sum(idx_size),1)ASidx_sizeFROMmonitor.pg_bloatWHEREtblnameISNOTNULLGROUPBY1,2,3)d;COMMENTONVIEWmonitor.pg_table_bloat_humanIS'postgres table bloat info in human-readable format';----------------------------------------------------------------------
-- Activity Overview: monitor.pg_session
----------------------------------------------------------------------
DROPVIEWIFEXISTSmonitor.pg_sessionCASCADE;CREATEORREPLACEVIEWmonitor.pg_sessionASSELECTcoalesce(datname,'all')ASdatname,numbackends,active,idle,ixact,max_duration,max_tx_duration,max_conn_durationFROM(SELECTdatname,count(*)ASnumbackends,count(*)FILTER(WHEREstate='active')ASactive,count(*)FILTER(WHEREstate='idle')ASidle,count(*)FILTER(WHEREstate='idle in transaction'ORstate='idle in transaction (aborted)')ASixact,max(extract(epochfromnow()-state_change))FILTER(WHEREstate='active')ASmax_duration,max(extract(epochfromnow()-xact_start))ASmax_tx_duration,max(extract(epochfromnow()-backend_start))ASmax_conn_durationFROMpg_stat_activityWHEREbackend_type='client backend'ANDpid<>pg_backend_pid()GROUPBYROLLUP(1)ORDERBY1NULLSFIRST)t;COMMENTONVIEWmonitor.pg_sessionIS'postgres activity group by session';----------------------------------------------------------------------
-- Sequential Scan: monitor.pg_seq_scan
----------------------------------------------------------------------
DROPVIEWIFEXISTSmonitor.pg_seq_scanCASCADE;CREATEORREPLACEVIEWmonitor.pg_seq_scanASSELECTschemanameASnspname,relname,seq_scan,seq_tup_read,seq_tup_read/seq_scanASseq_tup_avg,idx_scan,n_live_tup+n_dead_tupAStuples,round(n_live_tup*100.0::NUMERIC/(n_live_tup+n_dead_tup),2)ASlive_ratioFROMpg_stat_user_tablesWHEREseq_scan>0and(n_live_tup+n_dead_tup)>0ORDERBYseq_scanDESC;COMMENTONVIEWmonitor.pg_seq_scanIS'table that have seq scan';
Functions to view shared memory allocations (available for PG13 and above)
DROPFUNCTIONIFEXISTSmonitor.pg_shmem()CASCADE;CREATEORREPLACEFUNCTIONmonitor.pg_shmem()RETURNSSETOFpg_shmem_allocationsAS$$SELECT*FROMpg_shmem_allocations;$$LANGUAGESQLSECURITYDEFINER;COMMENTONFUNCTIONmonitor.pg_shmem()IS'security wrapper for pg_shmem';