clickhouse如何解决GLIBC不兼容问题--终篇

简介: clickhouse如何解决GLIBC不兼容问题--终篇

共享库与binary文件打包的副作用


test_getaddrinfo.cpp

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
int main()
{
  struct addrinfo hints;
  struct addrinfo *res;
  memset(&hints, 0, sizeof hints);                                         
  hints.ai_flags = 1024;
  hints.ai_family = 0;
  hints.ai_socktype = 1;
  hints.ai_protocol = 6; 
  hints.ai_addrlen = 0;
  hints.ai_addr = 0x0; 
  hints.ai_canonname = 0x0; 
  hints.ai_next = 0x0;
  int err = ::getaddrinfo("localhost", "8000", &hints, &res);
  printf("%d", err);
  return 0;
}

按照上一篇文章 中的方法,我们在ubuntu20环境中编译test_getaddrinfo.cpp文件,连同其依赖的共享库一块打包部署到ubuntu16环境,具体步骤如下


  • u20环境中,依次进行编译、复制共享库、修改ELF信息等操作
$ g++ test_getaddrinfo.cpp  -o test_getaddrinfo
$ ldd ./test_getaddrinfo                                        
  linux-vdso.so.1 (0x00007ffc539ea000)
  libc.so.6 => /usr/lib/x86_64-linux-gnu/libc.so.6 (0x00007fc38ae95000)
  /lib64/ld-linux-x86-64.so.2 (0x00007fc38b08e000)
$ copylib.sh ./test_getaddrinfo
$ patchelf --set-rpath  /home/liyang/lib  test_getaddrinfo
$ patchelf --set-interpreter /home/liyang/lib/ld-linux-x86-64.so.2 test_getaddrinfo
  • 将get_getaddrinfo连同lib文件一块复制到u16运行环境中。


  • 在u16环境中运行test_getaddrinfo, 可以看到程序异常, 因为::getaddrinfo返回的不是零
$ ./test_getaddrinfo 
-11

那么问题在哪里呢?作为对照组,我们直接在u16环境中编译运行test_getaddrinfo.cpp文件,返回为零。


分别strace这两个binary的运行过程,左右分别对应u16和u20编译的bianry。可以看到右边会多加载很多.so文件,而这些.so文件并不能通过copylib工具打包。个人猜想这个原因导致了test_getaddrinfo运行时没有彻底去除对u20内核的依赖,进而导致::getaddrinfo返回异常。


image.png

新方案


原因分析


有了上面这个bad case, 随binary打包lib的方案显然是走不通了。我们回溯到最初是的问题:u20编译的clickhouse, 在u16环境下启动时会报错:version GLIBC_2.27 not found


我们看看u16支持哪些GLIBC版本? 2.27确实不在u16支持之列

$ strings /lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC_ 
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_2.13
GLIBC_2.14
GLIBC_2.15
GLIBC_2.16
GLIBC_2.17
GLIBC_2.18
GLIBC_2.22
GLIBC_2.23
GLIBC_PRIVATE

那clickhouse中glibc 2.27到底是哪个动态库引入的呢?

$ objdump -x ./clickhouse
Version References:
  required from libdl.so.2:
    0x09691a75 0x00 02 GLIBC_2.2.5
  required from libpthread.so.0:
    0x09691a75 0x00 03 GLIBC_2.2.5
    0x09691974 0x00 04 GLIBC_2.3.4
  required from libm.so.6:
    0x09691a75 0x00 05 GLIBC_2.2.5
    0x06969187 0x00 06 GLIBC_2.27

libm库与数学计算相关,那么到底其中哪个symbol依赖了glibc 2.27呢?

$ readelf -s clickhouse | grep  "GLIBC_2.27"
   148: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND powf@GLIBC_2.27 (3)

原来是powf函数引入了对GLIBC的依赖。联想到clickhouse中有一个模块专门处理glibc不兼容问题

base/glibc-compatibility/glibc-compatibility.c

/** Allows to build programs with libc 2.27 and run on systems with at least libc 2.4,
  *  such as Ubuntu Hardy or CentOS 5.
  *
  * Also look at http://www.lightofdawn.org/wiki/wiki.cgi/NewAppsOnOldGlibc
  */

