ClickHouse 构建入门指南
ClickHouse 可以在 Linux、FreeBSD 和 macOS 上构建。如果您使用 Windows,您仍然可以在运行 Linux 的虚拟机中构建 ClickHouse,例如使用 Ubuntu 的 VirtualBox。
ClickHouse 编译和运行需要 64 位系统,32 位系统无法使用。
在 GitHub 上创建仓库
要开始为 ClickHouse 开发,您需要一个 GitHub 账户。请在本地生成一个 SSH 密钥(如果您还没有的话),并将公钥上传到 GitHub,因为这是贡献补丁的先决条件。
接下来,通过点击右上角的“fork”按钮,在您的个人账户中创建 ClickHouse 仓库 的分支。
要进行贡献,例如修复问题或添加功能,请将您的更改提交到您分支中的一个分支,然后创建一个包含更改的“pull request”到主仓库。
要使用 Git 仓库,请安装 git
。在 Ubuntu 中,在终端中运行以下命令
sudo apt update
sudo apt install git
Git 使用速查表可以在这里找到 这里。Git 的详细手册可以在这里找到 这里。
将仓库克隆到您的开发机器
首先,将源文件下载到您的工作机器,即克隆仓库
git clone [email protected]:your_github_username/ClickHouse.git # replace placeholder with your GitHub user name
cd ClickHouse
此命令创建一个包含 ClickHouse 源代码的 ClickHouse/
目录。如果您在 URL 后指定了自定义检出目录,但重要的是此路径不包含空格,因为这可能会导致以后构建出现问题。
ClickHouse 仓库使用 Git 子模块,即对外部仓库的引用(通常是 ClickHouse 使用的第三方库)。默认情况下不会检出这些库。若要检出,您可以
使用
--recurse-submodules
选项运行git clone
,如果
git clone
没有检出子模块,运行git submodule update --init --jobs <N>
(例如<N> = 12
以并行检出)以达到与前一个选项相同的效果,或者如果
git clone
没有检出子模块,并且您想使用 稀疏 和 浅层 子模块检出以省略子模块中不需要的文件和历史记录以节省空间(大约 5 GB 而不是大约 15 GB),运行./contrib/update-submodules.sh
。不建议这样做,因为它通常会使使用子模块变得不太方便且速度更慢。
您可以使用以下命令检查 Git 状态:git submodule status
。
如果您收到以下错误消息
Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
这通常意味着缺少用于连接到 GitHub 的 SSH 密钥。这些密钥通常位于 ~/.ssh
中。为了使 SSH 密钥被接受,您需要将它们上传到 GitHub 的设置中。
您也可以通过 https 协议克隆仓库
git clone --recursive --shallow-submodules https://github.com/ClickHouse/ClickHouse.git
但是,这将不允许您将更改发送到服务器。您仍然可以临时使用它,并在稍后添加 SSH 密钥,用 git remote
命令替换仓库的远程地址。
您还可以将原始 ClickHouse 仓库地址添加到您的本地仓库,以便从那里拉取更新
git remote add upstream [email protected]:ClickHouse/ClickHouse.git
成功运行此命令后,您将能够通过运行 git pull upstream master
从主 ClickHouse 仓库拉取更新。
以下说明假设您在 Linux 上构建。如果您正在交叉编译或在 macOS 上构建,请检查特定于操作系统和体系结构的指南,例如在 macOS 上为 macOS 构建、Linux 上为 macOS 构建、Linux 上为 Linux/RISC-V 构建、Linux 上为 Linux/LoongArch 构建 等。
构建系统
ClickHouse 使用 CMake 和 Ninja 进行构建。
CMake - 一个元构建系统,可以生成 Ninja 文件(构建任务)。
Ninja - 一个较小的构建系统,专注于用于执行这些 cmake 生成的任务的速度。
ccache - 一个编译器缓存。它通过缓存以前的编译并检测何时再次执行相同的编译来加快重新编译速度。
作为 ccache 的替代方案,可以使用分布式的 sccache。若要使用它,应使用 -DCOMPILER_CACHE=sccache
CMake 标志。
要在 Ubuntu、Debian 或 Mint 上安装,请运行 sudo apt install cmake ninja-build ccache
。
在 CentOS、RedHat 上运行 sudo yum install cmake ninja-build ccache
。
如果您使用 Arch 或 Gentoo,您可能自己知道如何安装 CMake 和其他工具。
C++ 编译器
从版本 16 开始,支持使用 Clang 编译器构建 ClickHouse。
应使用 Clang 而不是 gcc。不过,我们的持续集成 (CI) 平台会对大约十几个构建组合进行检查。
在 Ubuntu/Debian 上,您可以使用自动安装脚本(查看 官方网页)
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
构建过程
现在您已准备好构建 ClickHouse,我们建议您在 ClickHouse
内部创建一个单独的 build
目录,其中将包含所有构建工件
mkdir build
cd build
您可以为不同类型的构建创建多个不同的目录(build_release、build_debug 等)。
在 build
目录中,通过运行 CMake 配置构建。在第一次运行之前,您需要定义指定编译器的环境变量。
export CC=clang CXX=clang++
cmake ..
如果您使用上述自动安装脚本安装了 clang,请在第一个命令中也指定安装的 clang 版本,例如 export CC=clang-18 CXX=clang++-18
。clang 版本将在脚本输出中显示。
CC
变量指定 C 编译器,CXX
变量指示用于构建的 C++ 编译器。
为了更快地构建,您可以使用 debug
构建类型 - 一个没有优化的构建。为此,请提供以下参数 -D CMAKE_BUILD_TYPE=Debug
cmake -D CMAKE_BUILD_TYPE=Debug ..
您可以通过在 build
目录中运行此命令来更改构建类型。
运行 ninja 进行构建
ninja clickhouse-server clickhouse-client
在此示例中,只会构建所需的二进制文件。
如果您需要构建所有二进制文件(实用程序和测试),则应在不带任何参数的情况下运行 ninja
ninja
完整构建需要大约 30GB 的可用磁盘空间或 15GB 来构建主要二进制文件。
当构建机器上有大量 RAM 时,您应该使用 -j
参数限制并行运行的构建任务数量
ninja -j 1 clickhouse-server clickhouse-client
在具有 4GB RAM 的机器上,建议指定 1,对于 8GB RAM,建议使用 -j 2
。
如果您收到以下消息:ninja: error: loading 'build.ninja': No such file or directory
,则表示生成构建配置失败,您需要检查上面的消息。
构建过程成功启动后,您将看到构建进度 - 已处理的任务数量和总任务数量。
构建过程中可能会显示有关 LLVM 库的消息。它们不会影响任何内容,可以忽略。
构建成功后,您将获得一个可执行文件 ClickHouse/<build_dir>/programs/clickhouse
ls -l programs/clickhouse
高级构建流程
最小化构建
如果您对第三方库提供的功能不感兴趣,可以使用cmake
选项进一步加快构建速度。
cmake -DENABLE_LIBRARIES=OFF
如果开发选项出现任何问题,您需要自行解决!
Rust 支持
Rust 需要网络连接,如果您没有网络连接,可以禁用 Rust 支持。
cmake -DENABLE_RUST=OFF
运行 ClickHouse 的构建可执行文件
要在当前用户下运行服务器,您需要导航到ClickHouse/programs/server/
(位于build
外部)并运行
../../build/programs/clickhouse server
在这种情况下,ClickHouse 将使用当前目录中的配置文件。您可以从任何目录运行clickhouse server
,并将配置文件路径作为命令行参数--config-file
指定。
要在另一个终端中使用 clickhouse-client 连接到 ClickHouse,请导航到ClickHouse/build/programs/
并运行./clickhouse client
。
如果您在 macOS 或 FreeBSD 上收到Connection refused
消息,请尝试指定主机地址 127.0.0.1。
clickhouse client --host 127.0.0.1
您可以用您自定义构建的 ClickHouse 二进制文件替换系统中安装的 ClickHouse 生产版本。为此,请按照官方网站上的说明在您的机器上安装 ClickHouse。接下来,运行以下命令
sudo service clickhouse-server stop
sudo cp ClickHouse/build/programs/clickhouse /usr/bin/
sudo service clickhouse-server start
请注意,clickhouse-client
、clickhouse-server
等都是指向共享的clickhouse
二进制文件的符号链接。
您还可以使用系统上安装的 ClickHouse 软件包中的配置文件运行您自定义构建的 ClickHouse 二进制文件。
sudo service clickhouse-server stop
sudo -u clickhouse ClickHouse/build/programs/clickhouse server --config-file /etc/clickhouse-server/config.xml
IDE(集成开发环境)
CLion(推荐)
如果您不知道使用哪个 IDE,我们建议您使用CLion。CLion 是商业软件,但它提供 30 天免费试用。对于学生来说,它也是免费的。CLion 可以在 Linux 和 macOS 上使用。
使用 CLion 开发 ClickHouse 时需要了解的一些事项
- CLion 会自行创建
build
路径,并自动选择debug
作为构建类型。 - 它使用 CLion 中定义的 CMake 版本,而不是您安装的版本。
- CLion 将使用
make
运行构建任务,而不是ninja
(这是正常行为)。
其他替代方案
KDevelop 和 QTCreator 是开发 ClickHouse 的其他优秀的 IDE 替代方案。虽然 KDevelop 是一个很棒的 IDE,但有时它不稳定。如果 KDevelop 在打开项目时崩溃,您应该在它打开项目文件列表后立即单击“停止全部”按钮。这样做之后,KDevelop 应该就可以正常工作了。
您可以使用的其他 IDE 包括Sublime Text、Visual Studio Code 或 Kate(所有这些都在 Linux 上可用)。如果您使用的是 VS Code,我们建议您使用clangd 扩展替换 IntelliSense,因为它性能更高。
编写代码
以下是一些在为 ClickHouse 编写代码时可能会有用的快速链接。
编写文档
每个添加新功能的 pull request 都需要编写相应的文档。如果您想预览文档更改,可以在 README.md 文件中找到在本地构建文档页面的说明此处。在向 ClickHouse 添加新函数时,您可以使用以下模板作为指南。
# newFunctionName
A short description of the function goes here. It should describe briefly what it does and a typical usage case.
**Syntax**
\```sql
newFunctionName(arg1, arg2[, arg3])
\```
**Arguments**
- `arg1` — Description of the argument. [DataType](../data-types/float.md)
- `arg2` — Description of the argument. [DataType](../data-types/float.md)
- `arg3` — Description of optional argument (optional). [DataType](../data-types/float.md)
**Implementation Details**
A description of implementation details if relevant.
**Returned value**
- Returns {insert what the function returns here}. [DataType](../data-types/float.md)
**Example**
Query:
\```sql
SELECT 'write your example query here';
\```
Response:
\```response
┌───────────────────────────────────┐
│ the result of the query │
└───────────────────────────────────┘
\```
测试数据
开发 ClickHouse 通常需要加载真实的数据集。这对于性能测试尤其重要。我们准备了一套经过匿名化的网络分析数据。它还需要大约 3GB 的可用磁盘空间。请注意,完成大多数开发任务不需要此数据。
sudo apt install wget xz-utils
wget https://datasets.clickhouse.com/hits/tsv/hits_v1.tsv.xz
wget https://datasets.clickhouse.com/visits/tsv/visits_v1.tsv.xz
xz -v -d hits_v1.tsv.xz
xz -v -d visits_v1.tsv.xz
clickhouse-client
CREATE DATABASE IF NOT EXISTS test
CREATE TABLE test.hits ( WatchID UInt64, JavaEnable UInt8, Title String, GoodEvent Int16, EventTime DateTime, EventDate Date, CounterID UInt32, ClientIP UInt32, ClientIP6 FixedString(16), RegionID UInt32, UserID UInt64, CounterClass Int8, OS UInt8, UserAgent UInt8, URL String, Referer String, URLDomain String, RefererDomain String, Refresh UInt8, IsRobot UInt8, RefererCategories Array(UInt16), URLCategories Array(UInt16), URLRegions Array(UInt32), RefererRegions Array(UInt32), ResolutionWidth UInt16, ResolutionHeight UInt16, ResolutionDepth UInt8, FlashMajor UInt8, FlashMinor UInt8, FlashMinor2 String, NetMajor UInt8, NetMinor UInt8, UserAgentMajor UInt16, UserAgentMinor FixedString(2), CookieEnable UInt8, JavascriptEnable UInt8, IsMobile UInt8, MobilePhone UInt8, MobilePhoneModel String, Params String, IPNetworkID UInt32, TraficSourceID Int8, SearchEngineID UInt16, SearchPhrase String, AdvEngineID UInt8, IsArtifical UInt8, WindowClientWidth UInt16, WindowClientHeight UInt16, ClientTimeZone Int16, ClientEventTime DateTime, SilverlightVersion1 UInt8, SilverlightVersion2 UInt8, SilverlightVersion3 UInt32, SilverlightVersion4 UInt16, PageCharset String, CodeVersion UInt32, IsLink UInt8, IsDownload UInt8, IsNotBounce UInt8, FUniqID UInt64, HID UInt32, IsOldCounter UInt8, IsEvent UInt8, IsParameter UInt8, DontCountHits UInt8, WithHash UInt8, HitColor FixedString(1), UTCEventTime DateTime, Age UInt8, Sex UInt8, Income UInt8, Interests UInt16, Robotness UInt8, GeneralInterests Array(UInt16), RemoteIP UInt32, RemoteIP6 FixedString(16), WindowName Int32, OpenerName Int32, HistoryLength Int16, BrowserLanguage FixedString(2), BrowserCountry FixedString(2), SocialNetwork String, SocialAction String, HTTPError UInt16, SendTiming Int32, DNSTiming Int32, ConnectTiming Int32, ResponseStartTiming Int32, ResponseEndTiming Int32, FetchTiming Int32, RedirectTiming Int32, DOMInteractiveTiming Int32, DOMContentLoadedTiming Int32, DOMCompleteTiming Int32, LoadEventStartTiming Int32, LoadEventEndTiming Int32, NSToDOMContentLoadedTiming Int32, FirstPaintTiming Int32, RedirectCount Int8, SocialSourceNetworkID UInt8, SocialSourcePage String, ParamPrice Int64, ParamOrderID String, ParamCurrency FixedString(3), ParamCurrencyID UInt16, GoalsReached Array(UInt32), OpenstatServiceName String, OpenstatCampaignID String, OpenstatAdID String, OpenstatSourceID String, UTMSource String, UTMMedium String, UTMCampaign String, UTMContent String, UTMTerm String, FromTag String, HasGCLID UInt8, RefererHash UInt64, URLHash UInt64, CLID UInt32, YCLID UInt64, ShareService String, ShareURL String, ShareTitle String, `ParsedParams.Key1` Array(String), `ParsedParams.Key2` Array(String), `ParsedParams.Key3` Array(String), `ParsedParams.Key4` Array(String), `ParsedParams.Key5` Array(String), `ParsedParams.ValueDouble` Array(Float64), IslandID FixedString(16), RequestNum UInt32, RequestTry UInt8) ENGINE = MergeTree PARTITION BY toYYYYMM(EventDate) SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID), EventTime);
CREATE TABLE test.visits ( CounterID UInt32, StartDate Date, Sign Int8, IsNew UInt8, VisitID UInt64, UserID UInt64, StartTime DateTime, Duration UInt32, UTCStartTime DateTime, PageViews Int32, Hits Int32, IsBounce UInt8, Referer String, StartURL String, RefererDomain String, StartURLDomain String, EndURL String, LinkURL String, IsDownload UInt8, TraficSourceID Int8, SearchEngineID UInt16, SearchPhrase String, AdvEngineID UInt8, PlaceID Int32, RefererCategories Array(UInt16), URLCategories Array(UInt16), URLRegions Array(UInt32), RefererRegions Array(UInt32), IsYandex UInt8, GoalReachesDepth Int32, GoalReachesURL Int32, GoalReachesAny Int32, SocialSourceNetworkID UInt8, SocialSourcePage String, MobilePhoneModel String, ClientEventTime DateTime, RegionID UInt32, ClientIP UInt32, ClientIP6 FixedString(16), RemoteIP UInt32, RemoteIP6 FixedString(16), IPNetworkID UInt32, SilverlightVersion3 UInt32, CodeVersion UInt32, ResolutionWidth UInt16, ResolutionHeight UInt16, UserAgentMajor UInt16, UserAgentMinor UInt16, WindowClientWidth UInt16, WindowClientHeight UInt16, SilverlightVersion2 UInt8, SilverlightVersion4 UInt16, FlashVersion3 UInt16, FlashVersion4 UInt16, ClientTimeZone Int16, OS UInt8, UserAgent UInt8, ResolutionDepth UInt8, FlashMajor UInt8, FlashMinor UInt8, NetMajor UInt8, NetMinor UInt8, MobilePhone UInt8, SilverlightVersion1 UInt8, Age UInt8, Sex UInt8, Income UInt8, JavaEnable UInt8, CookieEnable UInt8, JavascriptEnable UInt8, IsMobile UInt8, BrowserLanguage UInt16, BrowserCountry UInt16, Interests UInt16, Robotness UInt8, GeneralInterests Array(UInt16), Params Array(String), `Goals.ID` Array(UInt32), `Goals.Serial` Array(UInt32), `Goals.EventTime` Array(DateTime), `Goals.Price` Array(Int64), `Goals.OrderID` Array(String), `Goals.CurrencyID` Array(UInt32), WatchIDs Array(UInt64), ParamSumPrice Int64, ParamCurrency FixedString(3), ParamCurrencyID UInt16, ClickLogID UInt64, ClickEventID Int32, ClickGoodEvent Int32, ClickEventTime DateTime, ClickPriorityID Int32, ClickPhraseID Int32, ClickPageID Int32, ClickPlaceID Int32, ClickTypeID Int32, ClickResourceID Int32, ClickCost UInt32, ClickClientIP UInt32, ClickDomainID UInt32, ClickURL String, ClickAttempt UInt8, ClickOrderID UInt32, ClickBannerID UInt32, ClickMarketCategoryID UInt32, ClickMarketPP UInt32, ClickMarketCategoryName String, ClickMarketPPName String, ClickAWAPSCampaignName String, ClickPageName String, ClickTargetType UInt16, ClickTargetPhraseID UInt64, ClickContextType UInt8, ClickSelectType Int8, ClickOptions String, ClickGroupBannerID Int32, OpenstatServiceName String, OpenstatCampaignID String, OpenstatAdID String, OpenstatSourceID String, UTMSource String, UTMMedium String, UTMCampaign String, UTMContent String, UTMTerm String, FromTag String, HasGCLID UInt8, FirstVisit DateTime, PredLastVisit Date, LastVisit Date, TotalVisits UInt32, `TraficSource.ID` Array(Int8), `TraficSource.SearchEngineID` Array(UInt16), `TraficSource.AdvEngineID` Array(UInt8), `TraficSource.PlaceID` Array(UInt16), `TraficSource.SocialSourceNetworkID` Array(UInt8), `TraficSource.Domain` Array(String), `TraficSource.SearchPhrase` Array(String), `TraficSource.SocialSourcePage` Array(String), Attendance FixedString(16), CLID UInt32, YCLID UInt64, NormalizedRefererHash UInt64, SearchPhraseHash UInt64, RefererDomainHash UInt64, NormalizedStartURLHash UInt64, StartURLDomainHash UInt64, NormalizedEndURLHash UInt64, TopLevelDomain UInt64, URLScheme UInt64, OpenstatServiceNameHash UInt64, OpenstatCampaignIDHash UInt64, OpenstatAdIDHash UInt64, OpenstatSourceIDHash UInt64, UTMSourceHash UInt64, UTMMediumHash UInt64, UTMCampaignHash UInt64, UTMContentHash UInt64, UTMTermHash UInt64, FromHash UInt64, WebVisorEnabled UInt8, WebVisorActivity UInt32, `ParsedParams.Key1` Array(String), `ParsedParams.Key2` Array(String), `ParsedParams.Key3` Array(String), `ParsedParams.Key4` Array(String), `ParsedParams.Key5` Array(String), `ParsedParams.ValueDouble` Array(Float64), `Market.Type` Array(UInt8), `Market.GoalID` Array(UInt32), `Market.OrderID` Array(String), `Market.OrderPrice` Array(Int64), `Market.PP` Array(UInt32), `Market.DirectPlaceID` Array(UInt32), `Market.DirectOrderID` Array(UInt32), `Market.DirectBannerID` Array(UInt32), `Market.GoodID` Array(String), `Market.GoodName` Array(String), `Market.GoodQuantity` Array(Int32), `Market.GoodPrice` Array(Int64), IslandID FixedString(16)) ENGINE = CollapsingMergeTree(Sign) PARTITION BY toYYYYMM(StartDate) SAMPLE BY intHash32(UserID) ORDER BY (CounterID, StartDate, intHash32(UserID), VisitID);
clickhouse-client --max_insert_block_size 100000 --query "INSERT INTO test.hits FORMAT TSV" < hits_v1.tsv
clickhouse-client --max_insert_block_size 100000 --query "INSERT INTO test.visits FORMAT TSV" < visits_v1.tsv
创建 Pull Request
在 GitHub 的 UI 中导航到您的 fork 仓库。如果您一直在分支中开发,则需要选择该分支。屏幕上将有一个“Pull request”按钮。从本质上讲,这意味着“请求将我的更改合并到主仓库中”。
即使工作尚未完成,也可以创建 Pull Request。在这种情况下,请在标题开头加上“WIP”(正在进行中),以后可以更改。这对于协作审查和讨论更改以及运行所有可用测试很有用。重要的是您需要提供对更改的简要描述,它将用于生成发布变更日志。
一旦 ClickHouse 员工为您的 PR 添加“可以测试”标签,测试就会开始。一些初步检查(例如代码风格)的结果将在几分钟内显示。构建检查结果将在半小时内到达。主要测试集将在一个小时内报告其结果。
系统将单独为您的 pull request 准备 ClickHouse 二进制构建。要检索这些构建,请单击检查列表中“构建”条目旁边的“详细信息”链接。在那里,您将找到构建的 ClickHouse .deb 包的直接链接,即使在您的生产服务器上也可以部署这些包(如果您不怕的话)。
大多数情况下,一些构建在第一次尝试时会失败。这是因为我们使用 gcc 和 clang 检查构建,并为 clang 启用了几乎所有现有的警告(始终使用-Werror
标志)。在同一页面上,您可以找到所有构建日志,这样您就不必以所有可能的方式构建 ClickHouse。
浏览 ClickHouse 源代码
您可以使用 GitHub 集成的代码浏览器此处。
此外,您还可以像往常一样在GitHub上浏览源代码。