29、利用日志和跟踪理解系统行为

利用日志和跟踪理解系统行为

1. 日志数据收集与格式约定

为了有效理解系统行为,收集日志中的 IP 数据并生成用户常见地理区域的可视化图表是一种可行的方式。而要有效地存储和搜索日志数据,首先需要工程团队就日志格式达成一致。一致的格式有助于确保数据能够被高效地存储和处理。

1.1 多源数据收集

要实现系统的可观测性,需要从多个来源收集数据,不仅包括运行中的服务,还包括基础设施。定义通用格式可以让我们更轻松地分析数据,并使用现有工具进行数据搜索。可能收集和使用的数据类型如下:
- 应用程序日志
- 数据库日志
- 网络日志
- 底层操作系统收集的性能数据

对于部分组件,可能无法控制其日志格式,这时就需要处理其特殊性并进行转换。不过,我们可以先聚焦于能够控制的服务部分。确保整个工程团队遵循统一的格式和操作方式,从长远来看是有回报的,因为这会让数据收集变得更简单、更有效。接下来,我们先确定日志条目中应存储的内容,再探讨存储方式。

1.2 日志条目有用信息

为了让日志数据有助于理解系统行为,日志条目应包含以下关键信息:

1.2.1 时间戳

为了关联和正确排序数据,需要为日志条目添加时间戳。时间戳应尽可能详细和精确,例如使用四位数年份并采用最佳分辨率。每个服务最好以微秒为单位生成自己的时间戳,并且应包含时区信息,尽可能以 GMT/UTC 格式收集数据。这样可以避免不同服务因时区不同而导致的数据关联问题,在分析时能更轻松地按事件发生时间对数据进行排序。

1.2.2 标识符

在日志数据中应尽可能多地使用唯一标识符,如请求 ID、用户 ID 等。这些标识符在跨多个数据源引用数据时非常有价值,能够有效地对不同来源的数据进行分组。通常,系统中已经存在这些 ID 用于标识资源,并且它们可能已经在不同服务中传播,因此应充分利用它们。结合时间戳,唯一标识符能成为理解系统中事件流的强大工具。

1.2.3 来源

确定日志条目的来源有助于在需要时进行调试。常见的来源数据包括:
- 主机
- 类或模块
- 函数
- 文件名

在记录函数调用的执行时间时,收集的来源信息可以帮助推断性能,即使不是实时的,也能有效识别瓶颈和潜在的性能问题。

1.2.4 级别或类别

每个日志条目应包含一个类别,可以是日志的数据类型或日志级别。常见的日志级别有:ERROR、DEBUG、INFO、WARN。类别可以对数据进行分组,一些工具可以解析日志文件,搜索 ERROR 级别的消息并将其发送到错误报告系统,从而实现错误报告的自动化。

1.3 日志结构与可读性

日志条目应采用人类可读的格式,同时要便于机器解析。避免使用二进制编码或普通人类难以理解的编码方式,例如不要存储图像的二进制表示,而应使用其 ID、文件大小等相关数据。此外,应避免使用多行日志,因为在日志聚合工具中解析时可能会导致碎片化,容易丢失与特定日志条目相关的信息,如 ID、时间戳或来源。

在示例中,我们使用 JSON 对日志条目进行编码,这样既能提供人类可读和机器可解析的数据,又能自动包含前面提到的部分数据。同时,还可以使用 Logstash 格式化库,它有多种语言版本,能提供一致的数据格式。以下是一个使用 Logstash 库为 Python 收集的日志条目示例:

{ 
    "source_host" : "e7003378928a", 
    "pathname" : "usrlocallibpython3.6site-packagesnamekorunners.py", 
    "relativeCreated" : 386.46125793457031,  
    "levelno" : 20,  
    "msecs" : 118.99447441101074,  
    "process" : 1,  
    "args" : [    "orders_service"  ],
    "name" : "nameko.runners",  
    "filename" : "runners.py", 
    "funcName" : "start", 
    "module" : "runners", 
    "lineno" : 64,  
    "@timestamp" : "2018-02-02T18:42:09.119Z", 
    "@version" : 1, 
    "message" : "starting services: orders_service", 
    "levelname" : "INFO", 
    "stack_info" : null,  
    "thread" : 140612517945416,   
    "processName" : "MainProcess",  
    "threadName" : "MainThread",  
    "msg" : "starting services: %s",  
    "created" : 1520275329.1189945
}