base/glibc-compatibility如何解决不兼容问题呢?原理很简单,重新override clickhouse依赖的glibc函数即可。但是clickhouse 20.3版本的base/glibc-compatibility中并没有override powf函数,因此编译ck时就依赖了u20本地的libm共享库, 也就引入了GLIBC 2.27的依赖。


解决方案


原因明确之后,解决方案便一目了然了:在base/glibc-compatibility中override powf的实现,好在clickhouse最新版中已经override了powf, 直接将相关代码copy过来重新编译即可。

image.png

我们验证override powf之后的clickhouse binary是否还依赖GLIBC 2.27?

$ objdump -x ./clickhouse | grep "GLIBC_2.27"
$ readelf -s  clickhouse  | grep powf
372223: 0000000028bb549c   727 FUNC    GLOBAL DEFAULT   15 powf
460362: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS powf.c
460380: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS powf_data.c
460381: 00000000124f7900   296 OBJECT  LOCAL  HIDDEN    11 __powf_log2_data
1274523: 0000000028bb549c   727 FUNC    GLOBAL DEFAULT   15 powf

clickhouse中的symbol: powf已经不依赖GLIBC_2.27了。


总结


在本文中我们首先证明了文章中的方案对于clickhouse行不通,然后分析了clickhouse为何会引入GLIBC 2.27的依赖,最后我们通过在base/glibc-compatibility中补全对powf的override,彻底解决了GLIBC <=2.27时兼容性问题。


顺便一提,社区最近的一个PR 已经实现了Hermetic builds, 使得编译clickhouse时只依赖clickhouse中的libc库,彻底去除了对编译环境中libc的依赖,从根本上解决了GLIBC > 2.27时的兼容性问题。到此不由感叹clickhouse真是一个宝藏社区,在各种工程细节上做到了极致,我们想到的想不到的问题他们都有解决,或是在解决的路上。



相关文章
|
Ubuntu 开发工具 C语言
clickhouse如何解决GLIBC不兼容问题
clickhouse如何解决GLIBC不兼容问题
417 0
|
2月前
|
存储 关系型数据库 MySQL
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB区别,适用场景
一个项目用5款数据库?MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景比较
|
3天前
|
SQL Unix OLAP
ClickHouse安装教程:开启你的列式数据库之旅
ClickHouse 是一个高性能的列式数据库管理系统,适用于在线分析处理(OLAP)。本文介绍了 ClickHouse 的基本使用步骤,包括下载二进制文件、安装应用、启动服务器和客户端、创建表、插入数据以及查询新表。还提到了图形客户端 DBeaver 的使用,使操作更加直观。通过这些步骤,用户可以快速上手并利用 ClickHouse 的强大性能进行数据分析。
23 4
|
2月前
|
存储 分布式计算 数据库
阿里云国际版设置数据库云分析工作负载的 ClickHouse 版
阿里云国际版设置数据库云分析工作负载的 ClickHouse 版
|
3月前
|
存储 SQL 缓存
数据库测试|Elasticsearch和ClickHouse的对决
由于目前市场上主流的数据库有许多,这次我们选择其中一个比较典型的Elasticsearch来和ClickHouse做一次实战测试,让大家更直观地看到真实的比对数据,从而对这两个数据库有更深入的了解,也就能理解为什么我们会选择ClickHouse。
数据库测试|Elasticsearch和ClickHouse的对决
|
2月前
|
存储 关系型数据库 MySQL
四种数据库对比MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景
四种数据库对比 MySQL、PostgreSQL、ClickHouse、MongoDB——特点、性能、扩展性、安全性、适用场景
|
6月前
|
DataWorks API 调度
DataWorks产品使用合集之在调度配置配置了节点的上游节点输出,没办法自动生成这个flow的依赖,该怎么操作
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
6月前
|
DataWorks 安全 关系型数据库
DataWorks产品使用合集之建了 polar 与clickhouse的数据源。为什么数据库这里总是mysql呢
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
5月前
|
存储 大数据 关系型数据库
从 ClickHouse 到阿里云数据库 SelectDB 内核 Apache Doris:快成物流的数智化货运应用实践
目前已经部署在 2 套生产集群,存储数据总量达百亿规模,覆盖实时数仓、BI 多维分析、用户画像、货运轨迹信息系统等业务场景。
|
6月前
|
存储 SQL 运维
OLAP数据库选型指南:Doris与ClickHouse的深入对比与分析
OLAP数据库选型指南:Doris与ClickHouse的深入对比与分析

热门文章

最新文章