日志系统的设计与实现_阿里云10 PB+/天的日志系统设计和实现

阿里云日志服务提供大规模日志采集、存储、查询及分析能力,支持PB级数据实时索引,广泛应用于问题排查及二次开发。系统设计考虑高可靠性、资源隔离及高效管理等需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

导读:此文系 ArchSummit 全球架构师峰会采访文章,旨在通过阿里优秀的技术实践,为读者提供解决问题的思路启发。本文采访嘉宾是阿里高级技术专家孙廷韬(花名:龙悟),负责阿里云日志服务架构设计和实现。

阿里云日志服务作为阿里集团底层日志平台,提供完善易用的数据采集方案,PB 级数据实时索引和分析能力,在阿里集团被广泛应用。数千工程师直接使用日志服务进行日常问题排查,也有大量应用基于日志服务进行二次开发,如阿里集团所有大型 Trace 系统底层都使用日志服务。

在此背景下,我们邀请了阿里云高级技术专家孙廷韬(花名:龙悟)老师来 7 月深圳 ArchSummit 全球架构师峰会上演讲,他本人重点负责阿里云日志服务架构设计和实现,此次将介绍阿里云 10PB+/ 天日志系统设计和实现的话题。

可以先通过一个大图,看看阿里云日志服务提供的核心功能:

3bbce6480c537ac473fcfbbca3b5b479.png

采集:

  • Logtail: 多年百万级服务器锤炼,简便、可靠、高性能 ;
  • SDK/Producer: Java/C/Go/iOS/Android/web tracking;
  • 全球加速: 集成 DCDN 全球加速

存储 & 消费 :

  • ConsumerGroup: 自动负载均衡、failover、服务端 checkpoint 持久化 ;
  • 生态集成:支持 Blink/Flink/Storm/Spark Streaming 等多种流系统,已对接各类监控系统
  • Shipper:支持 Oss、MaxCompute 数据转存

查询 & 分析:

  • Text、Json、Double、Long;
  • 支持中文,Json 自动展开,全文 / 键值 ;
  • 百亿级规模查询 ;
  • DevOps 场景:上下文、Live Tail、LogReduce、异常检查、预测、根因分析 ;
  • 分析功能:SQL92、交互式查询、机器学习、安全特色函数

可视化

  • 原生 Dashboard、十几种图形展示 ;
  • JDBC 接口,支持 DataV、Grafana、QuickBI 展示。

阿里云生产环境下的日志特点

在生产环境下,阿里云日志有如下特点:

  • 规模大: 每日产生的各类日志超过数十 PB;
  • 种类杂:包含各类访问日志、系统日志、应用日志等各类日志,种类繁多,格式复杂 ;
  • 来源多:服务器端、网络设备、嵌入式、web 端、Docker、移动 app 多种数据源实时产生数据 ;
  • 应用广:各条业务线对于日志的使用需求广泛,如监控报警、问题诊断、数据分析和深入挖掘、报表等各类场景,因此使用和消费模式也会多种多样 ;
  • 要求高:对于系统的稳定、可用性都有非常苛刻的要求,以满足关键业务的需求 ;
  • 峰值大:在双十一等活动,舜时会产生大量日志,如何应对这样的峰值,也是很大的挑战。

日志服务通过构建统一的系统,来解决不同用户在日志的采集、存储、查询和分析上的一些通用需求,简化用户使用日志的复杂度,使得用户能够更专注于日志数据价值的挖掘。

阿里云日志系统核心功能

针对阿里云的日志特点,日志系统需要满足以下这些条件:

  • 高可靠性:对于一些日志数据不落地的场景,如果后端服务不可用,很可能导致数据丢失 ;
  • 资源隔离:能够提供良好的 QOS,不因个别用户的异常,影响其他用户 ;
  • 高性价比:针对日志的一些特性,进行系统优化,尽可能降低处理海量数据的成本,如每天采集、存储、索引 1PB 日志,机器资源消耗最大能降低到多少 ;
  • 管理能力:如何管理百万级客户端的,如何快速发现、定位日志采集过程的异常;如何进行版本的维护升级 ;
  • 快速查询分析:在海量日志中,进行快速的查询和分析,及时返回结果给用户。

日志系统的设计

阿里云日志系统主要有以下模块:

  • 负责采集数据的客户端 Agent;
  • 提供 Resutful API 接口的前端模块 ;
  • 进行数据存储和索引的模块 ;
  • 查询分析模块 ;
  • 负责 Meta 信息管理模块 ;
  • 负责监控、运维的管理模块

在日志系统的设计过程中遇到的主要挑战有:

  1. 如何在性能、成本之间如何进行平衡以及取舍。现有硬件条件下, 每 GB SSD 磁盘的价格是普通 HDD 的 5 倍,在每日数十 PB 写入量的情况下,全部使用 SSD 磁盘,成本不可接受,但是 HDD 的磁盘读取延时、吞吐能力要比 SSD 差不少,在受限硬件条件下,如何满足海量数据的查询需求?针对这个苛刻的成本和性能问题,我们团队根据日志场景的特点,从 0 开始打造了一款专门为日志数据存储和索引的分布式引擎:
  2. a. 在倒排索引字典上,使用 succinct tree 进行编码,字典只有 FST 结构的 40~70%
  3. b. 倒排索引数据使用自研的混合 Bitmap 结构,可以直接在 encoding 后 Bitmap 上进行 and、not、or 操作,无需对 bitmap 进行反序列化
  4. c. 使用改进的 BKD-Tree 对数值进行索引,配合高效的压缩算法,读写速度是开源版本的 1.4~2 倍,压缩率提高 50%,部分 distinct 值个数较少场景压缩率提高 10 倍;
  5. d. 大量使用 SIMD 指令来提高数值压缩、解压速度。
  6. 在大规模分布式集群,如何打造 always available 的服务。系统要有良好的抗压和异常自我恢复能力,在各种高压情况下(如应用出错、代码 bug 等情况,流量可能成百、上千倍放大),系统要通过自身技术手段,自动、快速、准确定位异常流量,拦截在系统最外层,保证内部不被打垮。在分布式系统中,软硬件的异常时常发生,系统需要能进行自动迁移和隔离,最终保障系统的可用性。同时,为了最大程度提高资源使用效率,我们采用多租户共享集群资源的方式,但是应用场景多样,每个应用对日志使用模式并不相同,资源的消耗也有差异,例如,部分应用查询分析特别频繁,属于 CPU 密集型;部分应用流量特别大,是网络密集型;部分应用则周期性出现峰值等。如何在有限的资源下,提供良好的 QOS,满足各应用需求的同时,提高资源使用效率,也是一个不小挑战。
  7. 如何挖掘日志特性,设计适合日志数据的存储和索引结构,使其能在十 亿、百亿级场景下,进行快速查询分析。在阿里的场景下,单一应用每天产生上百 TB 日志是很常见,单次查询,覆盖十亿、百亿行日志也是是一个非常普遍的情况。在这样的规模下,如何进行加速,在设计上有不小挑战,分布式查询是一个必选项,一次查询可能会在数百节点之间同时进行。我们在设计时候,通过尽可能减少节点之间数据交互量;采用多层 Cache 结构,来复用索引、原始数据、临时计算结果;使用协程进行计算、IO 分离等;智能调节数后台索引 Compaction 速度等多种方式,来实现超大规模快速查询分析。
  8. 可靠、高效管理数百万台服务器的采集配置也是一个难点。特别是在双十一等特殊时期,需要系统能进行精准、快速的流控,确保高优先级数据及时采集,低优先级任务不因过多资源消耗而影响业务性能。为此,我们设计前端采集 Agent 和后端管理模块时,加入一套可靠的管理协议,所有的配置可以在控制台进行操作,由后端管理模块同步前端采集 Agent,无需登陆机器进行配置管理。同时,在双十一等特殊时期,可以动态修改每个日志源不同的采集上限,进行优先级控制。