下面是一个 mermaid 流程图,展示了日志数据从生成到存储的基本流程:

graph LR
    A[服务生成日志] --> B[遵循统一格式]
    B --> C[使用 Logstash 格式化]
    C --> D[存储日志数据]

2. 构建日志基础设施

2.1 ELK 和 Fluentd 解决方案

为了收集和聚合所有运行服务的日志,并提供搜索和关联功能,我们将构建一个基于 Elasticsearch、Logstash 和 Kibana(ELK)的日志基础设施,并使用 Fluentd 作为数据收集器。以下是这些技术的简要介绍:
- Elasticsearch :一个集中存储数据的搜索和分析引擎,对日志数据进行索引,支持高效的搜索和聚合操作。
- Logstash :服务器端处理管道,可从多个源摄取数据并进行转换,然后发送到 Elasticsearch。在本方案中,我们利用其格式化和数据收集功能,但使用 Fluentd 来发送数据。
- Kibana :用于可视化 Elasticsearch 数据的 UI 工具,可查询数据、探索关联并生成可视化图表。
- Fluentd :开源数据收集器,用于将服务中的日志推送到 Elasticsearch。它可以作为 Dockerfiles 的日志提供程序,在 Docker 组合文件中声明即可使用。

2.2 设置日志解决方案

我们通过 Docker 组合文件来设置日志解决方案,以下是添加到组合文件中的新组件:

version: '2.1'
services:
  gateway:
    container_name: simplebank-gateway
    restart: always
    build: ./gateway
    ports:
      - 5001:5000
    volumes:
      - ./gateway:/usr/src/app
    links:
      - "rabbitmq:simplebank-rabbitmq"
      - "fluentd"
    logging: 
      driver: "fluentd" 
      options:
        fluentd-address: localhost:24224
        tag: simplebank.gateway
  kibana:
    image: kibana 
    links:
      - "elasticsearch" 
    ports:
      - "5601:5601"
  elasticsearch:
    image: elasticsearch 
    expose:
      - 9200
    ports:
      - "9200:9200"
  fluentd:
    build: ./fluentd 
    volumes:
      - ./fluentd/conf:/fluentd/etc 
    links:
      - "elasticsearch" 
    ports:
      - "24224:24224"
      - "24224:24224/udp"

2.3 Fluentd 配置

构建 Fluentd 时使用的 Dockerfile 如下:

FROM fluent/fluentd:v0.12-debian 
RUN ["gem", "install", "fluent-plugin-elasticsearch", 
    "--no-rdoc", "--no-ri", "--version", "1.9.2"] 

Fluentd 的配置文件如下:

<source> 
  @type forward 
  port 24224
  bind 0.0.0.0
</source>
<match *.**> 
  @type copy 
  <store>
    @type elasticsearch 
    host elasticsearch
    port 9200
    logstash_format true
    logstash_prefix fluentd
    logstash_dateformat %Y%m%d
    include_tag_key true
    type_name access_log
    tag_key @log_name
    flush_interval 1s
  </store>
  <store>
    @type stdout 
  </store>
</match>

2.4 配置日志收集

在服务中,可以通过环境变量控制日志级别,以便在开发和生产环境中使用不同的级别。以网关服务为例,其日志配置文件如下:

AMQP_URI: amqp://${RABBIT_USER:guest}:${RABBIT_PASSWORD:guest}@${RABBIT_HOST:
    localhost}:${RABBIT_PORT:5672}/
