图12012年以前,携程的各个部门日志自行收集治理(如图1)。这样的方式缺乏统一标准,不便治理管控,也更加消耗人力和物力。从2012年开始,携程技术中心推出基于 ElasticSearch 的日志系统,统一了日志的接入、ETL、存储和查询标准。随着业务量的增长,数据量膨胀到 4PB 级别,给原来的 ElasticSearch 存储方案带来不少挑战,如 OOM、数据延迟及负载不均等。此外,随着集群规模的扩大,成本问题日趋敏感,如何节省成本也成为一个新的难题。2020年初,我们提出用 Clickhouse 作为主要存储引擎来替换 ElasticSearch 的方案,该方案极大地解决了 ElasticSearch 集群遇到的性能问题,并且将成本节省为原来的48%。2021年底,日志平台已经累积了20+PB 的数据量,集群也达到了数十个规模(如图2)。2022年开始,我们提出日志统一战略,将公司的 CLOG 及 UBT 业务统一到这套日志系统,预期数据规模将达到 30+PB。同时,经过两年多的大规模应用,日志集群累积了各种各样的运维难题,如集群数量激增、数据迁移不便及表变更异常等。因此,日志3.0应运而生。该方案落地了类分库分表设计、Clickhouse on Kubernetes、统一查询治理层等,聚焦解决了架构和运维上的难题,并实现了携程 CLOG 与 ESLOG 日志平台统一。
图2
图3
图4第二种是用户使用 Filebeat/Logagent/Logstash 或者写程序自行上报数据到 Kafka(如图5),再通过 GoHangout 写入到存储引擎中。
图5
图6
图72.5 数据展示数据展示方面我们使用了 Elastic Stack 家族的 Kibana(如图8)。Kibana 是一款适合于 ElasticSearch 的数据可视化和管理工具,提供实时的直方图、线形图、饼状图和表格等,极大地方便日志数据的展示。
图8
图9
图10Clickhouse采用的是 SQL 的交互方式,非常方便上手。接下来,我们将简单介绍一下 Clickhouse 的类 LSM、排序键、分区键特效,了解 Clickhouse 的主要原理。首先,用户每批写入的数据会根据其排序键进行排序,并写入一个新的文件夹(如201905_1_1_0),我们称为 Part C0(如图10)。随后,Clickhouse 会定期在后台将这些 Part 通过归并排序的方式进行合并排序,使得最终数据生成一个个数据顺序且空间占用较大的 Part。这样的方式从磁盘读写层面上看,能充分地把原先磁盘的随机读写巧妙地转化为顺序读写,大大提升系统的吞吐量和查询效率,同时列式存储+顺序数据的存储方式也为数据压缩率提供了便利。201905_1_1_0与201905_3_3_0合并为201905_1_3_1就是一个经典的例子。另外,Clickhouse 会根据分区键(如按月分区)对数据进行按月分区。05、06月的数据被分为了不同的文件夹,方便快速索引和管理数据。
图11我们看中了 Clickhouse 的列式存储、向量化、高压缩率和高吞吐等特效(如图11),很好地满足了我们当下日志集群对性能稳定性和成本的诉求。于是,我们决定用Clickhouse来替代原本 ElasticSearch 存储引擎的位置。
图12(1)库表设计
图13我们对ck在日志场景落地做了很多细节的优化(如图13),主要体现在库表设计:我们采用双 list 的方式来存储动态变化的 tags(当然最新的版本22.8,也可以用map和新特性的 json 方式)。按天分区和时间排序,用于快速定位日志数据。Tokenbf_v1 布隆过滤用于优化 term 查询、模糊查询。_log_increment_id 全局唯一递增 id,用于滚动翻页和明细数据定位。ZSTD 的数据压缩方式,节省了40%以上的存储成本。(2)Clickhouse 存储设计Clickhouse 集群主要由查询集群、多个数据集群和 Zookeeper 集群组成(如图14)。查询集群由相互独立的节点组成,节点不存储数据是无状态的。数据集群则由Shard组成,每个 Shard 又涵盖了多个副本 Replica。副本之间是主主的关系(不同于常见的主从关系),两个副本都可以用于数据写入,互相同步数据。而副本之间的元数据一致性则有 Zookeeper 集群负责管理。
图14(3)数据展示为了实现用户无感知的存储切换,我们专门实现了 Kibana 对 Clickhouse 数据源的适配并开发了不同的数据 panel(如图15),包括:chhistogram、chhits、chpercentiles、chranges、chstats、chtable、chterms 和 chuniq。通过 Dashboard 脚本批量生产替代的方式,我们快速地实现了原先 ElasticSearch 的 Dashboard 的迁移,其自动化程度达到95%。同时,我们也支持了使用 Grafana 的方式直接配置 SQL 来生成日志看板。