日志系统的稳定性如何保障

关于日志系统的稳定性,所有的模块需要做到可以水平扩展。无论是接收流量的前端模块,数据存储索引和查询模块,或是管理百万服务器配置管理模块,都需要做到水平扩展,才能撑起每日数十 PB 的日志量。

异常流量和请求在前端模块被拦截,防止穿透至后端。我们在设计系统的时候,为每个模块定义了标准处理能力,如负责数据索引的模块,确定每个 shard 读写能力标准,当实际流量超过标准,机器在还有富余资源时,会继续提供服务,而资源不够,并且 shard 未开启自动分裂的情况下,触发限流操作,系统内部的反馈机制,能够在毫秒级别延时内,将该 shard 流控信息,同步到所有上千个前端进程,各前端在一定时间内,可直接拒绝该 shard 流量。通过这样的机制,异常流量在系统最前端被拦截,防止后端单点被打爆,经线上实测,穿透到后端的异常流量只有正常流量的 1%~3%。

模块内部进行自动调度和负载均衡。系统内部,会实时统计各应用日志的流量和资源消耗,进行中心汇总,系统在分钟级别可发现集群中存在的热点和类型,并确定导致热点的日志源,根据热点的类型,匹配合适的迁移目标,将热点流量迁移至可以到合适的机器上,进行资源消耗互补。

资源隔离,自动根据负载调节资源使用限制。日志场景下,数据都带有时间信息,在进行日志查询和分析的时候,也限定了时间窗口。每次查询,后端根据当前负载以及应用之前资源消耗等信息,限定这次查询执行并发数、磁盘读取量、执行时间、内存消耗等资源上限,查询的中间结果被缓存在内存中,后续查询可复用 cache 中的结果加快查询速度。

完善的监控体系。监控对于一个系统来说至关重要,我们在覆盖系统的关键指标、硬件状态、外部访问监控的基础上,也使用系统自身提供的异常检查功能进行对自己进行异常检查。

日志数据的处理

在 Sec/Dev/IT Ops 领域,日志数据发挥了重要的作用,主要包括以下几个方面:

d52f3f7e94b93e95b3ff0af4d00e78f6.png
  • 实时查询和分析:日志服务本身提供海量日志实时检索和 SQL 分析、上下文查询(Context),实时 Tail(Live Tail)、日志数据智能聚类 (LogReduce)、异常检查和根因分析等能力,用户可直接在日志服务上进行问题排查、异常定位、深入挖掘日志数据价值 ;
  • 可视化分析:通过自定义画布 (Canvas),配合数十种图形和 Drill down/Roll up,非常方便地构建交互式可视分析仪表盘,数据所见即所得 ;
  • 告警:日志服务原生提供日志分析结果告警功能,对于告警消息的投递,除了传统的短信、邮件外,也支持 webhook,如投递给钉钉机器人,或自定义链接进行自动报警处理逻辑触发 ;
  • 二次开发:不少团队基于日志服务,根据其业务特点进行二次开发,如各类 Tracing 系统、客服系统等。

日志系统和其他系统的对接

下图展示了阿里云日志系统可以跟哪些系统对接:

60b1a9a992de3a985261f56b2a4fd95e.png
  • 各类流式系统:Flink/Blink, Storm (JStorm),Spark Streaming。日志服务提供各流式系统提供日志消费消费 lib,屏蔽数据拉取、checkpoint 保存、failover 等细节,只需关注数据流的处理逻辑即可,简化各类流系统实时消费日志的复杂度,完成数据实时 ETL、监控等场景 ;
  • 离线系统:对数据有更深入分析的场景,如用户画像、关联分析等场景,可以使用日志服务的归档功能,将数据保留至阿里云对象存储 (OSS), 或 MaxCompute 这样的系统,进行后续分析 ;
  • DataWorks: 对数据外部存储还有更多需求的用户,可以使用 DataWorks 实时消费日志日志,导入到各类其他系统,如 MySQL 等数据库 ;
  • Serverless:对于不想自己运维流式系统,但是又有自定义分析需求的场景,也可以使用 Serverless 的模式来消费日志,如阿里云函数计算 FC,只需要编写日志处理函数,运行由函数计算进行托管。