WEB_SERVER_ADDRESS: '0.0.0.0:5000'
RPC_EXCHANGE: 'simplebank-rpc'
LOGGING: 
    version: 1
    handlers:
        console:
            class: logging.StreamHandler 
    root:
        level: ${LOG_LEVEL:INFO} 
        handlers: [console] 

网关服务代码中启用日志的部分如下:

import datetime
import json
import logging 
import uuid
from logstash_formatter import LogstashFormatterV1 
from nameko.rpc import RpcProxy, rpc
from nameko.web.handlers import http
from statsd import StatsClient
from werkzeug.wrappers import Request, Response

class Gateway:
    name = "gateway"
    orders = RpcProxy("orders_service")
    statsd = StatsClient('statsd', 8125,
                         prefix='simplebank-demo.gateway')
    logger = logging.getLogger() 
    handler = logging.StreamHandler() 
    formatter = LogstashFormatterV1() 
    handler.setFormatter(formatter) 
    logger.addHandler(handler) 

    @http('POST', '/shares/sell')
    @statsd.timer('sell_shares')
    def sell_shares(self, request):
        req_id = uuid.uuid4()
        res = u"{}".format(req_id)
        self.logger.debug(
            "this is a debug message from gateway", 
            extra={"uuid": res}) 
        self.logger.info("placing sell order", extra=
            {"uuid": res}) 
        self.__sell_shares(res)
        return Response(json.dumps(
            {"ok": "sell order {} placed".format(req_id)}),
            mimetype='application/json')

    @rpc
    def __sell_shares(self, uuid):
        self.logger.info("contacting orders service", extra={
            "uuid": uuid}) 
        res = u"{}".format(uuid)
        return self.orders.sell_shares(res)

    @http('GET', '/health')
    @statsd.timer('health')
    def health(self, _request):
        return json.dumps({'ok': datetime.datetime.utcnow().__str__()})

2.5 启动服务与配置 Kibana

完成上述设置后,在根目录的控制台中执行以下命令启动所有服务、指标和日志基础设施:

docker-compose up --build --remove-orphans

启动后,还需要配置 Kibana 以使用 Fluentd 收集并存储在 Elasticsearch 中的日志。访问 Kibana 网络仪表板(http://localhost:5601),首次访问会重定向到管理页面,需要配置索引模式。在 Fluentd 配置中,我们设置了 logstash 前缀为 fluentd,因此在索引文本框中输入 fluentd-*,然后点击创建按钮,即可开始探索多个服务生成的日志数据。

通过以上步骤,我们构建了一个强大的日志基础设施,能够帮助我们更好地理解系统行为,进行问题排查和性能优化。

下面是一个 mermaid 流程图,展示了整个日志基础设施的工作流程:

graph LR
    A[服务] --> B[STDOUT 输出日志]
    B --> C[Fluentd 收集]
    C --> D[Elasticsearch 存储与索引]
    D --> E[Kibana 可视化与查询]

整个过程可以总结为以下步骤:
1. 服务生成日志并输出到 STDOUT。
2. Fluentd 收集日志并推送到 Elasticsearch。
3. Elasticsearch 对日志数据进行存储和索引。
4. Kibana 从 Elasticsearch 获取数据并进行可视化和查询。

通过这种方式,我们可以集中管理和分析所有服务的日志,提高系统的可观测性。

3. 日志数据的实际应用与优势

3.1 故障排查与问题定位

日志数据在故障排查中起着至关重要的作用。当系统出现问题时,我们可以通过查看日志中的时间戳、标识符、来源和日志级别等信息,快速定位问题所在。例如,如果某个服务出现错误,我们可以根据日志中的 ERROR 级别信息,结合唯一标识符,追踪该请求在各个服务中的处理流程,找出引发错误的具体函数或模块。

以下是一个简单的表格,展示了不同日志信息在故障排查中的作用:
| 日志信息 | 作用 |
| ---- | ---- |
| 时间戳 | 确定事件发生的顺序和时间,便于分析问题的先后关系 |
| 标识符 | 关联不同服务中的同一请求,追踪请求的完整流程 |
| 来源 | 定位问题发生的具体服务、模块或函数 |
| 日志级别 | 筛选重要信息,如 ERROR 级别的日志通常表示系统出现了严重问题 |

3.2 性能分析与优化

日志数据还可以用于性能分析和优化。通过记录函数的执行时间和资源使用情况,我们可以找出系统中的瓶颈和潜在的性能问题。例如,在日志中记录每个函数的执行时间,然后根据来源信息进行分组统计,就可以得到各个模块的性能指标。

以下是一个 mermaid 流程图,展示了使用日志数据进行性能分析的基本流程:

graph LR
    A[收集日志数据] --> B[提取执行时间和来源信息]
    B --> C[按来源分组统计]
    C --> D[找出性能瓶颈]
    D --> E[进行优化]
3.3 安全审计与合规性

日志数据对于安全审计和合规性检查也非常重要。通过记录用户的操作行为和系统的关键事件,我们可以监控系统的安全性,及时发现异常行为。例如,记录用户的登录时间、操作内容和 IP 地址等信息,可以帮助我们识别潜在的安全威胁。

4. 日志管理的最佳实践

4.1 日志级别管理

合理设置日志级别可以有效地控制日志数据的量,避免产生过多的无用信息。在开发环境中,可以将日志级别设置为 DEBUG,以便详细记录系统的运行状态;而在生产环境中,建议将日志级别设置为 INFO 或 WARN,只记录重要的信息。

4.2 日志保留策略

制定合理的日志保留策略可以确保日志数据的有效性和安全性。根据业务需求和法规要求,确定日志数据的保留时间,并定期清理过期的日志。例如,对于一些关键业务的日志,可以保留较长时间;而对于一些临时的调试日志,可以在问题解决后及时删除。

4.3 日志监控与告警

建立日志监控和告警机制可以及时发现系统中的问题。通过设置规则,监控日志中的特定信息,当出现异常情况时及时发出告警。例如,当某个服务的 ERROR 级别日志数量超过一定阈值时,发送邮件或短信通知相关人员。

5. 总结与展望

5.1 总结

通过构建基于 ELK 和 Fluentd 的日志基础设施,我们可以有效地收集、存储和分析系统的日志数据。日志数据不仅可以帮助我们理解系统行为,进行故障排查和性能优化,还可以用于安全审计和合规性检查。同时,遵循日志管理的最佳实践,可以提高日志数据的质量和可用性。

5.2 展望

随着系统的不断发展和复杂化,日志数据的规模和复杂度也会不断增加。未来,我们可以进一步探索日志数据的分析方法和技术,如使用机器学习算法进行异常检测和预测分析。此外,还可以结合其他数据源,如指标数据和跟踪数据,实现更全面的系统可观测性。

在实际应用中,我们可以根据具体的业务需求和系统特点,灵活调整日志基础设施的配置和日志管理策略,以满足不断变化的需求。通过持续优化和改进,我们可以更好地利用日志数据,提升系统的稳定性、性能和安全性。

以下是一个 mermaid 流程图,展示了未来日志管理的发展方向:

graph LR
    A[现有日志基础设施] --> B[引入机器学习算法]
    A --> C[结合其他数据源]
    B --> D[异常检测与预测分析]
    C --> E[实现全面可观测性]
    D --> F[持续优化系统]
    E --> F

通过不断探索和创新,我们可以将日志管理提升到一个新的水平,为系统的稳定运行和业务的发展提供有力支持。整个日志管理的过程可以总结为以下步骤:
1. 构建日志基础设施,确保日志数据的收集、存储和分析。
2. 应用日志数据进行故障排查、性能分析和安全审计。
3. 遵循日志管理的最佳实践,如日志级别管理、保留策略和监控告警。
4. 探索日志数据的分析方法和技术,结合其他数据源,实现更全面的系统可观测性。
5. 持续优化和改进日志管理策略,提升系统的稳定性、性能和安全性。

通过以上步骤,我们可以建立一个高效、可靠的日志管理体系,为系统的运行和发展提供有力保障。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值