์ด ๋ฌธ์๋ ์ ํ๋ฆฌ์ผ์ด์
์ LogPilot ํด๋ผ์ด์ธํธ๋ฅผ ์ฐ๋ํ๊ณ ์ด๋ฒคํธ/๋ฉ์์ง ์คํธ๋ฆฌ๋ฐ์ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช
ํฉ๋๋ค. Producer(logpilot-demo-produce)์ Consumer(logpilot-demo-consume) ๋ฐ๋ชจ ๋ชจ๋์ ์ฐธ์กฐํ์ฌ '๊ฒฝ๋ ์นดํ์นด' ๋ฉ์ปค๋์ฆ์ ์๋ดํฉ๋๋ค.
โ ๏ธ ํ์ ์กฐ๊ฑด: ํด๋ผ์ด์ธํธ๋ฅผ ์คํํ๊ธฐ ์ ์ LogPilot Server๊ฐ ์คํ ์ค์ด์ด์ผ ํฉ๋๋ค.์ต์ A: Gradle ์คํ
./gradlew :logpilot-server:bootRun์ต์ B: Docker ์คํ
docker build -t logpilot-server . docker run -p 8080:8080 -p 50051:50051 logpilot-server์ต์ C: Kubernetes ์คํ
# ์์ธ ๊ฐ์ด๋๋ K8S.ko.md ์ฐธ์กฐ kubectl apply -f k8s/๊ธฐ๋ณธ ์๋ฒ ์ฃผ์:
localhost:50051(gRPC) /http://localhost:8080(REST)
LogPilot์ ๋ ๊ฐ์ง ํต์ ํ๋กํ ์ฝ์ ์ง์ํฉ๋๋ค. ์๊ตฌ ์ฌํญ์ ๊ฐ์ฅ ์ ํฉํ ๋ฐฉ์์ ์ ํํ์ธ์.
| ํน์ง | REST (HTTP/1.1) | gRPC (HTTP/2 + Protobuf) |
|---|---|---|
| ์ฑ๋ฅ | ๋ณดํต (ํ ์คํธ ๊ธฐ๋ฐ JSON) | ๋์ (๋ฐ์ด๋๋ฆฌ Protobuf) |
| ์ฒ๋ฆฌ๋ (Throughput) | ํ์ค | ๋์ (Multiplexing ์ง์) |
| ํ์ ์์ ์ฑ | ๋์จํจ (JSON) | ์๊ฒฉํจ (IDL ์ ์) |
| ์ค์ ๋์ด๋ | ์ฌ์ (ํ์ค HTTP) | HTTP/2 ์ง์ ํ์ |
| ๊ถ์ฅ ๋์ | ๋จ์ ๋ก๊น , ๋ฐฉํ๋ฒฝ ์ ์ฝ ํ๊ฒฝ | ๋์ฉ๋ ๋ก๊ทธ ์์ฑ, ๋ก๊ทธ ๋ถ์/์๋น |
- gRPC ์ฌ์ฉ: ํ๋ก๋์ ํ๊ฒฝ, ๊ณ ์ฑ๋ฅ ์ด๋ฒคํธ ์คํธ๋ฆผ, ๋๋ ์ค์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํด์ผ ํ๋ Consumer ์ ํ๋ฆฌ์ผ์ด์ .
- REST ์ฌ์ฉ: ๊ฐ๋จํ ํ ์คํธ, ๊ฒฝ๋ ์์ฐ์(Producer), ๋๋ gRPC ํฌํธ ์ฌ์ฉ์ด ์ ํ๋ ํ๊ฒฝ.
Producer๋ ์ด๋ฒคํธ๋ ๋ฉ์์ง๋ฅผ ์์ฑํ์ฌ ์๋ฒ๋ก ์ ์กํฉ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์
๋ก๊ทธ๋ฅผ ์คํธ๋ฆผ์ผ๋ก ๋ณด๋ด๋ ค๋ฉด Logback Appender๋ฅผ, ์ปค์คํ
์ด๋ฒคํธ๋ฅผ ๋ณด๋ด๋ ค๋ฉด LogPilotClient๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
Producer๋ ๋ก๊ทธ๋ฅผ ์์ฑํ์ฌ ์๋ฒ๋ก ์ ์กํฉ๋๋ค. Logback Appender๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ๊ฐํธํฉ๋๋ค.
์ด ๋ชจ๋์ ํธ๋ํฝ์ด ๋ง์ ์ฑ์ฉ ์ฌ์ดํธ๋ฅผ ์๋ฎฌ๋ ์ด์
ํฉ๋๋ค. LogPilotAppender๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๊ทธ๋ฅผ ๋ฐฐ์น(Batch)๋ก ๋ฌถ์ด ๋น๋๊ธฐ ์ ์กํฉ๋๋ค.
์ค์ ์์ (logback-spring.xml):
<appender name="LOGPILOT" class="com.logpilot.logback.LogPilotAppender">
<!-- Appender๋ ๊ธฐ๋ณธ์ ์ผ๋ก REST๋ฅผ ์ฌ์ฉํ์ง๋ง ์ค์ ๊ฐ๋ฅ -->
<serverUrl>http://localhost:8080</serverUrl>
<serviceName>my-service</serviceName>
<apiKey>your-api-key</apiKey>
<!-- ์ฑ๋ฅ ์ต์ ํ (๋ฐฐ์น ์ ์ก) -->
<enableBatching>true</enableBatching>
<batchSize>100</batchSize>
<flushIntervalMillis>5000</flushIntervalMillis>
</appender>Tip: ์ ์ค์ ์ฒ๋ผ
batching์ ํ์ฑํํ๋ฉด ๋ฉ์ธ ์ค๋ ๋ ์ฐจ๋จ์ ๋ฐฉ์งํ๊ณ ๋คํธ์ํฌ ์ค๋ฒํค๋๋ฅผ ํ๊ธฐ์ ์ผ๋ก ์ค์ผ ์ ์์ต๋๋ค.
Consumer๋ ์๋ฒ์์ ๋ฉ์์ง๋ฅผ ๊ฐ์ ธ์ ์ฒ๋ฆฌํ๊ฑฐ๋ ์ค์๊ฐ ์ก์ ์ ์ํํฉ๋๋ค. LogPilot์ Kafka ์คํ์ผ์ **์คํ์ ๊ด๋ฆฌ(Offset Management)**๋ฅผ ์ ๊ณตํ์ฌ ๊ฐ ๋ฉ์์ง๊ฐ ์์ ์ ์ผ๋ก ํ ๋ฒ์ฉ ์ฒ๋ฆฌ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
์ด ๋ชจ๋์ ๋งค์ด ๋ก๊ทธ๋ฅผ ํด๋งํ์ฌ ์ค์๊ฐ ์ฑ์ฉ ํต๊ณ๋ฅผ ๊ณ์ฐํฉ๋๋ค. ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์กฐํ๋ฅผ ์ํด gRPC๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ฝ๋ ์์ (AnalyticsService.java):
// ํด๋ผ์ด์ธํธ ์ด๊ธฐํ (gRPC ๋ชจ๋)
LogPilotClient client = LogPilotClient.builder()
.serverUrl("localhost:50051")
.clientType(LogPilotClient.ClientType.GRPC)
.build();
// ์๋น์ ID๋ฅผ ์ฌ์ฉํ ์ด๋ฒคํธ ์กฐํ (์์ ์ ์ธ ์คํ์
์ถ์ )
// getLogs(channel, consumerId, limit)
List<LogEntry> events = client.getLogs("orders", "inventory-service", 100);
for (LogEntry event : events) {
process(event);
// autoCommit=false๊ฐ ์๋ ํ ์คํ์
์ ์๋์ผ๋ก ์ปค๋ฐ๋ฉ๋๋ค.
}์ gRPC์ธ๊ฐ?: ๋ฐ๋ชจ์ฒ๋ผ 1์ด๋ง๋ค ๋น๋ฒํ๊ฒ ๋ก๊ทธ๋ฅผ ํด๋งํด์ผ ํ๋ ๊ฒฝ์ฐ, gRPC์ ์ง์ ์ฐ๊ฒฐ(Persistent Connection)๊ณผ ๋ฐ์ด๋๋ฆฌ ํฌ๋งท์ REST ๋ฐฉ์์ ๋นํด CPU ์ฌ์ฉ๋๊ณผ ์ง์ฐ ์๊ฐ(Latency)์ ํฌ๊ฒ ๊ฐ์์ํต๋๋ค.
์์ ํจํด๋ค์ด ์ค์ ๋ก ๋์ํ๋ ๋ชจ์ต์ ํ์ธํด๋ณด์ธ์:
- ์๋ฒ ์์:
./gradlew :logpilot-server:bootRun - Producer ์์:
./gradlew :logpilot-demo-produce:bootRun(Port 8082)- ํธ๋ํฝ ์์ฑ (STEADY ๋ชจ๋):
curl -X POST "http://localhost:8082/simulation/start?mode=STEADY" - ํธ๋ํฝ ์์ฑ ์ค์ง:
curl -X POST "http://localhost:8082/simulation/stop"
- ํธ๋ํฝ ์์ฑ (STEADY ๋ชจ๋):
- Consumer ์์:
./gradlew :logpilot-demo-consume:bootRun(Port 8083)- ํต๊ณ ํ์ธ:
curl http://localhost:8083/analytics/stats
- ํต๊ณ ํ์ธ: