{"id":29418455,"url":"https://github.com/dennyzhang/challenges-k8s-logging","last_synced_at":"2025-07-11T23:34:36.005Z","repository":{"id":67455831,"uuid":"145078281","full_name":"dennyzhang/challenges-k8s-logging","owner":"dennyzhang","description":"Notes for deep dive into Kubernetes logging","archived":false,"fork":false,"pushed_at":"2019-06-03T03:09:08.000Z","size":10,"stargazers_count":4,"open_issues_count":0,"forks_count":7,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-05T21:06:21.853Z","etag":null,"topics":["denny-challenges","denny-kubernetes","kubernetes","logging"],"latest_commit_sha":null,"homepage":"https://www.dennyzhang.com/battle","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dennyzhang.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-08-17T05:58:53.000Z","updated_at":"2024-11-08T10:20:56.000Z","dependencies_parsed_at":"2023-06-11T02:49:53.057Z","dependency_job_id":null,"html_url":"https://github.com/dennyzhang/challenges-k8s-logging","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dennyzhang/challenges-k8s-logging","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennyzhang%2Fchallenges-k8s-logging","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennyzhang%2Fchallenges-k8s-logging/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennyzhang%2Fchallenges-k8s-logging/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennyzhang%2Fchallenges-k8s-logging/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dennyzhang","download_url":"https://codeload.github.com/dennyzhang/challenges-k8s-logging/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennyzhang%2Fchallenges-k8s-logging/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264914208,"owners_count":23682799,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["denny-challenges","denny-kubernetes","kubernetes","logging"],"created_at":"2025-07-11T23:32:50.957Z","updated_at":"2025-07-11T23:34:35.994Z","avatar_url":"https://github.com/dennyzhang.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"* Kubernets Logging                                              :Concept:\n:PROPERTIES:\n:type:     logging\n:END:\n\n#+BEGIN_HTML\n\u003ca href=\"https://github.com/dennyzhang/challenges-k8s-logging\"\u003e\u003cimg align=\"right\" width=\"200\" height=\"183\" src=\"https://www.dennyzhang.com/wp-content/uploads/denny/watermark/github.png\" /\u003e\u003c/a\u003e\n\n\u003cdiv id=\"the whole thing\" style=\"overflow: hidden;\"\u003e\n\u003cdiv style=\"float: left; padding: 5px\"\u003e \u003ca href=\"https://www.linkedin.com/in/dennyzhang001\"\u003e\u003cimg src=\"https://www.dennyzhang.com/wp-content/uploads/sns/linkedin.png\" alt=\"linkedin\" /\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv style=\"float: left; padding: 5px\"\u003e\u003ca href=\"https://github.com/dennyzhang\"\u003e\u003cimg src=\"https://www.dennyzhang.com/wp-content/uploads/sns/github.png\" alt=\"github\" /\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv style=\"float: left; padding: 5px\"\u003e\u003ca href=\"https://www.dennyzhang.com/slack\" target=\"_blank\" rel=\"nofollow\"\u003e\u003cimg src=\"https://slack.dennyzhang.com/badge.svg\" alt=\"slack\"/\u003e\u003c/a\u003e\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\u003cbr/\u003e\n\u003ca href=\"http://makeapullrequest.com\" target=\"_blank\" rel=\"nofollow\"\u003e\u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg\" alt=\"PRs Welcome\"/\u003e\u003c/a\u003e\n#+END_HTML\n\nBlog URL: https://kubernetes.dennyzhang.com/challenges-k8s-logging, Category: [[https://kubernetes.dennyzhang.com/category/concept][concept]]\n\n** Questions\n*** fluentd monitor only if folder exists\n*** When fluentd scan pod log files, it's not fast enough.\nIt will scan every 60 seconds. But my pods may be recreated within 10 seconds.\n*** Multiple log agents for different personas?\n*** kube pods: k8s related pods and pods from k8s add\n*** If each k8s worker node only has one log agent, would logging aggregation run into performance issue?\n*** Can't turn off feature level logging\n*** CRD: k8s controller issue unavailable issue\n- sink deletion when controller is down?\n* org-mode configuration                                           :noexport:\n#+STARTUP: overview customtime noalign logdone showall\n#+DESCRIPTION: \n#+KEYWORDS: \n#+AUTHOR: Denny Zhang\n#+EMAIL:  denny@dennyzhang.com\n#+TAGS: noexport(n)\n#+PRIORITIES: A D C\n#+OPTIONS:   H:3 num:t toc:nil \\n:nil @:t ::t |:t ^:t -:t f:t *:t \u003c:t\n#+OPTIONS:   TeX:t LaTeX:nil skip:nil d:nil todo:t pri:nil tags:not-in-toc\n#+EXPORT_EXCLUDE_TAGS: exclude noexport\n#+SEQ_TODO: TODO HALF ASSIGN | DONE BYPASS DELEGATE CANCELED DEFERRED\n#+LINK_UP:   \n#+LINK_HOME: \n* DONE mac syslog rfc5424                                          :noexport:\n  CLOSED: [2018-07-19 Thu 16:30]\nhttps://gist.github.com/darconeous/1b3aee893536c1de2401\nhttps://stackoverflow.com/questions/380172/reading-syslog-output-on-a-mac\n\nhttps://docs.fluentd.org/v1.0/articles/in_syslog\nhttps://stackify.com/syslog-101/\n\n\u003c16\u003e1 2017-02-28T12:00:00.009Z 192.168.0.1 fluentd - - - Hello!\n* TODO openshift logging: https://docs.openshift.com/container-platform/3.11/install_config/aggregate_logging.html :noexport:\n* 日志系统 -- Logging                                    :noexport:IMPORTANT:\n我们通常使用的日志库（如log4j等），将日志基本分为以下几类（从低到高）：\n\n| Level | Summary                                                                                                                  |\n|-------+--------------------------------------------------------------------------------------------------------------------------|\n| TRACE | The TRACE Level designates finer-grained informational events than the DEBUG                                             |\n| DEBUG | The DEBUG Level designates fine-grained informational events that are most useful to debug an application.               |\n| INFO  | The INFO level designates informational messages that highlight the progress of the application at coarse-grained level. |\n| WARN  | The WARN level designates potentially harmful situations.                                                                |\n| ERROR | The ERROR level designates error events that might still allow the application to continue running.                      |\n| FATAL | The FATAL level designates very severe error events that will presumably lead the application to abort.                  |\n\n#+begin_example\n  典型的日志系统需具备三个基本组件,分别为agent(封装数据源,将数据源中的数据发送给\n  collector),collector(接收多个 agent的数据,并进行汇总后导入后端的store中),store(中\n  央存储系统,应该具有可扩展性和可靠性,应该支持当前非常流行的HDFS)。\n\n  传统的日志分析系统提供了一种离线处理日志信息的可扩展方案,但若要进行实时处理,通常会有较\n  大延迟。而现有的消(队列)系统能够很好的处理实时或者近似实时的应用,但未处理的数据通常不\n  会写到磁盘上\n#+end_example\n** [#A] Scribe - facebook开源的日志收集系统\n#+begin_example\n   Scribe是对一个使用非阻断C++服务器的thrift服务的实现.\n\n   它最重要的特点是容错性好。当后端的存储系统crash时,scribe会将数据写到本地磁盘上,当存储系统恢复正常后,scribe将日志重新加载到存储系统中。\n\n   scribe支持非常多的store,包括file(文件),buffer(双层存储,一个主储存,一个副存储),network(另一个scribe服务器),bucket(包含多个 store,通过hash的将数据存到不同store中),null(忽略数据),thriftfile(写到一个Thrift TFileTransport文件中)和multi(把数据同时存放到不同store中)。\n\n   Attempts to store messages and returns true if successful.\n   On failure, returns false and messages contains any un-processed messages\n#+end_example\n*** [概念] category: 是对预期目标信息的高层次描述\nScribe的独特之处是客户端日志实例包含两个字符串:类别和信息(a category and a message).\n类别(category)是对预期目标信息的高层次描述,可以在Scribe服务器中进行配置,这样就允许我们可以通过更改配置文件的方式转移数据而不需要更改代码.\n*** 代码解析\n    store.cpp来存储消息\n# --8\u003c-------------------------- §separator§ ------------------------\u003e8--\nstruct LogEntry\n{\n  1:  string category,\n  2:  string message\n}\n# --8\u003c-------------------------- §separator§ ------------------------\u003e8--\n*** TODO scribe_server.h: class scribeHandler : virtual public scribe::thrift::scribeIf, 这里scribeIf是什么接口\n*** [概念] buckets\n**** complicated configuration file                                :noexport:\n##  Copyright (c) 2007-2008 Facebook\n##\n##  Licensed under the Apache License, Version 2.0 (the \"License\");\n##  you may not use this file except in compliance with the License.\n##  You may obtain a copy of the License at\n##\n##      http://www.apache.org/licenses/LICENSE-2.0\n##\n##  Unless required by applicable law or agreed to in writing, software\n##  distributed under the License is distributed on an \"AS IS\" BASIS,\n##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n##  See the License for the specific language governing permissions and\n##  limitations under the License.\n##\n## See accompanying file LICENSE or visit the Scribe site at:\n## http://developers.facebook.com/scribe/\n\n##\n## Sample Scribe configuration\n##\n\n# This file configures Scribe to listen for messages on port 1463 and write\n# them to /tmp/scribetest\n#\n# This configuration also tells Scribe to discard messages with a category\n# that begins with 'ignore'.\n#\n# If the message category is 'bucket_me', Scribe will hash this message to\n# 1 of 5 buckets.\n\nport=1463\nmax_msg_per_second=2000000\ncheck_interval=3\n\n# IGNORE* - discards messages for categories that begin with 'ignore'\n\u003cstore\u003e\ncategory=ignore*\ntype=null\n\u003c/store\u003e\n\n# BUCKET_ME - write 'bucket_me' messages to 1 of 5 subdirectories\n\u003cstore\u003e\ncategory=bucket_me\ntype=buffer\n\ntarget_write_size=20480\nmax_write_interval=1\nbuffer_send_rate=2\nretry_interval=30\nretry_interval_range=10\n\n\u003cprimary\u003e\ntype=bucket\nnum_buckets=5\nbucket_subdir=bucket\nbucket_type=key_hash\ndelimiter=58\n# This will hash based on the part of the message before the first ':' (char(58))\n\n\u003cbucket\u003e\ntype=file\nfs_type=std\nfile_path=/tmp/scribetest\nbase_filename=bucket_me\nmax_size=10000\n\u003c/bucket\u003e\n\u003c/primary\u003e\n\n\u003csecondary\u003e\ntype=file\nfs_type=std\nfile_path=/tmp\nbase_filename=bucket_me\nmax_size=30000\n\u003c/secondary\u003e\n\u003c/store\u003e\n\n# DEFAULT - write all other categories to /tmp/scribetest\n\u003cstore\u003e\ncategory=default\ntype=buffer\n\ntarget_write_size=20480\nmax_write_interval=1\nbuffer_send_rate=2\nretry_interval=30\nretry_interval_range=10\n\n\u003cprimary\u003e\ntype=file\nfs_type=std\nfile_path=/tmp/scribetest\nbase_filename=thisisoverwritten\nmax_size=1000000\n\u003c/primary\u003e\n\n\u003csecondary\u003e\ntype=file\nfs_type=std\nfile_path=/tmp\nbase_filename=thisisoverwritten\nmax_size=3000000\n\u003c/secondary\u003e\n\u003c/store\u003e\n*** DONE [#A] scribe在系统恢复时, 如何重新加载到存储系统          :Important:\n    CLOSED: [2011-09-29 Thu 16:33]\n/tmp/scribe/scribe/src/store_queue.cpp: void StoreQueue::threadMember()\n#+begin_src c++\n    // handle messages if stopping, enough time has passed, or queue is large\n    //\n    if (stop ||\n        (this_loop - last_handle_messages \u003e= maxWriteInterval) ||\n        msgQueueSize \u003e= targetWriteSize) {\n\n      if (failedMessages) {\n        // process any messages we were not able to process last time\n        messages = failedMessages;\n        failedMessages = boost::shared_ptr\u003clogentry_vector_t\u003e();\n      } else if (msgQueueSize \u003e 0) {\n        // process message in queue\n        messages = msgQueue;\n        msgQueue = boost::shared_ptr\u003clogentry_vector_t\u003e(new logentry_vector_t);\n        msgQueueSize = 0;\n      }\n\n      // reset timer\n      last_handle_messages = this_loop;\n    }\n\n    pthread_mutex_unlock(\u0026msgMutex);\n\n    if (messages) {\n      if (!store-\u003ehandleMessages(messages)) {\n        // Store could not handle these messages\n        processFailedMessages(messages);\n      }\n      store-\u003eflush();\n    }\n\n    if (!stop) {\n      // set timeout to when we need to handle messages or do a periodic check\n      abs_timeout.tv_sec = min(last_periodic_check + checkPeriod,\n          last_handle_messages + maxWriteInterval);\n      abs_timeout.tv_nsec = 0;\n\n      // wait until there's some work to do or we timeout\n      pthread_mutex_lock(\u0026hasWorkMutex);\n      if (!hasWork) {\n\tpthread_cond_timedwait(\u0026hasWorkCond, \u0026hasWorkMutex, \u0026abs_timeout);\n      }\n      hasWork = false;\n      pthread_mutex_unlock(\u0026hasWorkMutex);\n    }\n#+end_src\n*** DONE 如果写log失败, store.cpp会去掉已经写好的消息, 同时返回失败。 由此, 用户重试即可\n    CLOSED: [2011-09-29 Thu 15:32]\n*** scribe的架构比较简单,主要包括三部分,分别为scribe agent, scribe和存储系统\n#+begin_example\n(1) scribe agent\n\nscribe agent实际上是一个thrift client。 向scribe发送数据的唯一方法是使用thrift client,\nscribe内部定义了一个thrift接口,用户使用该接口将数据发送给server。\n\n(2) scribe\n\nscribe接收到thrift client发送过来的数据,根据配置文件,将不同topic的数据发送给不同的对象。\nscribe提供了各种各样的store,如 file, HDFS等,scribe可将数据加载到这些store中。\n\n(3) 存储系统\n\n存储系统实际上就是scribe中的store,当前scribe支持非常多的store,包括file(文件),\nbuffer(双层存储,一个主储存,一个副存储),network(另一个scribe服务器),bucket(包含多个\nstore,通过hash的将数据存到不同store中),null(忽略数据),thriftfile(写到一个Thrift\nTFileTransport文件中)和multi(把数据同时存放到不同store中)。\n#+end_example\n*** useful link\n    http://hi.baidu.com/feifeilee/blog/item/26452ffaab9f24384e4aea00.html\\\\\n    Installing Facebook Scribe on Fedora 8【转】_大笨鸟的天空_百度空间\n    http://blog.csdn.net/amuseme_lu/article/details/6328013\\\\\n    Facebook Scribe介绍 - lemo的专栏 - 博客频道 - CSDN.NET\n    https://github.com/facebook/scribe/\n    Scribe - GitHub\n** Chukwa - Apache的日志系统\n*** Chukwa中主要有3种角色,分别为：adaptor,agent,collector。\n    http://dongxicheng.org/search-engine/log-systems/\\\\\n\n(1) Adaptor 数据源\n\n可封装其他数据源,如file,unix命令行工具等\n\n目前可用的数据源有：hadoop logs,应用程序度量数据,系统参数数据(如linux cpu使用流率)。\n\n(2) HDFS 存储系统\n\nChukwa采用了HDFS作为存储系统。HDFS的设计初衷是支持大文件存储和小并发高速写的应用场景,而日志系统的特点恰好相反,它需支持高并发低速率的写和大量小文件的存储。需要注意的是,直接写到HDFS上的小文件是不可见的,直到关闭文件,另外,HDFS不支持文件重新打开。\n\n(3) Collector和Agent\n\n为了克服(2)中的问题,增加了agent和collector阶段。\n\nAgent的作用：给adaptor提供各种服务,包括：启动和关闭adaptor,将数据通过HTTP传递给Collector;定期记录adaptor状态,以便crash后恢复。\n\nCollector的作用：对多个数据源发过来的数据进行合并,然后加载到HDFS中;隐藏HDFS实现的细节,如,HDFS版本更换后,只需修改collector即可。\n\n(4) Demux和achieving\n\n直接支持利用MapReduce处理数据。它内置了两个mapreduce作业,分别用于获取data和将data转化为结构化的log。存储到data store(可以是数据库或者HDFS等)中。\n** LinkedIn的Kafka\n#+begin_example\nKafka是2010年12月份开源的项目,采用scala语言编写,使用了多种效率优化机制,整体架构比较新颖(push/pull),更适合异构集群。\n\nKafka实际上是一个消息发布订阅系统。 producer向某个topic发布消息,而consumer订阅某个topic的消息,进而一旦有新的关于某个topic的消息,broker会传递给订阅它的所有consumer。\n\n使用了zookeeper进行负载均衡。\n\n在Kafka上,有两个原因可能导致低效：1)太多的网络请求 2)过多的字节拷贝。\n#+end_example\n*** 设计目标\n(1)数据在磁盘上存取代价为O(1)。一般数据在磁盘上是使用BTree存储的,存取代价为O(lgn)。\n\n(2)高吞吐率。即使在普通的节点上每秒钟也能处理成百上千的message。\n\n(3)显式分布式,即所有的producer、broker和consumer都会有多个,均为分布式的。\n\n(4)支持数据并行加载到Hadoop中。\n*** Kafka中主要有三种角色,分别为producer,broker和consumer。\n#+begin_example\n    http://dongxicheng.org/search-engine/log-systems/\\\\\n\n(1) Producer\n\nProducer的任务是向broker发送数据。Kafka提供了两种producer接口,一种是low_level接口,使用该接口会向特定的broker的某个topic下的某个partition发送数据;另一种那个是high level接口,该接口支持同步/异步发送数据,基于zookeeper的broker自动识别和负载均衡(基于Partitioner)。\n\n其中,基于zookeeper的broker自动识别值得一说。producer可以通过zookeeper获取可用的broker列表,也可以在zookeeper中注册listener,该listener在以下情况下会被唤醒：\n\na．添加一个broker\n\nb．删除一个broker\n\nc．注册新的topic\n\nd．broker注册已存在的topic\n\n当producer得知以上时间时,可根据需要采取一定的行动。\n\n(2) Broker\n\nBroker采取了多种策略提高数据处理效率,包括sendfile和zero copy等技术。\n\n(3) Consumer\n\nconsumer的作用是将日志信息加载到中央存储系统上。kafka提供了两种consumer接口,一种是low level的,它维护到某一个broker的连接,并且这个连接是无状态的,即,每次从broker上pull数据时,都要告诉broker数据的偏移量。另一种是high-level 接口,它隐藏了broker的细节,允许consumer从broker上push数据而不必关心网络拓扑结构。更重要的是,对于大部分日志系统而言,consumer已经获取的数据信息都由broker保存,而在kafka中,由consumer自己维护所取数据信息。\n#+end_example\n*** useful link\n    http://dongxicheng.org/search-engine/kafka/\\\\\n    消息系统Kafka介绍 | 董的博客\n** Cloudera的Flume\n#+begin_example\n   http://dongxicheng.org/search-engine/log-systems/\\\\\n\nFlume是cloudera于2009年7月开源的日志系统。它内置的各种组件非常齐全,用户几乎不必进行任何额外开发即可使用。\n\nFlume提供了三种级别的可靠性保障,从强到弱依次分别为：end-to-end(收到数据agent首先将event写到磁盘上,当数据传送成功后,再删除;如果数据发送失败,可以重新发送。),Store on failure(这也是scribe采用的策略,当数据接收方crash时,将数据写到本地,待恢复后,继续发送),Best effort(数据发送到接收方后,不会进行确认)。\n#+end_example\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdennyzhang%2Fchallenges-k8s-logging","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdennyzhang%2Fchallenges-k8s-logging","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdennyzhang%2Fchallenges-k8s-logging/lists"}