网关系统 apisix/kong 日志收集方案实施对比

目前在一个核心服务上应用一个网关系统,并后期推广升级

网关调研方向包括spring,kong apisix,java栈的netty由于一些原因,不适合应用方向

同时考虑云原生的友好程度,简单说是否有配套的k8s ingress和k8s能使用同一套方案,减少技术团队整体的学习和使用成本,主要考虑kong和apisix

kong + konga + kong ingress 个人深度使用了有3年多,整体比较满意

k8s平台集成kong ingress 布署konga集成ui - 博客园 (cnblogs.com)

apisix官方和kong的性能对比,实际是比较的kong1.0,个人对apisix和kong的性能对比是有点疑问的,只不过一般的业务流量,所以在kong能满足要求的前提下,对apisix只是有限了解


目前为加强基础架构对各上层应用的全局支持,需要添加对request_body的请求日志收集,基础的nginx都能做到这点,也许是kong的处理流程上做了较大调整,kong 官方居然不支持

官方插件库 Kong Hub | Plugins and Integrations | Kong Docs (konghq.com)

1 首先官方的log类插件并不能简单便捷的添加对request_body的收集

HTTP Log plugin | Kong Docs (konghq.com)

kong 免费版本提供的log相关插件,都不支持对request_body的收集上报

kong 插件上报一部分,再通过更改kong相关的nginx配置生成一部分,两部分用flink做大数据处理双流join实现,该方案不优雅

考虑直接通过kong 插件收集

准备找找有没有第三方的方案,有必要的的话需要自己参照kong的官方插件写插件了

整体看了下难度倒是不大,个人以前搞openwrt路由器luci时有点lua的开发经验 lua https request 调用 - 博客园 (cnblogs.com)

EuphonyInc/kong-plugin-request-body-logger: A plugin for Kong which enables logging of request bodies over HTTP (github.com)

2 日志处理收集,写入kafka的场景较为典型,通常结合大数据spark streaming/flink 做流式计算

https://docs.konghq.com/hub/kong-inc/kafka-log

kong 官方插件库提供kafka 的日志收集,但是收费,同时有不能简易收集request_body的问题

3 Kafka Upstream plugin | Kong Docs (konghq.com)

kong 有一个专门的上报kafka组件,

--data "config.forward_body=true" 简单看了遍文档,这个插件支持对request_body的日志收集,该组件也同样收费

log类插件不支持request_body,kafka在日志收集上的应用,再看看这个收费插件,大概明白官方为什么没有把request_body做在免费插件里了

在log插件代码基础上加上request_body 还算简单,但在没有官方代码参照的基础上(这些代码官方未开源),实现写kafka 难度和工作量会大很多,可以用多级上报,结合filebeat,logstash,prometheus之类的实现

基础功能足够日常使用,收费功能有效,但预算有限,因此转头看看其他方案有没有替代,比如apisix


apisix 目前全开源,比较合胃口,开源则对一些官方不支持的特性做定制化开发比较方便,kong也开源了,但插件类同样只开源了免费的部分

apisix官方插件库

apisix/apisix/plugins at release/2.11 · apache/apisix (github.com)

请求日志收集至kafka

apisix/kafka-logger.lua at release/2.11 · apache/apisix (github.com)

看代码,支持对request的收集

        include_req_body = {type = "boolean", default = false},
        include_req_body_expr = {
            type = "array",
            minItems = 1,
            items = {
                type = "array",
                items = {
                    type = "string"
                }
            }
        }

并未用kong2.0和apisix做基础性能对比,但就日志request_body收集功能上,apisix和kong 基础免费版,apisix强于kong

因此网关系统开始部分从kong迁移转至apisix


以下是部分测试验证的细节,启动log-kafka插件收集

{
    "broker_list": {
        "192.168.11.22": 9092,
        "192.168.11.23": 9092,
        "192.168.11.24": 9092
    },
    "kafka_topic": "test_apisix",
    "key": "key1",
    "batch_max_size": 1,
    "name": "kafka logger",
    "include_req_body":true,
    "meta_format":"default",
    "log_format":""
}

meta_format支持两种格式,为收集解析方便使用"default"

样例日志
{
    "start_time": 1638185753246,
    "client_ip": "172.17.0.1",
    "latency": 0,
    "service_id": "127.0.0.1",
    "server": {
        "hostname": "fe053d1baf4a",
        "version": "2.9"
    },
    "response": {
        "status": 404,
        "headers": {
            "server": "APISIX/2.9",
            "connection": "close",
            "transfer-encoding": "chunked",
            "content-type": "text/plain; charset=utf-8"
        },
        "size": 223
    },
    "request": {
        "headers": {
            "host": "127.0.0.1:8280",
            "user-agent": "curl/7.29.0",
            "accept": "*/*"
        },
        "method": "GET",
        "size": 83,
        "url": "http://127.0.0.1:9080/hello",
        "querystring": {},
        "uri": "/hello"
    }
}

自定义格式

curl http://127.0.0.1:9080/apisix/admin/plugin_metadata/kafka-logger -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
    "log_format": {"host": "$host", "@timestamp": "$time_iso8601",    "client_ip":"$remote_addr","request_id":"$request_id","request_length":"$request_length","request_time":"$request_time","header_test_1":"$http_nothas","header_test_1":"$http_x-api-key","body":"$request_body"}
}'

apisix从测试和查看源码上看,也有些待优化的点

1 "default"格式完全默认无法自定义,如果需要nginx原生的一些信息,则需要使用log_format

defautl信息为目前为硬编码,如果需要一些别的信息,需要直接修改代码
https://github.com/apache/apisix/blob/2.10.1.1/apisix/utils/log-util.lua

default格式实现,和上面的demo对应
local log =  {
        request = {
            url = url,
            uri = var.request_uri,
            method = ngx.req.get_method(),
            headers = ngx.req.get_headers(),
            querystring = ngx.req.get_uri_args(),
            size = var.request_length
        },
        response = {
            status = ngx.status,
            headers = ngx.resp.get_headers(),
            size = var.bytes_sent
        },
        server = {
            hostname = core.utils.gethostname(),
            version = core.version.VERSION
        },
        upstream = var.upstream_addr,
        service_id = service_id,
        route_id = route_id,
        consumer = consumer,
        client_ip = core.request.get_remote_client_ip(ngx.ctx.api_ctx),
        start_time = ngx.req.start_time() * 1000,
        latency = (ngx_now() - ngx.req.start_time()) * 1000
    }

#默认的default格式
_M.get_full_log = get_full_log
#自定义全局格式
_M.get_custom_format_log = get_custom_format_log               

2 log_format目前是全局生效的,即全局只能有一种log_format格式,若想对不同的路由配置不同的规则,则作不到

3 可以通过修改 https://github.com/apache/apisix/blob/2.10.1.1/apisix/utils/log-util.lua default格式的log内容,很简单

apisix满足网关的性能和日志收集需求

END

上一篇:ApiSix


下一篇:Apache APISIX 源码构建