为了公平对比,ElasticSearch仓库在同一个月有惊人的1076个合并PR,同时在功能性方面,它的节奏也非常让人印象深刻!我们正在将 Clickhouse 用于 ApiRoad.net 项目(这是一个 API 市场,开发人员出售其 API ,目前活跃开发中)的日志存储和分析,到目前为止,我们对效果感到满意。作为一名 API 开发人员, HTTP 请求/响应周期的可观察性和可分析性对于维护服务质量和快速发现 bug 非常重要,这一点对于纯 API 服务尤其如此。
我们也在其他项目上使用 ELK( ElasticSearch,Logstash,filebeat,Kibana)技术栈用于同样目的:获取 HTTP 和邮件日志,使用 Kibana 进行事后的分析与搜索。当然,我们也无处不在的使用 MySQL !这篇文章主要介绍我们选择 Clickhouse 而不是 ElasticSearch(或 MySQL )作为基础数据(服务请求日志)存储解决方案的主要原因(说明:出于 OLTP的目的,我们仍会处使用 MySQL)。
在很多情况下,PostgreSQL 的 generate_series() 功能很有用。来自 ApiRoad 的一个具体示例:我们需要在chart.js 时间轴上映射请求数量。每天进行常规的SELECT .. group by day,但如果某些天没有任何查询时,就会出现间隙。但我们并不想要间隙,因此需要补零,对吧?这正是 PostgreSQL 中 generate_series() 函数有用的地方。在 MySQL 中,推荐按日期创建表并进行连接,不太优雅了吧?如下是 ElasticSearch 中如何解决:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html#_missing_value_2关于查询语言:我对 ElasticSearch 的 Lucene 语法、HTTP API 以及为检索数据而编写 json 等几个方面仍然不满意。而 SQL 将是我的首选。这是 Clickhouse 用于日期差填充时的解决方案:
SELECT a.timePeriod as t, b.count as c from (with (select toUInt32(dateDiff('day', [START_DATE], [END_DATE])) ) as diffInTimeUnitsselect arrayJoin(arrayMap(x -> (toDate(addDays([START_DATE], x))), range(0, diffInTimeUnits+1))) as timePeriod ) aLEFTJOIN (selectcount(*) ascount, toDate(toStartOfDay(started_at)) as timePeriod fromlogsWHERE [CONDITIONS]GROUPBY toStartOfDay(started_at)) b on a.timePeriod=b.timePeriod
在这里,我们通过 lambda 函数和循环生成一个虚拟表,然后再与按天分组的日志表进行左连接。我认为 arrayJoin + arrayMap + range 函数方式相比 generate_series() 有更多灵活性。通过WITH FILL 关键词可用于更简洁的语法。
SELECTcount(*) as cnt, quantileTiming(0.5)(duration) as duration_median, quantileTiming(0.9)(duration) as duration_90th, quantileTiming(0.99)(duration) as duration_99thFROMlogsWHEREstatus=404
这里要注意 quantileTiming 函数的用法以及如何优雅地使用currying。Clickhouse 具有通用的分位数 quantile 函数!但是 quantileTiming 已针对序列化数据进行了优化,比如加载网页时间或后端响应时间的日志.还有更多类似的,需要加权算术平均数吗?要计算线性回归吗?这很容易,只需使用专门的函数就可以。这是 Clickhouse 相关统计函数的完整列表:https://clickhouse.tech/docs/en/sql-reference/aggregate-functions/reference/这些大部分在 MySQL 中都是有问题的。ElasticSearch 在这方面比 MySQL 好得多,它既具有分位数又具有加权中位数,但是它还没有线性回归。
五、MySQL 和 Clickhouse 紧密结合
MySQL 和 Clickhouse 有多种级别的相互集成,这使它们最小化数据重复的情况下非常方便在一起使用: