0%

使用 Deno 2.2 原生 OpenTelemetry 支持构建可观测的微服务

Deno 2.2 版本引入了原生的 OpenTelemetry 支持,使得在 Deno 应用中集成分布式追踪变得异常简单。本文将介绍如何使用 Deno 2.2 和 Hono 框架构建一个简单的微服务系统,并通过 OpenTelemetry 实现服务的可观测性。

项目概述

我们构建了一个包含两个服务的简单系统:

  1. API 网关服务 (gateway.ts):负责接收客户端请求,并将其路由到相应的服务。
  2. 天气服务 (weather.ts):提供天气信息查询功能。

此外,我们还实现了一个中间件 (TraceRoute.ts) 和一个模拟的第三方 API 调用 (thirdApi.ts),用于演示如何在服务中进行追踪。

代码实现

API 网关服务 (gateway.ts)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { Hono } from "@hono/hono";
import { TraceRoute } from "./TraceRoute.ts";

const app = new Hono().basePath("/api");

app.use(TraceRoute());

app
.get("/", (c) => {
return c.text("Hello from the Trees!");
})
.get("/weather/batch-get", async (c) => {
const cities = c.req.queries("city") as string[];
const result = (
await Promise.all(
cities.map(async (city: string) => {
const resp = await fetch(`http://localhost:8001/weather/${city}`);
return await resp.text();
})
)
).join("\n");
return c.text(result);
})
.get("/weather/:city", (c) => {
return fetch(`http://localhost:8001/weather/${c.req.param("city")}`);
});

Deno.serve(app.fetch);

天气服务 (weather.ts)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Hono } from "@hono/hono";
import { TraceRoute } from "./TraceRoute.ts";
import { getWeather } from "./thirdApi.ts";

const app = new Hono();

app.use(TraceRoute());

app.get("/weather/:city", (c) => {
const city = c.req.param("city");
return c.text(getWeather(city));
});

Deno.serve({ port: 8001 }, app.fetch);

追踪中间件 (TraceRoute.ts)

1
2
3
4
5
6
7
8
9
10
11
import type { MiddlewareHandler } from "@hono/hono/types";
import { trace } from "@opentelemetry/api";

export const TraceRoute = (): MiddlewareHandler => {
return async function (c, next) {
const span = trace.getActiveSpan();
span?.setAttribute("http.route", c.req.path);
span?.updateName(`${c.req.method} ${c.req.path}`);
await next();
};
};

第三方 API 调用 (thirdApi.ts)

1
2
3
4
5
6
7
8
9
10
11
12
import { trace } from "@opentelemetry/api";

export function getWeather(city: string) {
return trace
.getTracer("weather-api")
.startActiveSpan("getWeatherFunction", (span) => {
span.setAttribute("city", city);
span.end();
console.log(`Fetch weather from ${city}`);
return `${city} is sunny, 20℃.`;
});
}

运行服务

要运行这两个服务,可以使用以下命令:

1
OTEL_SERVICE_NAME=gateway OTEL_DENO=true OTEL_DENO_CONSOLE=capture deno run --unstable-otel -A --watch gateway.ts
1
OTEL_SERVICE_NAME=weather-api OTEL_DENO=true OTEL_DENO_CONSOLE=capture deno run --unstable-otel -A --watch weather.ts

然后,可以使用 curl 命令测试服务:

1
curl http://localhost:8000/api/weather/batch-get?city=beijing&city=shanghai

可视化追踪数据

为了查看追踪和指标信息,我们在本地启动了一套 LGTM 服务:

1
2
3
4
5
6
docker run --name lgtm -p 3000:3000 -p 4317:4317 -p 4318:4318 --rm -ti \
-v "$PWD"/lgtm/grafana:/data/grafana \
-v "$PWD"/lgtm/prometheus:/data/prometheus \
-v "$PWD"/lgtm/loki:/data/loki \
-e GF_PATHS_DATA=/data/grafana \
docker.io/grafana/otel-lgtm:0.8.1

通过访问 http://localhost:3000,可以在 Grafana 中查看服务的追踪和指标信息。

总结

Deno 2.2 的原生 OpenTelemetry 支持使得在 Deno 应用中实现可观测性变得非常简单。通过本文的示例,我们展示了如何在微服务系统中集成 OpenTelemetry,并通过 LGTM 服务可视化追踪数据。希望这篇文章能帮助你更好地理解和应用 Deno 和 OpenTelemetry。

更多详细信息和完整代码,请访问 GitHub 仓库

扫码加入技术交流群🖱️
QR code