BI 系统问题记录 Logback + Filebeat + Kafka + ClicksHoue + Metabase

环境 Logback + Filebeat + Kafka + ClicksHoue + Metabase

问题一,生产环境发现 Clickhouse 不再消费 Kafka 中数据。

涉及到的各项配置:

filebeat:

apiVersion: v1
kind: ConfigMap
metadata:
  name: 名称
  #  namespace: kube-system
  labels:
    k8s-app: 名称
data:
  OUTPUT_KAFKA_HOSTS: kafka地址
  filebeat.yml: |-
    filebeat.config.inputs:
      enabled: true
      reload.enabled: true
      reload.period: 10s
    filebeat.inputs:
      - type: log
        paths:
          - /文件地址
    output.kafka:
      enabled: true
      # initial brokers for reading cluster metadata
      hosts: '${OUTPUT_KAFKA_HOSTS}'
      topics:
        - topic: "topic1"
          when.contains:
            message: "\"标识字段\":\"标识字段内容1\""
        - topic: "topic2"
          when.contains:
            message: "\"标识字段\":\"标识字段内容2\""
      partition.round_robin:
        reachable_only: false
      version: '2.6.0'
      required_acks: 1
      compression: gzip
      # max_message_bytes: 1000000
      codec.format:
        string: '%{[message]}'

Kafka 买的现成的

clickhouse 虽说是买的现成的,但是表还是自己创建的,

建表sql 就是官网扒下来的也就不贴了。

排查思路:

查看clickhouse报错

select * from system.errors

Cannot parse input: expected '{' before: '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'

又去看了kafka topic 里的内容发现确实是有 \0x00。

\0x00是不可见字符,cat命令是看不到的。
用的vi看到的。

定位下是 logback 问题 还是 Filebeat 问题

grep -Pa ‘\x00\x00\x00\x00\x00’ /日志目录 -nr 发现没有,初步定位问题为 Filebeat 导致的。
但是自己重现不了。
考虑到 filebeat的input 目前是按文本字符串来处理日志的,改为 json形式获取

解决,修改 filebeat 配置。

修改后

apiVersion: v1
kind: ConfigMap
metadata:
  name: 名字
  #  namespace: kube-system
  labels:
    k8s-app: 名字
data:
  OUTPUT_KAFKA_HOSTS: kafka地址
  filebeat.yml: |-
    filebeat.config.inputs:
      enabled: true
      reload.enabled: true
      reload.period: 10s
    filebeat.inputs:
      - type: log
        paths:
          - /日志目录
        json.keys_under_root: true
        json.overwrite_keys: true
        #  json.message_key: message
        json.add_error_key: true
        json.ignore_decoding_error: true
    output.kafka:
      enabled: true
      # initial brokers for reading cluster metadata
      hosts: '${OUTPUT_KAFKA_HOSTS}'
      topics:
        - topic: "topic1"
          when.equals:
            标识字段: "标识字段内容1"
        - topic: "topic2"
          when.equals:
            标识字段: "标识字段内容2"
      partition.round_robin:
        reachable_only: false
      version: '2.6.0'
      required_acks: 1
      compression: gzip

问题二 一个输出想入到clickhouse俩个字段中

解决方案:改sql ,放弃 select * ,改为自定义

CREATE TABLE.XXX_queue ON CLUSTER `集群名`
(
`eventStartTime` UInt64,
其他字段
 )
 ENGINE = Kafka  其他kafka配置。

CREATE MATERIALIZED VIEW.XXX_mv  ON CLUSTER `集群名` TO.XXX AS
select
    `ts` as `eventStartTimeTs`,
    `dtts` as `eventStartTime`,
    其他字段
from  (
          SELECT *,eventStartTime as ts,fromUnixTimestamp64Milli(toInt64(`eventStartTime`)) as dtts
          FROM.XXX_queue
      ) tmp_source;

问题三: MetaBase Clickhouse时区问题。

定位问题所使用的命令

clickhouse 涉及 命令,(最终发现所有clickhouse的时区都是 Asia/Shanghai)

查看 时区相关设置
select * from system.settings where name like '%zone%'
查看时区
SELECT timezone()
查看配置文件中的时区,默认是注释掉的
cat /etc/clickhouse-server/config.xml
查看服务器时区  
date +%z

修改metabse使用的链接参数
use_client_time_zone=1   #使用客户端时区, 未生效 
se_time_zone=UTC+8&use_server_time_zone=UTC+8   #使用服务端时区, 同样未生效 

Metabase 涉及命令 (同样Metabase的时区也都是 Asia/Shanghai)

查看服务器时区  
date +%z
查看 env是否成功配置
env
metabase  sql 执行窗口 来验证时区是否生效。
select now(),toString(now()),timezone()
以及直接打开表来验证 datetime 类型的是否显示正确。

最终确定问题为 clickhouse.metabase-driver.jar 问题。

当使用 0.7.5 版本时可以正常显示
当使用 0.8.1 版本时不可以正常显示

涉及的组件部署文件:

#  clickhouse  docker-compose.yml
version: "3"
services:
    server:
     image: yandex/clickhouse-server
     ports:
     - "8123:8123"
     - "9000:9000"
     - "9009:9009"
     volumes:
      - D:\docker\clickhouse\tmp:/tmp
      - D:\docker\clickhouse\data/:/var/lib/clickhouse/data 
     environment:
         TZ: Asia/Shanghai
     ulimits:
      nproc: 65535
      nofile:
       soft: 262144
       hard: 262144
    client:
      image: yandex/clickhouse-client
      command: ['--host', 'server']
#  metabase  docker-compose.yml
version: "3"
services:
    metabase:
       # image: metabase/metabase:v0.43.0-rc1
       # image: metabase/metabase:v0.42.4
       image: metabase/metabase:v0.41.3.1
       entrypoint: [ "bash", "-c", "apk add --no-cache tzdata && wget -P /plugins https://github.com/enqueue/metabase-clickhouse-driver/releases/download/0.7.5/clickhouse.metabase-driver.jar && /app/run_metabase.sh"]  
       volumes:
         # - D:\docker\metabase\plugins:/plugins
         - C:\Windows\System32\drivers\etc\hosts:/etc/hosts

       ports:
         - "3000:3000"
       environment:
         TZ: Asia/Shanghai
         JAVA_TIMEZONE: Asia/Shanghai 
         MB_DB_TYPE: mysql
         MB_DB_DBNAME: metabase
         MB_DB_PORT: 3306
         MB_DB_USER: root
         MB_DB_PASS: 123456
         MB_DB_HOST: host.docker.internal

问题四、不能执行 DDL请求

最终解决方案:报错始终没解决,直接把数据备份到一个新表,把表删除了重新建,然后再把数据 insert 回来。 参考 : https://clickhouse.com/docs/en/sql-reference/statements/insert-into/#inserting-the-results-of-select。
下面是排查走过的路。
Clickhouse Cannot execute replicated DDL query, maximum retires exceeded
直译 : 不能执行分布式DDL语句 , 超出最大限度的retires 。
参考: clickhouse 常见问题处理(持续更新中) 、ClickHouse 在商业中台的实践和应用
直接现象,不能加字段了报错了,
所用SQL

 ALTER TABLE.ON CLUSTER `集群名称`    ADD COLUMN `字段名1` 类型,    ADD COLUMN `字段名2` 类型;

返回:Cannot execute replicated DDL query, maximum retires exceeded
BI 系统问题记录 Logback + Filebeat + Kafka + ClicksHoue + Metabase_第1张图片排查方案,根据 clickhouse 常见问题处理(持续更新中 中提示找到ZK的路径,先找clickhouse 针对 ZK的配置 。

命令行:/$ cd   /etc/clickhouse-server
命令行:/etc/clickhouse-server$ ls
conf.d  config.d  config.xml  users.d  users.xml
命令行:/etc/clickhouse-server$ cd  config.d/
命令行:/etc/clickhouse-server/config.d$ ls
01-clickhouse-01-listen.xml  01-clickhouse-02-logger.xml  01-clickhouse-03-query_log.xml  01-clickhouse-04-part_log.xml  chop-generated-remote_servers.xml
命令行:/etc/clickhouse-server/config.d$ cd  ../conf.d
命令行:/etc/clickhouse-server/conf.d$ ls
chop-generated-macros.xml  chop-generated-zookeeper.xml
命令行:/etc/clickhouse-server/conf.d$ cat  chop-generated-zookeeper.xml 

    
        
            zookeeper-0.zookeepers.zoons
            2181
        
        
            zookeeper-1.zookeepers.zoons
            2181
        
        
            zookeeper-2.zookeepers.zoons
            2181
        
        30000
        10000
    
    
        /clickhouse/XXX/task_queue/ddl
    

然后 执行sql看了下ZK 中存的啥, 果然是一堆没执行成功的SQL。

select  * from  system.zookeeper where path ='/clickhouse/XXX/task_queue/ddl'  order by  name asc

也可以看 历史的DDL 都执行了啥 参考 DDL task queue is stuck

select * from system.distributed_ddl_queue  order by entry asc

尝试自动清理 参考配置ClickHouse分布式DDL记录自动清理。有自动清理但是是七天的过期时间。不知道这个是只存了错误的还是都存了。
尝试清理zk下的这些node。

找到报错的源码,原来是在集群中多次执行没有成功。
https://clickhouse.com/codebrowser/ClickHouse/src/Interpreters/DDLWorker.cpp.html#829
那就该去看看每台机器都报啥错了。 一直都是报这个 tmp 的文件夹已存在

2022.07.21 03:26:56.169474 [ 149 ] {}  库名.表名: auto DB::StorageReplicatedMergeTree::processQueueEntry(ReplicatedMergeTreeQueue::SelectedEntryPtr)::(anonymous class)::operator()(DB::StorageReplicatedMergeTree::LogE
ntryPtr &) const: Code: 84, e.displayText() = DB::Exception: Part in /var/lib/clickhouse/data/库名/表名/tmp_clone_202204_0_2_1_4 already exists

看了下是空的文件夹,自己去手动 rm -r 了也不行,还是会自动再新增,继续报这个错。
想自己到6台机器上执行下增加列跳过这把报错,结果也不行,但是给了我们提示,说副本中的metadata 和zk中的不一样

Code: 517. DB::Exception: Received from localhost:9000. DB::Exception: Metadata on replica is not up to date with common metadata in Zookeeper. Cannot alter.

问题五 filebeat 丢日志日志了

场景

项目里都是以json来打日志的,filebeat input 中也配置了 json.keys_under_root: true 等json.* 发现丢数据了,有些日志没收集到。

问题根本原因

filebeat 处理网络存储有问题,本地不会,而我们用的是阿里的nas。
https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-network-volumes.html

排查过程:

1、先百度了一波,先确定几个参数 close_inactive 、 scan_frequency 、 close_rename 、 close_removed. 发现没人改过,默认参数是支持我们业务场景的,毕竟量不大。

2、在filebeat 的 output.kafka 里加了一波捕获错误

- topic: "xxx-error"
          when.has_fields: ['error']

查看 xxx-error 内容,发现是filebeat扫描到了日志但是解析错了
报错:

{\"message\":\"Error decoding JSON: invalid character '\\\\x00' looking for beginning of value\"

导致报错原因:filebeat 读取网络存储的时候读取了很多 NUL,示例日志:

在日志开头莫名其妙的加了很多个 \u0000  也就是 ASCII 的 null。
\\u0000*n {\\\"timestamp\\\":\\\"123456\\\""}}

这里说下这个NUL 在 unicode 中是 \u0000。 在 ASICC 0, 操作系统中是 \0。不同编程语言又不一样。不同编辑器展示的又不一样。vim 展示的是 ^@ 、 sublime 展示的是<0x00>

3、找到问题了,filebeat 和网络存储配合的不是很好。

这个其实是Clickhouse报过这个错,但是当时linux命令排查了下发现日志文件里没有NUL,以为是filebeat传输给多加了NUL,当时直接改了filebeat改为读json了,但是没处理error的。(相当于做了个有bug就把bug提示干掉),这次终于定位准了,是filebeat 和网络存储配合不好导致的。
当时用到查NUL的命令:

grep -Pa '\x00\x00\x00\x00\x00'   目录  -nr

4、解决,改filebeat的配置 将 input 改为读文本,自己加processors 去处理将文本编辑并转成json给到output。本地样例

logging.level: debug

filebeat.config.inputs:
  enabled: true
  reload.enabled: true
  reload.period: 10s
filebeat.inputs:
- type: log
  paths:
   - D:\logs\log-demo\XXX.log
processors:
   # 去掉开头的NUL  并将内容放到 key1 中
  - dissect:  
      tokenizer: "%{key1}"
      # field: "message"
      target_prefix: ""
      trim_values: "all"
      trim_chars: "\x00"   
      overwrite_keys: true
  # 去掉开头的空格  key1 中
  - dissect:  
      tokenizer: "%{key1}"
      field: "key1"
      target_prefix: ""
      trim_values: "all"
      trim_chars: " "  
      overwrite_keys: true
  # 删掉message  ,上边的已经处理后的 message 放到了 key1中
  - drop_fields:
      fields: ["message"]
  # 将key1 由 string 转换成json 并将其中的元素放到 json的root下,也就是一级json。
  # 其实不确定是这一步 string转的json还是 上一步去掉了空格自己就转了。
  - decode_json_fields:
      fields: ["key1"]
      process_array: false
      max_depth: 1
      target: ""
      overwrite_keys: true
      add_error_key: true
  # 删掉key1 减少
  - drop_fields:
      fields: ["key1"]
output.file:
  path: "D:\\logs\\tmp"
  filename: filebeat-target.log

问题六 : Clickhouse 解析报错 cannot parse json expected opening quote at row

参考:https://github.com/ClickHouse/ClickHouse/issues/1589

原因:字段AAA 对应Clickhouse数据类型为String,但是在 json 串中是一个json对象。导致clickhouse不能解析。

导致该原因操作 : 经过上一步问题五的修改filebeat出现了嵌套解析的问题。String中存json应该是个挺常见的场景,但是确实是没有考虑到,之道上线才报了解析异常。
错误配置 : max_depth 上一步设置为了2 , 应该设置为1的。

- decode_json_fields:
      fields: ["key1"]
      process_array: false
      #  这里错了。 
      max_depth: 2  
      target: ""
      overwrite_keys: true
      add_error_key: true

场景重现demo

原文件示例

{"timestamp":"123","AAA":"{\"alert\":[\"aaaaa\"]}"}

max_depth: 2 结果。 这时AAA为json对象

{"timestamp":"123","AAA":{"alert":["aaaaa"]}}

max_depth: 1 结果。 这时AAA为String 与原内容相同。

{"timestamp":"123","AAA":"{\"alert\":[\"aaaaa\"]}"}

问题六 :Clickhouse 中数据比日志中少太多。

原因(猜测)

CH中kafka engine 与 MV( MATERIALIZED VIEW )是 n <-> 1,kafka engine 并发写入MV 导致数据丢失。

解决方案

kafka engine 将kafka_num_consumers 设为1 。

排查过程:

附一个clickhouse kafka 流程https://clickhouse.com/docs/en/integrations/kafka/kafka-table-engine/

  1. 先查了filebeat报错、CH 报错都没报错
  2. 先猜是Filebeat的问题,但是查了kafka中的数据发现kafka中有数据。
将kafka中的数据写到文件用到命令,
--from-beginning : 是新建了一个消费者组,但是consumer 没权限建组,报错了,只能用下边的从每个分区取。

mycount=0; while (( $mycount < 3 )); do  ./bin/kafka-console-consumer.sh --bootstrap-server kafka地址 --topic  topic   --offset 预估开始时间的offset --partition $mycount --max-messages 1000 >> /tmp/XXX.log;((mycount=$mycount+1)); done;
mycount=3; while (( $mycount < 36 )); do  ./bin/kafka-console-consumer.sh --bootstrap-server kafka地址 --topic  topic   --offset 预估开始时间的offset --partition $mycount --max-messages 1000 >> /tmp/XXX.log;((mycount=$mycount+1)); done;
grep  '关键字'  /XXX.log | grep -E 条件1|条件2|条件n
  1. 开始google一波,主要关键字 clickhouse lose data、clickhouse kafka engine lose data、clickhouse MATERIALIZED VIEW lose data、clickhouse ReplicatedMergeTree lose data。clickhouse Distributed lose data
    3.1. 一开始以为是ReplicatedMergeTree 丢了。 改参数 insert_deduplicate=0 还是丢。说明不是这个原因。主要每次丢的还不一样。参考为什么写入ReplicatedMergeTree引擎表里的数据少了?、改参数参考 aliyun user.xml参数修改
    clickhouse 查参数
    select * from system.settings where name = 'insert_deduplicate';
    
    3.2 换了思路先查了下 xxx_mv 里的数据,发现也少了。又查到一个MATERIALIZED VIEW always lost some data,继续改参数 parallel_view_processing=1 用新group消费,还是丢且随机丢。
    3.3 继续查查到了kafka 丢数据。查到 Kafka engine can lose data with replicated table and zookeeper issue 看到一个评论提issue的人说了一句 一个kafka后面挂了多个 MV 我突然想到并发写的问题,直接查了dev环境(dev环境能正常读),kafka_num_consumers = 1,再看prod环境的kafka_num_consumers = 12,这样就是12个消费者往一个 MV里写。把线上测试环境改为 1 直接不丢了,在想应该是有参数设置 kafka engine 到 MV的并发参数,但是没找到。所以解决方案就是改 kafka消费者数量。

问题七 :Metabase中下拉框的值没有刷新,少一些候选值。

参考/知识扩展 Metabase数据库列值缓存的分析与改进

实际解决步骤:

  • 管理员设置
  • 数据模型
  • 选库、选表、选字段(直接页面搜索)
  • 点该字段所在行后边的小齿轮图标 进入字段设置页面
  • 拉到最下面点击重新扫描该字段按钮

问题八 Nullable 的字段不能直接给 非Nullable字段设置值

场景 示例:执行下边sql后正常返回没报错,但是字段值没update。

ALTER TABLE `库名`.`表名`  ON CLUSTER `default`
    update `时间字段` = Nullable字段名
    where `条件`  and 条件;

原因:Nullable 的字段不能直接给 非Nullable字段设置值。

排查过程:
1、直接google sql查update为什么不生效。
找到:https://github.com/ClickHouse/ClickHouse/issues/17806 。查系统表的 MergeTree 后台异变表(不知道为啥叫异变表,可能是地翻译问题,理解为记录影响数据变化信息的表就好)。

select table, parts_to_do, is_done from system.mutations;
实际直接  select *  可以看到更多信息。

2、看到报错

Code: 349, e.displayText() = DB::Exception: Cannot convert NULL value to non-Nullable type: while executing 'FUNCTION CAST(Nullable字段名: 79, 'DateTime64(3, \'Asia/Shanghai\')' : 85) -> CAST(Nullable字段名, 'DateTime64(3, \'Asia/Shanghai\')') DateTime64(3, 'Asia/Shanghai') : 84' (version 21.8.2.1)

3、 直接kill掉 后台报错的的 statements 。
参考:官网 KILL Statements .

KILL MUTATION WHERE database = '库名' AND table = '表名' AND mutation_id = '0000000067'

4、直接拿一条看下字段的返回类型 以及各函数返回类型。

select  `Nullable字段名`,coalesce(Nullable字段名),assumeNotNull(Nullable字段名),toDateTime64(toString(`Nullable字段名`),3,'Asia/Shanghai') ,toString(`Nullable字段名`) from  ``.`` where `条件`  and 条件;

5、最终 assumeNotNull 是生效的。
如何知道的assumeNotNull 函数
先google查CH 中Nullable怎么转回正常类型。 然后找到了官网 Nullable处理函数。翻了翻看到了 assumeNotNull
将可为空类型的值转换为非Nullable类型的值。

你可能感兴趣的:(Filebeat)