针对中小型项目,介绍一下简单廉价的日志处理方式。
日志的处理方式多种多样,从裸日志文件到使用消息队列,再到日志分析,各有所长。
比较流行的开源产品有 ELK,Loki。除此之外,个大云厂商都有相应的日志处理服务。
棘手的问题
在做日志处理的时候,有几个棘手的问题。
- 日志格式
- 日志推送
- 日志检索
- 费用
日志格式
为了能让之日检索更为方便,我们不得不去固定日志格式,因为日志处理系统还无法如此智能到,把任意格式的日志文件,格式化成检索模式。
由此带来的问题就是,开发者需要格外注意日志格式,何时写日志,写什么信息等等。不过,业务压力巨大的情况下,很难精益求精。
日志推送
简简单单推送日志很简单,像 filebeat, promtail 这些小程序,都可以把本地日志文件推送到服务端进行分析存储。这里的最麻烦的问题是,推送到日志存储服务之前,
我们通常会对裸日志进行一些简单处理。举例来说,在经典 filebeat -> logstash -> elasticsearch 模式中,logstash 就是扮演日志【分拣员】的角色。用过 logstash 的人都应该有体验,
这里的语法及其繁琐,而且动不动就会出现日志格式不匹配,而导致日志被丢掉的情况。
日志检索
像 Elasticsearch Kibana, Splunk 都有着出色的检索功能,不过并不像搜索引擎一样,随意填写关键字,就可以检索出来,这里也有它自己的语法。而且随着这些产品的迭代,使用门槛也越来越高。
Demo 里的图表很绚丽,不过要想做出这种绚丽的图表,需要做的事情非常繁琐,对于刚上手的人来说,几天的时间,很难搞清楚。
费用
费用也是一个不能忽视的因素。随着规模越来越大,日志存储服务的费用也会随之升高。像专业版的 ELK,商业版的日志处理引擎,动不动就要上千,上万。日志是解决线上问题的必要因素,不能丢弃,所以这部分开销,对于中小规模团队,企业来说,是很大的负担。
简单日志处理需要什么?
我们暂时不讨论大规模的业务日志应该如何处理。在中小规模的业务中,尤其是小规模业务,我们需要的就是日志存储 检索(哪怕是 grep)。
高级的检索,绘制图表功能,其实并不需要。
简单廉价解决方案
这里我们介绍的是 rk-boot/v2 Loki Grafana 对象存储的解决方案。
避开棘手的问题
在这个方案中,我们没有使用到 filebeat, promtail 这种日志采集器,也没有使用日志推送进程。因为是小规模场景,把【棘手的问题】忽略掉,是一个不错的选择。
我们使用 rk-boot/v2 直接往 loki 中推送日志,即避免了繁琐的正则表达式,也不用考虑日志采集器不工作的问题,同时,也不用考虑日志格式的问题。
便宜
- 代码成本:我们使用的都是开源程序
- 存储成本:对象存储的单价非常便宜,以腾讯云为例,0.118元/GB/月,如果再加上免费额度,几乎花不了什么钱。至于流量费用,入流量是免费的,出流量虽然贵一些,不过,日志检索不是每时每刻都在做,在承受范围之内。
- 运维成本:少了采集器,推送服务,以及日志格式处理,运维成本大大降低。
Demo
1.使用 Docker 启动 Loki
我们将会使用 Docker 来启动 Loki,并且在 Loki 配置文件中,指定写入到腾讯云对象存储,当然,也可以写入到任何与 AWS S3 兼容的对象存储中。
我们首先到腾讯云创建一个账号,然后开一个存储桶,当然,记得往里存个1块钱,否则无法开通服务。
- loki.yaml
创建一个 loki.yaml 文件,Docker 启动 Loki 的时候,会把这个文件挂载到 Docker 镜像中。
代码语言:yaml复制# 除了 aws 相关参数,剩下的可以保留成如下的默认值
auth_enabled: false
server:
http_listen_port: 3100
ingester:
wal:
dir: /loki/wal
lifecycler:
ring:
kvstore:
store: inmemory
replication_factor: 1
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: aws
schema: v11
index:
prefix: loki_index_
period: 24h
storage_config:
aws:
bucketnames: loki-logs-1310384686 # 请在腾讯云创建一个对象存储存储桶,并把存储桶名称写到这里
endpoint: cos.ap-beijing.myzijiebao.com # 腾讯云的对象存储域名后缀
access_key_id: <Your access key id from TencentCloud> # 腾讯云 AK
secret_access_key: <Your secret access key from TencentCloud> # 腾讯云 SK
region: ap-beijing # 对象存储存储桶地域
boltdb_shipper:
active_index_directory: /loki/index
shared_store: s3
cache_location: /loki/boltdb-cache
compactor:
working_directory: /loki/boltdb-shipper-compactor
shared_store: aws
- 启动 loki
-v 后面给出自己的当前路径。
代码语言:txt复制$ docker run -v /Users/dongxuny/workspace/rk/rk-demo/gin/basic/loki.yaml:/etc/loki/local-config.yaml -p 3100:3100 grafana/loki
2.使用 Docker 启动 grafana 并配置 Loki
初始化账号: admin
初始化密码:admin
代码语言:txt复制$ docker run -p 3000:3000 grafana/grafana
- 进入 localhost:3000
- 选择 Loki 为数据源
- 配置 Loki 地址
3.下载 rk-boot/v2
rk-boot/v2 是可以通过 YAML 文件启动 Golang 流行框架的依赖库,里面包含了很多实用中间件。
为了模拟微服务,我们同时还下载 rk-gin/v2 来启动 gin-gonic 服务。
代码语言:shell复制$ go get github.com/rookie-ninja/rk-boot/v2
$ go get github.com/rookie-ninja/rk-gin/v2
4.配置 boot.yaml
创建一个 boot.yaml 文件。boot.yaml 文件告诉 rk-boot/v2 启动哪些 Gin 配套的服务。
代码语言:yaml复制---
logger:
- name: logger
loki:
enabled: true
addr: localhost:3100 # 往 Loki 里推送日志
event:
- name: event
loki:
enabled: true
addr: localhost:3100 # 往 Loki 里推送 Event 类型日志
gin:
- name: greeter
port: 8080
enabled: true
loggerEntry: logger # 告诉 Gin 使用 logger 作为日志实例
eventEntry: event # 告诉 Gin 使用 event 作为 Event 日志实例
middleware:
logging:
enabled: true # 启动日志中间件,API 会自动记录日志,并发送到 Loki 中
5.写个 API
代码语言:go复制// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/rookie-ninja/rk-boot/v2"
"github.com/rookie-ninja/rk-gin/v2/boot"
"github.com/rookie-ninja/rk-gin/v2/middleware/context"
"net/http"
)
func main() {
// Create a new boot instance.
boot := rkboot.NewBoot()
// Register handler
ginEntry := rkgin.GetGinEntry("greeter")
ginEntry.Router.GET("/v1/greeter", Greeter)
// Bootstrap
boot.Bootstrap(context.Background())
// Get logger and event instance with bellow functions
//logger := rkentry.GlobalAppCtx.GetLoggerEntry("logger")
//event := rkentry.GlobalAppCtx.GetEventEntry("event")
// Wait for shutdown sig
boot.WaitForShutdownSig(context.Background())
}
func Greeter(ctx *gin.Context) {
rkginctx.GetLogger(ctx).Info("Can you see me from Grafana Loki dashboard?")
ctx.JSON(http.StatusOK, &GreeterResponse{
Message: fmt.Sprintf("Hello %s!", ctx.Query("name")),
})
}
type GreeterResponse struct {
Message string
}
6.启动 main.go & 发送请求
代码语言:txt复制$ go run main.go
$ curl localhost:8080/v1/greeter
7.日志检索
当开启日志中间件,rk-boot/v2 默认会对每个 API 记录 Event 类型的日志。
- API 日志
- 应用日志 可以通过 rkginctx.GetLogger(ctx).Info("XXX") 方式获取当前请求相关的 logger 实例,当开启 meta 中间件的时候,这个 logger 实例会默认打印 RequestID。
- 搜索
Loki 有一套检索语法 ,还比较好理解。
8.验证对象存储桶
登陆腾讯云,验证数据是否正常写入到对象存储。
9.后期运维 & 线上配置 Loki
这里我们只是给了一个单机版的例子,在实际项目当中,我们建议使用 HELM 往 K8S 容器中部署 Loki。
至于费用方面,各大云长上提供了【弹性 K8S 集群】,价格也很便宜,以腾讯云为例,一个 1 CPU, 1 GB 内存的弹性 POD,每个月的大概需要 ¥45,再加上对象存储相关费用,负载均衡,¥100 以内是可以搞定的。
对于中小规模项目,日志方面的开销,完全可以接受。
- HELM LOKI
10.大规模项目
在上面的方案中,我们没有使用任何数据库相关的产品来处理检索引擎,大规模项目,日志庞大的话,LOKI 显然会出现性能瓶颈。这时候,可以考虑切换到商业版日志处理产品。毕竟业务大了,开销也可以上涨。