userver: userver/storages/postgres/statistics.hpp Source File
Loading...
Searching...
No Matches
statistics.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/statistics.hpp
4/// @brief Statistics helpers
5
6#include <string>
7#include <unordered_map>
8#include <vector>
9
10#include <userver/storages/postgres/detail/time_types.hpp>
11
12#include <userver/congestion_control/controllers/linear.hpp>
13#include <userver/utils/statistics/min_max_avg.hpp>
14#include <userver/utils/statistics/percentile.hpp>
15#include <userver/utils/statistics/rate_counter.hpp>
16#include <userver/utils/statistics/recentperiod.hpp>
17#include <userver/utils/statistics/relaxed_counter.hpp>
18#include <userver/utils/statistics/writer.hpp>
19
20USERVER_NAMESPACE_BEGIN
21
22namespace storages::postgres {
23
24/// @brief Template transaction statistics storage
25template <typename Counter, typename PercentileAccumulator>
27 /// Number of transactions started
28 Counter total = 0;
29 /// Number of transactions committed
30 Counter commit_total = 0;
31 /// Number of transactions rolled back
32 Counter rollback_total = 0;
33 /// Number of out-of-transaction executions
34 Counter out_of_trx_total = 0;
35 /// Number of parsed queries
36 Counter parse_total = 0;
37 /// Number of query executions
38 Counter execute_total = 0;
39 /// Total number of replies
40 Counter reply_total = 0;
41 /// Number of portal bind operations
43 /// Error during query execution
45 /// Timeout while executing query
46 Counter execute_timeout = 0;
47 /// Duplicate prepared statements
48 /// This is not a hard error, the prepared statements are quite reusable due
49 /// to pretty uniqueness of names. Nevertheless we would like to see them to
50 /// diagnose certain kinds of problems
52
53 // TODO pick reasonable resolution for transaction
54 // execution times
55 /// Transaction overall execution time distribution
56 PercentileAccumulator total_percentile;
57 /// Transaction aggregated query execution time distribution
58 PercentileAccumulator busy_percentile;
59 /// Transaction wait for pool time (difference between trx_start_time and
60 /// work_start_time)
61 PercentileAccumulator wait_start_percentile;
62 /// Transaction wait for pool time (difference between last_execute_finish and
63 /// trx_end_time)
64 PercentileAccumulator wait_end_percentile;
65 /// Return to pool percentile (difference between trx_end_time and time the
66 /// connection has been returned to the pool)
67 PercentileAccumulator return_to_pool_percentile;
68};
69
70/// @brief Template connection statistics storage
71template <typename Counter, typename MmaAccumulator>
73 /// Number of connections opened
74 Counter open_total = 0;
75 /// Number of connections dropped
76 Counter drop_total = 0;
77 /// Number of active connections
78 Counter active = 0;
79 /// Number of connections in use
80 Counter used = 0;
81 /// Number of maximum allowed connections
82 Counter maximum = 0;
83 /// Number of waiting requests
84 Counter waiting = 0;
85 /// Error during connection
86 Counter error_total = 0;
87 /// Connection timeouts (timeouts while connecting)
88 Counter error_timeout = 0;
89 /// Number of rejected connection attempts due to rate limiting
91 /// Number of maximum allowed waiting requests
92 Counter max_queue_size = 0;
93
94 /// Prepared statements count min-max-avg
95 MmaAccumulator prepared_statements;
96};
97
98/// @brief Template instance topology statistics storage
99template <typename MmaAccumulator>
101 /// Roundtrip time min-max-avg
102 MmaAccumulator roundtrip_time;
103 /// Replication lag min-max-avg
104 MmaAccumulator replication_lag;
105};
106
107/// @brief Template instance statistics storage
108template <typename Counter, typename PercentileAccumulator, typename MmaAccumulator>
110 /// Connection statistics
111 ConnectionStatistics<Counter, MmaAccumulator> connection;
112 /// Transaction statistics
113 TransactionStatistics<Counter, PercentileAccumulator> transaction;
114 /// Topology statistics
116 /// Error caused by pool exhaustion
118 /// Error caused by queue size overflow
119 Counter queue_size_errors = 0;
120 /// Connect time percentile
121 PercentileAccumulator connection_percentile;
122 /// Acquire connection percentile
123 PercentileAccumulator acquire_percentile;
124 /// Congestion control statistics
125 std::conditional_t<std::is_same_v<Counter, uint32_t>, std::byte /* NOOP */, congestion_control::v2::Stats>
127};
128
129using RateCounter = USERVER_NAMESPACE::utils::statistics::RateCounter;
130using Percentile = USERVER_NAMESPACE::utils::statistics::Percentile<2048>;
131using MinMaxAvg = USERVER_NAMESPACE::utils::statistics::MinMaxAvg<uint32_t>;
132using InstanceStatistics = InstanceStatisticsTemplate<
133 USERVER_NAMESPACE::utils::statistics::RelaxedCounter<uint32_t>,
134 USERVER_NAMESPACE::utils::statistics::RecentPeriod<Percentile, Percentile, detail::SteadyCoarseClock>,
135 USERVER_NAMESPACE::utils::statistics::RecentPeriod<MinMaxAvg, MinMaxAvg, detail::SteadyCoarseClock>>;
136
137struct StatementStatistics final {
138 Percentile timings{};
139 RateCounter executed{};
140 RateCounter errors{};
141
142 void Add(const StatementStatistics& other) {
143 timings.Add(other.timings);
144 executed.Add(other.executed.Load());
145 errors.Add(other.errors.Load());
146 }
147};
148
149using InstanceStatisticsNonatomicBase = InstanceStatisticsTemplate<uint32_t, Percentile, MinMaxAvg>;
150
151struct InstanceStatisticsNonatomic : InstanceStatisticsNonatomicBase {
152 InstanceStatisticsNonatomic() = default;
153
154 template <typename Statistics>
155 InstanceStatisticsNonatomic(const Statistics& stats) {
156 *this = stats;
157 }
158 InstanceStatisticsNonatomic(InstanceStatisticsNonatomic&&) = default;
160
162 const InstanceStatistics& stats,
163 const decltype(InstanceStatistics::topology)& topology_stats
164 ) {
165 connection.open_total = stats.connection.open_total;
166 connection.drop_total = stats.connection.drop_total;
167 connection.active = stats.connection.active;
168 connection.used = stats.connection.used;
169 connection.maximum = stats.connection.maximum;
170 connection.waiting = stats.connection.waiting;
171 connection.error_total = stats.connection.error_total;
172 connection.error_timeout = stats.connection.error_timeout;
173 connection.rate_limit_throttled = stats.connection.rate_limit_throttled;
174 connection.prepared_statements = stats.connection.prepared_statements.GetStatsForPeriod();
175 connection.max_queue_size = stats.connection.max_queue_size;
176
177 transaction.total = stats.transaction.total;
178 transaction.commit_total = stats.transaction.commit_total;
179 transaction.rollback_total = stats.transaction.rollback_total;
180 transaction.out_of_trx_total = stats.transaction.out_of_trx_total;
181 transaction.parse_total = stats.transaction.parse_total;
182 transaction.execute_total = stats.transaction.execute_total;
183 transaction.reply_total = stats.transaction.reply_total;
184 transaction.portal_bind_total = stats.transaction.portal_bind_total;
185 transaction.error_execute_total = stats.transaction.error_execute_total;
186 transaction.execute_timeout = stats.transaction.execute_timeout;
187 transaction.duplicate_prepared_statements = stats.transaction.duplicate_prepared_statements;
188 transaction.total_percentile = stats.transaction.total_percentile.GetStatsForPeriod();
189 transaction.busy_percentile = stats.transaction.busy_percentile.GetStatsForPeriod();
190 transaction.wait_start_percentile = stats.transaction.wait_start_percentile.GetStatsForPeriod();
191 transaction.wait_end_percentile = stats.transaction.wait_end_percentile.GetStatsForPeriod();
192 transaction.return_to_pool_percentile = stats.transaction.return_to_pool_percentile.GetStatsForPeriod();
193
194 topology.roundtrip_time = topology_stats.roundtrip_time.GetStatsForPeriod();
195 topology.replication_lag = topology_stats.replication_lag.GetStatsForPeriod();
196
197 pool_exhaust_errors = stats.pool_exhaust_errors;
198 queue_size_errors = stats.queue_size_errors;
199 connection_percentile = stats.connection_percentile.GetStatsForPeriod();
200 acquire_percentile = stats.acquire_percentile.GetStatsForPeriod();
201
202 return *this;
203 }
204
205 InstanceStatisticsNonatomic& Add(const std::unordered_map<std::string, StatementStatistics>& stats) {
206 for (const auto& [statement_name, statement_stats] : stats) {
207 const auto [it, inserted] = per_statement_stats.try_emplace(statement_name, statement_stats);
208 if (!inserted) {
209 it->second.Add(statement_stats);
210 }
211 }
212
213 return *this;
214 }
215
216 std::unordered_map<std::string, StatementStatistics> per_statement_stats;
217};
218
219/// @brief Instance statistics with description
221 /// host[:port] of an instance
222 std::string host_port;
223 /// Statistics of an instance
225};
226
227/// @brief Cluster statistics storage
229 /// Connlimit mode auto is on
231 /// Master instance statistics
233 /// Sync slave instance statistics
235 /// Slave instances statistics
237 /// Unknown/unreachable instances statistics
239};
240
241// InstanceStatisticsNonatomic values support for utils::statistics::Writer
242void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const InstanceStatisticsNonatomic& stats);
243
244/// @brief InstanceStatsDescriptor values support for utils::statistics::Writer
245void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const InstanceStatsDescriptor& value);
246
247/// @brief ClusterStatistics values support for utils::statistics::Writer
248void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const ClusterStatistics& value);
249
250using ClusterStatisticsPtr = std::unique_ptr<ClusterStatistics>;
251
252} // namespace storages::postgres
253
254USERVER_NAMESPACE_END