Zipkin Tracing: Microservices වල ගැටළු විසඳමු | Distributed Tracing SC Guide

මයික්රෝ සර්විස් ලෝකේ අතරමං නොවී Traces හොයමු: Zipkin SC Guide
අප්පේ! ඔයාලත් Microservices Architectures එක්ක වැඩ කරනවා නම්, මේ ප්රශ්නයට මුහුණ දීලා ඇති. පොඩි බග් එකක් හොයන්න ගිහිල්ලා, request එකක් එක service එකකින් තව service එකකට යනකොට කොතනද වැරදුනේ, නැත්නම් වැඩි වෙලාවක් ගත්තේ කොතනද කියලා හොයාගන්න බැරුව අත අරින්න හිතෙන තරමටම එපා වෙලා ඇති. ඒක ලොකු ව්යාපෘතියක් නම්, මේක ඇත්තටම කට්ටක් නේද?
මයික්රෝ සර්විස් එකක බග් එකක් හොයන එක රතු පලසක් උඩ ඉඳගෙන ගිනිකෙළි බලනවා වගේ නෙවෙයි නේද? ඒක හරියට අඳුරු කාමරයක කළු බළලෙක් හොයනවා වගේ වැඩක්. විශේෂයෙන්ම, services ගොඩක් අතරේ request එකක් ගමන් කරනකොට, ඒක හරියට නූල් පොටක් නැති පොඩි ගැටයක් හොයනවා වගේ. මේකට තමයි Distributed Tracing කියන කන්සෙප්ට් එක අපිට උදව් කරන්නේ. අද අපි බලමු කොහොමද මේ Zipkin කියන සුපිරි ටූල් එක පාවිච්චි කරලා අපේ Microservices වල Request flows හරියටම ට්රේස් කරගන්නේ කියලා.
මේ ලිපියෙන් අපි කතා කරන්නේ:
- Distributed Tracing කියන්නේ මොකක්ද? (සරලව)
- ඇයි Zipkin මේ වැඩේට නියම solution එක වෙන්නේ?
- Zipkin Setup කරන හැටි (Docker වලින් ලේසියෙන්ම)
- අපේ Spring Boot Microservices වලට Zipkin එකතු කරන හැටි (Practical example එකක් එක්ක!)
- Zipkin UI එකෙන් Traces බලලා bottlenecks හොයන හැටි.
ඉතින්, අපි පටන් ගමු! මේක ඔයාලට ඔයාලගේ Microservices වල ගැටළු ඉක්මනින් විසඳගන්න ලොකු උදව්වක් වෙයි කියලා මට විශ්වාසයි.
Distributed Tracing කියන්නේ මොකක්ද? - Microservices වල X-Ray එක
සරලවම කිව්වොත්, Distributed Tracing කියන්නේ software system එකක් හරහා යන තනි request එකක complete journey එක track කරන ක්රමයක්. හිතන්නකෝ ඔයාලා Online store එකකින් order එකක් දැම්මා කියලා. ඒ order එක process වෙන්න customer service එක, order service එක, inventory service එක, payment service එක, notification service එක වගේ services ගොඩක් හරහා යන්න පුළුවන්. මේ හැම service එකක්ම වෙන වෙනම applications විදියට දුවන නිසා, කොහේ හරි ගැටළුවක් ආවොත්, ඒක හොයන එක මාරම අමාරුයි.
සාමාන්යයෙන් අපි debugging වලට Logs පාවිච්චි කරනවනේ. හැබැයි, එක request එකක logs services ගොඩක විසිරිලා තියෙනකොට, ඒ හැම log එකක්ම එකට ගලපලා request එකේ flow එක තේරුම් ගන්න එක හරිම සංකීර්ණයි. මෙතනට තමයි Distributed Tracing එන්නේ.
Distributed Tracing වලදී, හැම request එකකටම unique ID එකක් (Trace ID) දෙනවා. ඊට පස්සේ, ඒ request එක එක service එකක ඉඳන් තව service එකකට යන හැම පියවරකටම තව unique ID එකක් (Span ID) දෙනවා. මේ Span ID වලට parent-child relationship එකක් තියෙනවා. මේ විදියට, එක request එකක් services කීපයක් හරහා යනකොට හැම step එකක්ම (span එකක්) record වෙනවා. මේ හැම span එකක්ම එකම Trace ID එකකට අයිති වෙනවා.
මේ වගේ Traces එකතුවක් බලනකොට අපිට පුළුවන්:
- Request එකක් services හරහා ගිය complete path එක බලන්න.
- කොයි service එකේද වැඩිම වෙලාවක් ගත්තේ කියලා හඳුනාගන්න (bottlenecks).
- Request එකක් fail වුණා නම්, ඒක fail වුණේ කොයි service එකේද කියලා හරියටම දැනගන්න.
මේක හරියට පාර්සලයක් තැපැල් කන්තෝරු ගොඩක් හරහා යනකොට, ඒක කොහේ ඉඳන් කොහේටද ගියේ, කොයි වෙලාවෙද, කොහේදීද පමා වුණේ, කියලා track කරනවා වගේ වැඩක්. නියමයි නේද?
ඇයි Zipkin? - Open Source සුපිරි තේරීම
Distributed Tracing වලට ටූල්ස් ගොඩක් තියෙනවා. හැබැයි, ඒ අතරින් Zipkin කියන්නේ ගොඩක් ජනප්රිය, open-source, powerful solution එකක්. Twitter සමාගම විසින් මුලින්ම develop කරපු මේ Zipkin, දැන් Cloud Native Computing Foundation (CNCF) එකේ project එකක් විදියට දියුණු වෙනවා.
Zipkin පාවිච්චි කරන්න තියෙන වාසි:
- සරල Setup එක: Docker image එකක් විදියට පහසුවෙන් run කරන්න පුළුවන්.
- හොඳ UI එකක්: Traces බලන්න, search කරන්න, analyze කරන්න ඉතාම පැහැදිලි user interface එකක් තියෙනවා.
- ප්රබල Community එකක්: ඕනෑම ප්රශ්නයකට උදව් හොයාගන්න පුළුවන් active community එකක් තියෙනවා.
- විවිධ Languages/Frameworks වලට සහය: Java (Spring Boot), Node.js, Python, Go වගේ ඕනෑම programing language එකක framework එකක් එක්ක පහසුවෙන් integrate කරන්න පුළුවන්.
- OpenTracing/OpenTelemetry support: මේ වගේ industry standards වලට සහය දක්වන නිසා, Future-proof solution එකක්.
Zipkin වල core component කිහිපයක් තියෙනවා:
- Collectors: Client applications වලින් එවන Trace data receive කරලා validate කරනවා.
- Storage: Received Traces දත්ත ගබඩා කරනවා. (Cassandra, Elasticsearch, MySQL වගේ)
- Query Service: Storage එකෙන් Traces search කරලා UI එකට අවශ්ය විදියට සකසනවා.
- Web UI: Traces බලන්න, filter කරන්න, dependency graphs බලන්න පුළුවන් graphical interface එක.
මේ හැම දෙයක්ම එකට එකතු වෙලා තමයි Zipkin Distributed Tracing solution එක හැදෙන්නේ.
Zipkin Setup කරමු (Docker වලින් ලේසියෙන්ම)
Zipkin setup කරන එක හරිම ලේසියි. අපිට පුළුවන් Docker වලින් එක command එකකින් Zipkin server එක run කරන්න. මේක development environment එකකට නම් නියමයි.
පියවර 1: Docker Install කරගන්න
ඔයාලගේ machine එකේ Docker install කරලා නැත්නම්, මුලින්ම ඒක කරගන්න. (Windows, macOS, Linux සඳහා Docker Desktop install කරගන්න).
පියවර 2: Zipkin Server එක run කරන්න
Command Prompt (CMD) හෝ Terminal එක open කරලා මේ command එක type කරන්න:
docker run -d -p 9411:9411 openzipkin/zipkin
මේ command එකෙන් වෙන්නේ:
docker run
: Docker container එකක් run කරන්න.-d
: Container එක background එකේ (detached mode) run කරන්න.-p 9411:9411
: Local machine එකේ Port 9411 එක Container එකේ Port 9411 එකට expose කරන්න. Zipkin UI එකට access වෙන්නේ මේ Port එකෙන්.openzipkin/zipkin
: Zipkin server එකේ Docker image එකේ නම.
නියමයි! දැන් ඔයාලගේ Zipkin server එක run වෙනවා. දැන් ඔයාලට පුළුවන් Browser එකේ http://localhost:9411 කියන address එකට ගිහිල්ලා Zipkin UI එක බලන්න.
production environment එකකදී නම්, Zipkin වලට persistent storage (Elasticsearch, Cassandra, MySQL වගේ) එකක් configure කරන්න වෙනවා. නැත්නම්, container එක restart කරද්දී Traces නැති වෙන්න පුළුවන්.
Microservices වලට Zipkin එකතු කරමු (Spring Boot එක්ක)
දැන් අපි බලමු කොහොමද අපේ Spring Boot microservices වලට Zipkin එකතු කරන්නේ කියලා. Spring Boot applications වලට නම් මේක Spring Cloud Sleuth නිසා හරිම ලේසියි.
Spring Cloud Sleuth කියන්නේ මොකක්ද?
Spring Cloud Sleuth කියන්නේ Spring ecosystem එක ඇතුළේ Distributed Tracing කරන්න උදව් වෙන project එකක්. මේක අපේ code එකට කිසිම ලොකු වෙනසක් නොකරම traces generate කරන්න පුළුවන් වෙන විදියට නිර්මාණය කරලා තියෙනවා. Sleuth එක කරන්නේ request එකක් එනකොට අලුත් Trace ID එකක් generate කරන එක, existing Trace ID එකක් තියෙනවා නම් ඒක continue කරන එක, අලුත් Span ID එකක් generate කරන එක සහ මේ IDs ටික outgoing requests වලට (HTTP headers හරහා) inject කරන එක.
උදාහරණයක්: Service A සිට Service B දක්වා Tracing
අපි හිතමු අපිට Spring Boot services දෙකක් තියෙනවා කියලා: service-a
සහ service-b
. service-a
එකෙන් service-b
එකට call එකක් යනකොට අපි මේ request එක trace කරන්නේ කොහොමද කියලා බලමු.
පියවර 1: Dependencies එකතු කරන්න
ඔයාලගේ pom.xml
file එකට (Spring Boot applications වල) මේ dependencies ටික එකතු කරන්න:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.3</version> <!-- Replace with your Spring Cloud version -->
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
spring-cloud-starter-sleuth
එකෙන් tracing functionality එක add කරනවා, spring-cloud-sleuth-zipkin
එකෙන් generated traces Zipkin server එකට send කරනවා.
පියවර 2: Configuration එකතු කරන්න
දැන් ඔයාලගේ application.properties
(හෝ application.yml
) file එකට මේ configurations එකතු කරන්න:
service-a (application.properties):
spring.application.name=service-a
server.port=8080
spring.zipkin.base-url=http://localhost:9411/
spring.sleuth.sampler.probability=1.0
service-b (application.properties):
spring.application.name=service-b
server.port=8081
spring.zipkin.base-url=http://localhost:9411/
spring.sleuth.sampler.probability=1.0
මෙහිදී:
spring.application.name
: මේක තමයි Zipkin UI එකේ ඔයාලගේ service එකට පෙන්වන නම.spring.zipkin.base-url
: Zipkin server එක run වෙන address එක.spring.sleuth.sampler.probability=1.0
: මේකෙන් කියන්නේ හැම request එකක්ම trace කරන්න කියලා. Production environment එකකදී නම් මේක පොඩ්ඩක් අඩු කරනවා (ex: 0.1) services ගොඩක් තියෙනකොට Zipkin server එකට එන data load එක අඩු කරන්න.
පියවර 3: Services Develop කරන්න
Service A Controller (ServiceAController.java
):
package com.example.servicea;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class ServiceAController {
private static final Logger logger = LoggerFactory.getLogger(ServiceAController.class);
@Autowired
private RestTemplate restTemplate;
@GetMapping("/call-service-b")
public String callServiceB() {
logger.info("Calling Service B from Service A");
String response = restTemplate.getForObject("http://localhost:8081/hello", String.class);
logger.info("Response from Service B: {}", response);
return "Response from Service B: " + response;
}
// Remember to configure RestTemplate bean for Sleuth to auto-instrument
// For example, in your main application class:
/*
@Bean
@LoadBalanced // Use if you have a load balancer like Eureka/Ribbon
public RestTemplate restTemplate() {
return new RestTemplate();
}
*/
}
Service B Controller (ServiceBController.java
):
package com.example.serviceb;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServiceBController {
private static final Logger logger = LoggerFactory.getLogger(ServiceBController.class);
@GetMapping("/hello")
public String hello() throws InterruptedException {
logger.info("Hello from Service B");
Thread.sleep(100); // Simulate some processing time
return "Hello from Service B!";
}
}
වැදගත් සටහන: RestTemplate
bean එක expose කරනකොට, Spring Cloud Sleuth ඒක auto-instrument කරනවා. ඒ කියන්නේ, RestTemplate
එකෙන් යන හැම outgoing HTTP request එකකටම tracing headers (B3 headers - x-b3-traceid
, x-b3-spanid
වගේ) automaticly add කරනවා. මේ headers තමයි Tracing information එක services අතරේ propagate කරන්නේ.
පියවර 4: Services run කරන්න
දැන් ඔයාලට පුළුවන් මේ services දෙකම වෙන වෙනම run කරන්න (IntelliJ IDEA, Eclipse වගේ IDE එකකින් හෝ Maven/Gradle command line එකෙන්).
මුලින් service-b
run කරන්න, ඊට පස්සේ service-a
run කරන්න.
පියවර 5: Request එකක් යවන්න
දැන් Browser එකේ හෝ Postman/cURL එකෙන් http://localhost:8080/call-service-b කියන address එකට request එකක් යවන්න. මේකෙන් service-a
එක service-b
එකට call එකක් දෙනවා.
Zipkin UI එකෙන් Traces බලමු - ගැටළු විසඳන හැටි
දැන් අපි බලමු කොහොමද මේ Zipkin UI එක පාවිච්චි කරලා, අපේ requests වල traces බලලා, ගැටළු හොයාගන්නේ කියලා.
ඔයාලගේ browser එකේ http://localhost:9411 වලට යන්න.
Zipkin UI Features:
- Search Page: මේක තමයි ඔයාලට පේන default page එක. මෙතනින් පුළුවන් trace එකක් search කරන්න.
- Service Name: ඔයාලට බලන්න ඕනේ service එක තෝරන්න. (අපේ උදාහරණයේ නම්
service-a
හෝservice-b
) - Lookback: කොච්චර අතීතයකටද traces හොයන්නේ කියලා (පැය, දවස්).
- Min/Max Duration: Trace එකේ අඩුම වැඩිම duration එක දාන්න. (දිගු වෙලාවක් ගත්ත requests හොයන්න)
- Annotation Query: Custom tags හෝ log messages වලින් search කරන්න.
- Service Name: ඔයාලට බලන්න ඕනේ service එක තෝරන්න. (අපේ උදාහරණයේ නම්
- Trace Details: Search results වලින් trace එකක් click කරාම, ඒ trace එකේ සම්පූර්ණ විස්තරය පෙන්වනවා.
- Timeline View: Services අතරේ request එක ගිය හැටි, ඒ හැම step එකකටම (span එකකටම) ගිය වෙලාව graphicially පෙන්වනවා. මේකෙන් bottlenecks හරිම ලේසියෙන් හොයාගන්න පුළුවන්. (කොයි service එකේද වැඩියෙන් වෙලා ගියේ කියලා බලන්න.)
- Span Details: හැම span එකක්ම expand කරලා ඒකට අයිති details (method name, URL, HTTP status, custom tags, duration) බලන්න පුළුවන්. Errors එනකොට මෙතන error tags තියෙනවා.
- Dependency Graph: මේක මාරම වැදගත් feature එකක්. Zipkin විසින් services අතර තියෙන dependencies automatically generate කරනවා. ඒ කියන්නේ, කොයි service එකද කොයි service එකටද call කරන්නේ කියලා මේ graph එකෙන් පෙන්වනවා. මේකෙන් system එකේ architecture එක තේරුම් ගන්න සහ unexpected dependencies හොයාගන්න උදව් වෙනවා.
අපේ උදාහරණයේදී, ඔයාලා service-a
තෝරලා search කරාම, request එකේ Trace එකක් පෙනෙයි. ඒක click කරාම, service-a
එකෙන් service-b
එකට call කරපු හැටි, ඒ හැම call එකකටම ගිය වෙලාව, වගේ හැම දෙයක්ම පැහැදිලිව Timeline view එකේ පෙනෙයි. service-b
එකට අපි Thread.sleep(100)
එකක් දැම්මා මතකද? ඒ delay එක trace එකේ කොහොමද පෙනෙන්නේ කියලා බලන්න. ඒකෙන් හරිම ලේසියෙන් bottlenecks හොයාගන්න පුළුවන්.
ලොග්ස් ගොඩක් පීරලා, පොඩි වැරදීමක් හොයනවාට වඩා මේක කොච්චර ලේසිද?
අවසන් වචන
ඉතින් යාලුවනේ, Distributed Tracing කියන්නේ Microservices architecture එකේදී නැතිවම බැරි දෙයක්. විශේෂයෙන්ම System එකක් ලොකු වෙනකොට, request flow එකේ ගැටළු හොයාගන්න එක මාරම අමාරු වෙනවා. Zipkin වගේ ටූල් එකක් පාවිච්චි කරන එකෙන් ඒ වැඩේ හරිම පහසු වෙනවා.
අපි මේ ලිපියෙන් Zipkin කියන්නේ මොකක්ද, ඒක setup කරන්නේ කොහොමද, අපේ Spring Boot services වලට integrate කරන්නේ කොහොමද, වගේම Zipkin UI එකෙන් Traces analyze කරන්නේ කොහොමද කියලා කතා කළා.
මේක පොඩි දෙයක් වගේ පෙනුනත්, ලොකු Microservices system එකකදී මේක කොච්චර වටිනවද කියලා දැනගන්න නම් ට්රයි කරලාම බලන්න ඕනේ. ඒ වගේම, මේක ඔයාලට ඔයාලගේ applications වල performance bottlenecks හඳුනාගෙන, ඒවා improve කරගන්නත් ලොකු උදව්වක් වෙයි.
ඔයාලගේ අත්දැකීම්, ප්රශ්න පහළ කමෙන්ට් සෙක්ෂන් එකේ දාලා යන්න අමතක කරන්න එපා. අපි ඊළඟ පෝස්ට් එකෙන් තවත් වැදගත් topic එකක් එක්ක හම්බවෙමු! සුභ දවසක්!