26792056722674c6697343c7e0dafd11.gif
8152eaa4772d6f0545564d48f54c77e9.png
#include "stm32f10x.h" #include "mqtt_demo.h" #include "led.h" #include "mqtt.h" #include "led.h" #include "delay.h" #include "debug.h" #include "dht11.h" #include "BH1750.h" #include "esp8266_uart.h" #include "oled.h" #include "sg90.h" //FC-28土壤湿度******************************************************************************************* void AD_Init(void); uint16_t AD_GetValue(void); uint16_t GetHumidity(int times); /** ****************************************************************************** * @file 基于嵌入式的花卉环境监测系统的设计实现 * @author LGW * @version V1.0 * @date 2025-03-01 * @brief 光照传感器bh1750 * SCL ---- PA0 * SDA ---- PA1 * @brief 土壤湿度传感器fc-28 * AO ----- PB0 * @brief 温湿度传感器 * OUT ---- PB1 * @brief esp8266 * TX ---- PA3 * RX ---- PA2 * @brief 风扇 PC13 * @brief 水泵 PC14 * @brief 补光灯 PC15 * @brief OLED * SCL ---- PB10 * SDA ---- PB11 ****************************************************************************** **/ int main() { u8 temp; u8 humi; float light; uint32_t heartbeat_tick = 0; uint32_t post_tick = 0,turangshidu = 0; char str_Humidity[10],str_turangshidu[10]; // 字符数组,用于存储字符串 char str_light[10],str_guangzhao[10]; char str_dht11_temp[10],str_kongqiwendu[10]; char str_dht11_Hum[10],str_kongqishidu[10]; char result[50]; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设定优先级分组为2 SysTick_Init(); IO_Init(); Debug_init(); esp8266_uart_init(); Init_BH1750(); TIM1_PWM_Init(); while(1) { openlock(); ESP_delay_ms(1000); ESP_delay_ms(1000); ESP_delay_ms(1000); } // while (Esp8266_Init()) // 配置WiFi以STA联网模式工作 // { // } // while (Mqtt_Connect_Aliyun()) // 配置MQTT链接阿里云 // { // } while(DHT11_Init()) { printf("DHT11 Error \r\n"); delay_ms(1000); } while (1) { if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12) == 0) { GPIO_ResetBits(GPIOC, GPIO_Pin_13); mqtt_publish_data(MQTT_PUBLISH_TOPIC, "D1" , 0); // 上报信息到平台服务器send_data } else { GPIO_SetBits(GPIOC, GPIO_Pin_13); } printf("报警:%d\r\n",GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)); DHT11_Read_Data(&temp,&humi); light=read_BH1750(); //读取BH1750的光强数据 printf("温度:%d\r\n",temp); printf("湿度:%d\r\n",humi); printf("光照:%f\r\n",light); printf("\r\n\n"); if(shoudong_sta == 0) { if(temp > 30) { // GPIO_ResetBits(GPIOC,GPIO_Pin_13);// 输出低电平 风扇开 } else { // GPIO_SetBits(GPIOC, GPIO_Pin_13); // 输出高电平 风扇关 } if(humi > 30) { // GPIO_ResetBits(GPIOC,GPIO_Pin_13);// 输出低电平 加湿器开 } else { // GPIO_SetBits(GPIOC, GPIO_Pin_13); // 输出高电平 加湿器关 } if(light > 100) GPIO_SetBits(GPIOC, GPIO_Pin_15); // 输出高电平 遮阳开 else GPIO_ResetBits(GPIOC,GPIO_Pin_15);// 输出低电平 遮阳关 } // ESP_printf("light:%f\r\n",light); mqtt_msg_handle(); // 处理阿里云下发数据,云端数据处理!!! // 每隔5分钟上传设备状态 if ((ESP_GET_TICK() - post_tick) / 1000 >= 5) { post_tick = ESP_GET_TICK(); // mqtt_report_devices_status(); // 上报开发板设备状态到云端 memset(result, 0, sizeof(result)); // 清空 result 数组 snprintf(str_light, sizeof(str_light), "A%d", (unsigned int)light);//将光照强度转为字符串并在字符串前加标识符“A” snprintf(str_dht11_temp, sizeof(str_dht11_temp), "B%d", temp);//将空气温度转为字符串并在字符串前加标识符“C” snprintf(str_dht11_Hum, sizeof(str_dht11_Hum), "C%d", humi);//将空气湿度转为字符串并在字符串前加标识符“D” strcat(result, str_light); strcat(result, str_dht11_temp); strcat(result, str_dht11_Hum); mqtt_publish_data(MQTT_PUBLISH_TOPIC, result , 0); // 上报信息到平台服务器send_data } // 每隔60秒发送心跳包 if ((ESP_GET_TICK() - heartbeat_tick) / 1000 >= 60) { heartbeat_tick = ESP_GET_TICK(); /* 设备端在保活时间间隔内(保护时间在mqtt_connect设置为60s),至少需要发送一次报文,包括ping请求。 连接保活时间的取值范围为30秒~1200秒。建议取值300秒以上。 从物联网平台发送CONNACK响应CONNECT消息时,开始心跳计时。收到PUBLISH、SUBSCRIBE、PING或 PUBACK消息时,会重置计时器。 */ // 发送心跳包,过于频繁发送心跳包,服务器将会持续一段时间不发送响应信息[可选] if (!mqtt_send_heart()) { ESP_delay_ms(200); } else { // 如果断开热点,则重新配置WiFi模块连接热点 while (Esp8266_Init()) ; // 如果断开阿里云,则重新配置MQTT链接阿里云 while (Mqtt_Connect_Aliyun()) ; } } ESP_delay_ms(500); } } 这个程序的openlock();执行后舵机无反应,/***************STM32F103C8T6********************** * 文件名 :main.c * 描述 : 舵机测试 * 实验平台:STM32F103C8T6 * 备注 :使用定时器来产生pwm波,控制舵机动作 * 接口 :TIM1, CH1-PB13, CH2-PB14, CH3-PB15 ****************STM32F103C8T6**********************/ #include "sg90.h" #include "delay.h" /* 配置TIM1复用输出PWM时用到的I/O */ static void TIM1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//定时器1时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//GPIOB时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } /*配置TIM1输出的PWM信号的模式,如周期、极性、占空比 */ static void TIM1_Mode_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; /* PWM信号电平跳变值 */ u16 CCR1_Val = 0; u16 CCR2_Val = 0; //u16 CCR3_Val = 50000; /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = 20000 - 1;//定时器周期,20ms TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;//时钟预分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数方式:向上计数 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); /* PWM1 Mode configuration: Channel1 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//选择定时器模式:tim脉宽调制2 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR1_Val; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//极性 TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;//开反向通道 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); /* PWM1 Mode configuration: Channel2 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR2_Val; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;//开反向通道 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; TIM_OC2Init(TIM1, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable); /* PWM1 Mode configuration: Channel3 */ /* TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR3_Val; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;//开反向通道 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; TIM_OC3Init(TIM1, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); */ TIM_ARRPreloadConfig(TIM1, ENABLE); /* TIM1 enable counter */ TIM_Cmd(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); } /*配置初始化TIM1 */ void TIM1_PWM_Init(void) { TIM1_GPIO_Config(); TIM1_Mode_Config(); } //舵机摆动 void Servo_out_0 (void) { TIM1->CCR1 = 500;//pwm波高电平持续时间,2ms } void Servo_out_1 (void) { TIM1->CCR1 = 1500;//pwm波高电平持续时间,2ms } void openlock(void) { Servo_out_1(); delay_ms(1000); delay_ms(1000); delay_ms(1000); delay_ms(1000); delay_ms(1000); Servo_out_0(); }
最新发布
05-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值