Çoxdandır blogda məqalə yazmıram, karantində mən də şeytanın qıçını sındırım dedim 🙂
Bu məqalədə hikari-connection-pool`da mövcud olan connection`ların vəziyyəti haqqında real-time məlumatları izləmək üçün manual necə metrics yazmaq olar ona baxacağıq.
Çox güman ki, devops tərəfdə connection metrics ilə bağlı çox gözəl hazır tool`lar var, bu məqalədə sadəcə qısa və yığcam şəkildə necə metrics yazmaq olar onu görəcəyik. Bunu develop etmək niyyəti əslində hazırda üzərində işlədiyim proyekt ilə əlaqədar yarandı. Proyekt connection`lara həssas bir proyektdi, yüngül load test etmək istəyirdim və mənə connection`ların özlərini necə aparmağına tool`suz filan rahat şəkildə, istədiyim vaxt baxa bilmək lazım oldu. Və beləcə bu kod meydana gəldi.
Yəqin fikir vermisiz, loglarda Hikari`inin DEBUG modunu açıq etsəniz müəyyən intervaldan bir aşağıdakı logun çıxdığını görürsünüz:
HikariPool-1 - Pool stats (total=10, active=0, idle=10, waiting=0)
Mənə də bu məlumatlar kifayət edirdi. Qərara aldım ki, bir endpoint yazım, istədiyim vaxt çağırıb bu infolara baxım. Bu məqalədə də bu endpoint`i develop edəcəyik. Getdik 🙂
Deməli metrics ilə işləmək üçün Spring Boot Actuator kitabxanasından istifadə edəcəyik. Spring Boot 2 versiyasından sonra actuator`da 2 endpointdən (/health və /info) başqa digər bütün endpoint`lər default olaraq disabled gəlir. Əgər bütün endpoint`ləri enabled etmək istəsək o zaman application.properties faylına aşağıdakı sətri əlavə etməliyik:
management.endpoints.web.exposure.include=*
Bizə metrics lazım olduğuna görə sadəcə onu əlavə edəcəyik. Metrics`də mövcud olan bütün parametrlərin siyahısına baxmaq üçün aşağıdakı endpoint`i çağırırıq:
http://localhost:8888/actuator/metrics
{
"names": [
"jvm.threads.states",
"hikaricp.connections.pending",
"jvm.gc.memory.promoted",
"hikaricp.connections",
"jvm.memory.max",
"hikaricp.connections.active",
"jvm.memory.used",
"hikaricp.connections.idle",
"hikaricp.connections.creation",
"jvm.gc.max.data.size",
"jvm.memory.committed",
"system.cpu.count",
"logback.events",
"jvm.gc.pause",
"jvm.buffer.memory.used",
"tomcat.sessions.created",
"jvm.threads.daemon",
"hikaricp.connections.max",
"hikaricp.connections.min",
"system.cpu.usage",
"jvm.gc.memory.allocated",
"hikaricp.connections.usage",
"tomcat.sessions.expired",
"jvm.threads.live",
"jvm.threads.peak",
"hikaricp.connections.timeout",
"process.uptime",
"jdbc.connections.active",
"tomcat.sessions.rejected",
"hikaricp.connections.acquire",
"process.cpu.usage",
"jvm.classes.loaded",
"jdbc.connections.max",
"jdbc.connections.min",
"jvm.classes.unloaded",
"tomcat.sessions.active.current",
"tomcat.sessions.alive.max",
"jvm.gc.live.data.size",
"http.server.requests",
"jvm.buffer.count",
"jdbc.connections.idle",
"jvm.buffer.total.capacity",
"tomcat.sessions.active.max",
"process.start.time",
]
}
Bu siyahıdakı hansı parametrlə bağlı məlumata baxmaq istəyiriksə, həmin parametrin adını yuxarıda qeyd etdiyimiz endpointdən sonra / qoyaraq əlavə edib çağırırıq. Məsələn HikariCP`də mövcud olan bütün connection`ların sayına baxmaq üçün aşağıdakı endpoint`i çağırırıq:
http://localhost:8888/actuator/metrics/hikaricp.connections
{
"name":"hikaricp.connections",
"description":"Total connections",
"baseUnit":null,
"measurements":[
{
"statistic":"VALUE",
"value":35
}
],
"availableTags":[
{
"tag":"pool",
"values":[
"mysql-pool",
"oracle-pool",
"h2-pool"
]
}
]
}
Qayıdan response`dan görürük ki, bizim 3 connection pool`umuz və ümumilikdə 35 mövcud connection`umuz var. Amma hansı connection pool`a nə qədər connection aiddir onu ayrıca görə bilmirik.
Yazdıqlarımızı yekunlaşdırsaq deməli hazırkı vəziyyətdə bizim 2 çətinliyimiz var:
- Hansı parametrlə bağlı məlumatı görmək istəyiriksə, onun üçün ayrıca endpoint çağırmalıyıq; əgər 4 parametr üzrə məlumat lazımdısa, 4 fərqli endpoint çağırmalıyıq;
- Tutaq ki, bir neçə fərqli endpoint çağırmağa razı olduq, amma bizim əldə etdiyimiz məlumat yenə də ümumi məlumat olur. Əgər bizim bir neçə connection-pool`umuz varsa, hər pool üzrə məlumatları ayrıca görə bilməyəcəyik, necə ki, yuxarıdakı response`da göstərilən 35 connection 3 pool`a aiddir.
Buna görə də məlumatları istədiyimiz formada əldə etmək üçün manual metrics yazacağıq və bunun üçün actuator kitabxanasının MetricsEndpoint klasını istifadə edəcəyik. Proyektimizin strukturu aşağıdakı kimi olacaq:
MetricsController.java
@RestController
@RequestMapping("/metrics")
public class MetricsController {
private final MetricsService metricsService;
public MetricsController(MetricsService metricsService) {
this.metricsService = metricsService;
}
@GetMapping("/hikari/connections")
public Map<String, Map> getHikariConnectionsInfo() {
return metricsService.hikariConnectionPoolMetrics();
}
}
MetricsService.java
@Service
public class MetricsService {
private final MetricsEndpoint metricsEndpoint;
private final Map<String, String> hikariFields;
public MetricsService(MetricsEndpoint metricsEndpoint) {
this.metricsEndpoint = metricsEndpoint;
this.hikariFields = MetricsUtil.hikariMetricFields();
}
public Map<String, Map> hikariConnectionPoolMetrics() {
MetricResponse hikariPoolInfo = metricsEndpoint.metric(hikariFields.get("total"), null);
AvailableTag availableTag = hikariPoolInfo.getAvailableTags().get(0);
String tagName = availableTag.getTag();
Set<String> tagValues = availableTag.getValues();
Map<String, Map> connections = new HashMap<>();
for (String tagValue : tagValues) {
Map<String, Object> params = new LinkedHashMap<>();
hikariFields.forEach((k, v) -> {
MetricResponse metricResponse = metricsEndpoint.metric(v, Arrays.asList(tagName + ":" + tagValue));
Integer val = metricResponse.getMeasurements().get(0).getValue().intValue();
params.put(k, val);
});
connections.put(tagValue, params);
}
return connections;
}
}
MetricsUtil.java
public class MetricsUtil {
private MetricsUtil() {
}
public static Map<String, String> hikariMetricFields() {
Map<String, String> hikariFields = new LinkedHashMap<>();
hikariFields.put("total", "hikaricp.connections");
hikariFields.put("active", "hikaricp.connections.active");
hikariFields.put("idle", "hikaricp.connections.idle");
hikariFields.put("waiting", "hikaricp.connections.pending");
return hikariFields;
}
}
DatabaseConfig.java
@Configuration
public class DatabaseConfig {
@Primary
@Bean("oracleDataSource")
@ConfigurationProperties(prefix = "spring.datasource.oracle-db")
public DataSource oracleDataSource() {
return DataSourceBuilder.create().build();
}
@Bean("mySqlDataSource")
@ConfigurationProperties(prefix = "spring.datasource.mysql-db")
public DataSource mySqlDataSource() {
return DataSourceBuilder.create().build();
}
@Bean("h2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.h2-db")
public DataSource h2DataSource() {
return DataSourceBuilder.create().build();
}
}
application.yml
server:
port: 8888
spring:
application:
name: hikari-connection-pool-metrics
datasource:
oracle-db:
driver-class-name: oracle.jdbc.OracleDriver
jdbc-url: jdbc:oracle:thin:@localhost:1521:xe
username: test
password: test
pool-name: oracle-pool
maximum-pool-size: 20
data-source-properties:
oracle.jdbc.implicitStatementCacheSize: 100
mysql-db:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://localhost:3306/test
username: root
password: root
pool-name: mysql-pool
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
h2-db:
driver-class-name: org.h2.Driver
jdbc-url: jdbc:h2:mem:testdb
username: sa
password:
pool-name: h2-pool
maximum-pool-size: 5
management:
endpoints:
web:
exposure:
include: info, health, metrics
logging:
level:
com.zaxxer.hikari: DEBUG
İndi aşağıdakı endpoint`i çağırmaqla nəticəni artıq öz istədiyimiz şəkildə görə bilərik:
http://localhost:8888/metrics/hikari/connections
{
"oracle-pool":{
"total":20,
"active":0,
"idle":20,
"waiting":0
},
"h2-pool":{
"total":5,
"active":0,
"idle":5,
"waiting":0
},
"mysql-pool":{
"total":10,
"active":0,
"idle":10,
"waiting":0
}
}
Kodları yəqin ki, izah etməyə ehtiyac yoxdur, MetricsEndpoint klasının metric() metodunu araşdırmaq kifayət edir. Parametrlərin ümumi siyahısına baxmaq üçün MetricsEndpoint klasının listNames() metodundan istifadə edə bilərsiz. Mənə hikari ilə bağlı 4 parametr lazım olduğundan sadəcə onları qruplaşdırmışam. Amma siz istəsəniz bunu özünüzə lazım olan digər şəkillərdə təkmilləşdirə bilərsiz.
Kodlara tam şəkildə Githubda aşağıdakı repo üzərindən baxa bilərsiz:
https://github.com/mmushfiq/hikari-connection-pool-metrics.git
Bu məqaləmiz də bu qədər, ümid edirəm faydalı olmuşdur. Növbəti məqalələrdə görüşənədək. Necə deyərlər evdə qalın, sağlam qalın, amma arada imkan olduqca yazın pozun))


Faydalı yazıdı. Təşəkkürlər!
Buyurun