图15(4)集群管理平台为了更好地管理 Clickhouse 集群,我们也做了一整套界面化的 Clickhouse 运维管理平台。该平台覆盖了日常的 shard 管理、节点生成、绑定/解绑、权重修改、DDL 管理和监控告警等治理工具(如图16)。
图16
图17
图18(1)数据跨如何跨集群假设我们有三个数据集群1、2、3和三个表A、B、C(如图18)。在改造之前,我们单张表(如A)只能坐落在一个数据集群1中。这样的设计方式,导致了当集群1磁盘满了之后,我们没有办法快速地将表A数据搬迁到磁盘相对空闲的集群2中。我们只能用双写的方式将表A同时写入到集群1和集群2中,等到集群2的数据经过了TTL时间(如7天)后,才能将表A从数据集群1中删除。这样,对我们的集群运维管理带来了极大的不方便和慢响应,非常耗费人力。于是,我们设计一套类分库分表的架构,来实现表A在多个集群1、2、3之间来回穿梭。我们可以看到右边改造后,表A以时间节点作为分库分表的切换点(这个时间可以是精确到秒,为了好理解,我们这里以月来举例)。我们将6月份的数据写入到集群1、7月写到集群2、8月写到集群3。当查询语句命中6月份数据时,我们只查询集群1的数据;当查询语句命中7月和8月的数据,我们就同时查询集群2和集群3的数据。我们通过建立不同分布式表的方式实现了这个能力(如:分布式表tableA_06/tableA_07/tableA_08/tableA_0708,分布式表上的逻辑集群则是是集群1、2、3的组合)。这样,我们便解决了表跨集群的问题,不同集群间的磁盘使用率也会趋于平衡。(2)如何修改排序键不删除历史数据非常巧妙的是,这种方式不仅能解决磁盘问题。Clickhouse 分布式表的设计只关心列的名称,并不关心本地数据表的排序键设置。基于这种特性,我们设计表A在集群2和集群3使用不一样的排序键。这样的方式也能够有效解决初期表A在集群2排序键设计不合理的问题。我们通过在集群3上重新建立正确的排序键,让其对新数据生效。同时,表A也保留了旧的7月份数据。旧数据会在时间的推移一下被TTL清除,最终数据都使用了正确的排序键。(3)如何解决删除大表字段导致元数据不一致更美妙的是,Clickhouse 的分布式表设计并不要求表A在7月和8月的元数据字段完全一致,只需要有公共部分就可以满足要求。比如表A有在7月有11个字段,8月份想要删除一个弃用的字段,那么只需在集群3上建10个字段的本地表A,而分布式表 tableA_0708 配置两个表共同拥有的10个字段即可(这样查分布式表只要不查被删除的字段就不会报错)。通过这种方式,我们也巧妙地解决了在数据规模特别大的情况下(单表百TB),删除字段导致常见的元数据不一致问题。(4)集群升级同时,这种多版本集群的方式,也能方便地实现集群升级迭代,如直接新建一个集群4来存储所有的09月的表数据。集群4可以是社区最新版本,通过这种迭代的方式逐步实现全部集群的升级。
图19
图20(2)查询代理层
图21我们对所有用户的SQL查询做了一层统一的查询网关代理(如图21)。该程序会根据元数据信息和策略对用户的 SQL 进行改写,实现了精准路由和性能优化等功能。同时,该程序会记录每次查询的明细上下文,用于对集群的查询做统一化治理,如:QPS 限制、大表扫描限制和时间限制等拒绝策略,来提高系统的稳定性。我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co
我正在尝试在Rails上安装ruby,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立