Ç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