From 390c4b719524747f41c9483eb5e3bef9e285cff8 Mon Sep 17 00:00:00 2001 From: YuCheng Hu Date: Thu, 22 Jul 2021 11:04:41 -0400 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Getting=20started=20?= =?UTF-8?q?=E5=88=86=E7=B1=BB=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GettingStarted/Docker.md | 63 +++ GettingStarted/chapter-1.md | 60 +++ GettingStarted/chapter-2.md | 163 +++++++ GettingStarted/chapter-3.md | 69 +++ GettingStarted/chapter-4.md | 421 ++++++++++++++++++ GettingStarted/img/tutorial-quickstart-01.png | Bin 0 -> 67013 bytes design/index.md | 107 +++-- 7 files changed, 840 insertions(+), 43 deletions(-) create mode 100644 GettingStarted/Docker.md create mode 100644 GettingStarted/chapter-1.md create mode 100644 GettingStarted/chapter-2.md create mode 100644 GettingStarted/chapter-3.md create mode 100644 GettingStarted/chapter-4.md create mode 100644 GettingStarted/img/tutorial-quickstart-01.png diff --git a/GettingStarted/Docker.md b/GettingStarted/Docker.md new file mode 100644 index 0000000..9285881 --- /dev/null +++ b/GettingStarted/Docker.md @@ -0,0 +1,63 @@ + + + + + + +## Docker + +在这个部分中,我们将从 [Docker Hub](https://hub.docker.com/r/apache/druid) 下载Apache Druid镜像,并使用 [Docker](https://www.docker.com/get-started) 和 [Docker Compose](https://docs.docker.com/compose/) 在一台机器上安装它。完成此初始设置后,集群将准备好加载数据。 + +在开始快速启动之前,阅读 [Druid概述](chapter-1.md) 和 [摄取概述](../DataIngestion/ingestion.md) 是很有帮助的,因为教程将参考这些页面上讨论的概念。此外,建议熟悉Docker。 + +### 前提条件 + +* Docker + +### 快速开始 + +Druid源代码包含一个 [示例docker-compose.yml](https://github.com/apache/druid/blob/master/distribution/docker/docker-compose.yml) 它可以从Docker Hub中提取一个镜像,适合用作示例环境,并用于试验基于Docker的Druid配置和部署。 + +#### Compose文件 + +示例 `docker-compose.yml` 将为每个Druid服务创建一个容器,包括Zookeeper和作为元数据存储PostgreSQL容器。深度存储将是本地目录,默认配置为相对于 `docker-compose.yml`文件的 `./storage`,并将作为 `/opt/data` 挂载,并在需要访问深层存储的Druid容器之间共享。Druid容器是通过 [环境文件](https://github.com/apache/druid/blob/master/distribution/docker/environment) 配置的。 + +#### 配置 + +Druid Docker容器的配置是通过环境变量完成的,环境变量还可以指定到 [标准Druid配置文件](../Configuration/configuration.md) 的路径 + +特殊环境变量: + +* `JAVA_OPTS` -- 设置 java options +* `DRUID_LOG4J` -- 设置完成的 `log4j.xml` +* `DRUID_LOG_LEVEL` -- 覆盖在log4j中的默认日志级别 +* `DRUID_XMX` -- 设置 Java `Xmx` +* `DRUID_XMS` -- 设置 Java `Xms` +* `DRUID_MAXNEWSIZE` -- 设置 Java最大新生代大小 +* `DRUID_NEWSIZE` -- 设置 Java 新生代大小 +* `DRUID_MAXDIRECTMEMORYSIZE` -- 设置Java最大直接内存大小 +* `DRUID_CONFIG_COMMON` -- druid "common"属性文件的完整路径 +* `DRUID_CONFIG_${service}` -- druid "service"属性文件的完整路径 + +除了特殊的环境变量外,在容器中启动Druid的脚本还将尝试使用以 `druid_`前缀开头的任何环境变量作为命令行配置。例如,Druid容器进程中的环境变量`druid_metadata_storage_type=postgresql` 将被转换为 `-Ddruid.metadata.storage.type=postgresql` + +Druid `docker-compose.yml` 示例使用单个环境文件来指定完整的Druid配置;但是,在生产用例中,我们建议使用 `DRUID_COMMON_CONFIG` 和`DRUID_CONFIG_${service}` 或专门定制的特定于服务的环境文件。 + +### 启动集群 + +运行 `docker-compose up` 启动附加shell的集群,或运行 `docker-compose up -d` 在后台运行集群。如果直接使用示例文件,这个命令应该从Druid安装目录中的 `distribution/docker/` 运行。 + +启动集群后,可以导航到 [http://localhost:8888](http://localhost/) 。服务于 [Druid控制台](../Operations/druid-console.md) 的 [Druid路由进程](../Design/Router.md) 位于这个地址。 + +![](img/tutorial-quickstart-01.png) + +所有Druid进程需要几秒钟才能完全启动。如果在启动服务后立即打开控制台,可能会看到一些可以安全忽略的错误。 + +从这里你可以跟着 [标准教程](chapter-2.md),或者详细说明你的 `docker-compose.yml` 根据需要添加任何其他外部服务依赖项。 \ No newline at end of file diff --git a/GettingStarted/chapter-1.md b/GettingStarted/chapter-1.md new file mode 100644 index 0000000..26d0ceb --- /dev/null +++ b/GettingStarted/chapter-1.md @@ -0,0 +1,60 @@ + + + + + + +### Druid是什么 + +Apache Druid是一个实时分析型数据库,旨在对大型数据集进行快速的查询分析("[OLAP](https://en.wikipedia.org/wiki/Online_analytical_processing)"查询)。Druid最常被当做数据库来用以支持实时摄取、高性能查询和高稳定运行的应用场景,同时,Druid也通常被用来助力分析型应用的图形化界面,或者当做需要快速聚合的高并发后端API,Druid最适合应用于面向事件类型的数据。 + +Druid通常应用于以下场景: + +* 点击流分析(Web端和移动端) +* 网络监测分析(网络性能监控) +* 服务指标存储 +* 供应链分析(制造类指标) +* 应用性能指标分析 +* 数字广告分析 +* 商务智能 / OLAP + +Druid的核心架构吸收和结合了[数据仓库](https://en.wikipedia.org/wiki/Data_warehouse)、[时序数据库](https://en.wikipedia.org/wiki/Time_series_database)以及[检索系统](https://en.wikipedia.org/wiki/Search_engine_(computing))的优势,其主要特征如下: + +1. **列式存储**,Druid使用列式存储,这意味着在一个特定的数据查询中它只需要查询特定的列,这样极地提高了部分列查询场景的性能。另外,每一列数据都针对特定数据类型做了优化存储,从而支持快速的扫描和聚合。 +2. **可扩展的分布式系统**,Druid通常部署在数十到数百台服务器的集群中,并且可以提供每秒数百万条记录的接收速率,数万亿条记录的保留存储以及亚秒级到几秒的查询延迟。 +3. **大规模并行处理**,Druid可以在整个集群中并行处理查询。 +4. **实时或批量摄取**,Druid可以实时(已经被摄取的数据可立即用于查询)或批量摄取数据。 +5. **自修复、自平衡、易于操作**,作为集群运维操作人员,要伸缩集群只需添加或删除服务,集群就会在后台自动重新平衡自身,而不会造成任何停机。如果任何一台Druid服务器发生故障,系统将自动绕过损坏。 Druid设计为7*24全天候运行,无需出于任何原因而导致计划内停机,包括配置更改和软件更新。 +6. **不会丢失数据的云原生容错架构**,一旦Druid摄取了数据,副本就安全地存储在[深度存储介质](Design/../chapter-1.md)(通常是云存储,HDFS或共享文件系统)中。即使某个Druid服务发生故障,也可以从深度存储中恢复您的数据。对于仅影响少数Druid服务的有限故障,副本可确保在系统恢复时仍然可以进行查询。 +7. **用于快速过滤的索引**,Druid使用[CONCISE](https://arxiv.org/pdf/1004.0403.pdf)或[Roaring](https://roaringbitmap.org/)压缩的位图索引来创建索引,以支持快速过滤和跨多列搜索。 +8. **基于时间的分区**,Druid首先按时间对数据进行分区,另外同时可以根据其他字段进行分区。这意味着基于时间的查询将仅访问与查询时间范围匹配的分区,这将大大提高基于时间的数据的性能。 +9. **近似算法**,Druid应用了近似count-distinct,近似排序以及近似直方图和分位数计算的算法。这些算法占用有限的内存使用量,通常比精确计算要快得多。对于精度要求比速度更重要的场景,Druid还提供了精确count-distinct和精确排序。 +10. **摄取时自动汇总聚合**,Druid支持在数据摄取阶段可选地进行数据汇总,这种汇总会部分预先聚合您的数据,并可以节省大量成本并提高性能。 + +### 什么场景下应该使用Druid + +许多公司都已经将Druid应用于多种不同的应用场景,详情可查看[Powered by Apache Druid](https://druid.apache.org/druid-powered)页面。 + +如果您的使用场景符合以下的几个特征,那么Druid是一个非常不错的选择: + +* 数据插入频率比较高,但较少更新数据 +* 大多数查询场景为聚合查询和分组查询(GroupBy),同时还有一定得检索与扫描查询 +* 将数据查询延迟目标定位100毫秒到几秒钟之间 +* 数据具有时间属性(Druid针对时间做了优化和设计) +* 在多表场景下,每次查询仅命中一个大的分布式表,查询又可能命中多个较小的lookup表 +* 场景中包含高基维度数据列(例如URL,用户ID等),并且需要对其进行快速计数和排序 +* 需要从Kafka、HDFS、对象存储(如Amazon S3)中加载数据 + +如果您的使用场景符合以下特征,那么使用Druid可能是一个不好的选择: + +* 根据主键对现有数据进行低延迟更新操作。Druid支持流式插入,但不支持流式更新(更新操作是通过后台批处理作业完成) +* 延迟不重要的离线数据系统 +* 场景中包括大连接(将一个大事实表连接到另一个大事实表),并且可以接受花费很长时间来完成这些查询 + diff --git a/GettingStarted/chapter-2.md b/GettingStarted/chapter-2.md new file mode 100644 index 0000000..053e536 --- /dev/null +++ b/GettingStarted/chapter-2.md @@ -0,0 +1,163 @@ + + + + + +### 快速开始 + +在本快速入门教程中,我们将下载Druid并将其安装在一台服务器上,完成初始安装后,向集群中加载数据。 + +在开始快速入门之前,阅读[Druid概述](./chapter-1.md)和[数据摄取概述](../DataIngestion/index.md)会很有帮助,因为当前教程会引用这些页面上讨论的概念。 + +#### 预备条件 +##### 软件 +* **Java 8(8u92+)** +* Linux, Mac OS X, 或者其他类UNIX系统(Windows不支持) + +> [!WARNING] +> Druid服务运行依赖Java 8,可以使用环境变量`DRUID_JAVA_HOME`或`JAVA_HOME`指定在何处查找Java,有关更多详细信息,请运行`verify-java`脚本。 + +##### 硬件 + +Druid安装包提供了几个[单服务器配置](./chapter-3.md)的示例,以及使用这些配置启动Druid进程的脚本。 + +如果您正在使用便携式等小型计算机上运行服务,则配置为4CPU/16GB RAM环境的`micro-quickstart`配置是一个不错的选择。 + +如果您打算在本教程之外使用单机部署进行进一步试验评估,则建议使用比`micro-quickstart`更大的配置。 + +#### 入门开始 + +[下载](https://www.apache.org/dyn/closer.cgi?path=/druid/0.17.0/apache-druid-0.17.0-bin.tar.gz)Druid最新0.17.0release安装包 + +在终端中运行以下命令来提取Druid + +```json +tar -xzf apache-druid-0.17.0-bin.tar.gz +cd apache-druid-0.17.0 +``` + +在安装包中有以下文件: + +* `LICENSE`和`NOTICE`文件 +* `bin/*` - 启停等脚本 +* `conf/*` - 用于单节点部署和集群部署的示例配置 +* `extensions/*` - Druid核心扩展 +* `hadoop-dependencies/*` - Druid Hadoop依赖 +* `lib/*` - Druid核心库和依赖 +* `quickstart/*` - 配置文件,样例数据,以及快速入门教材的其他文件 + +#### 启动服务 + +以下命令假定您使用的是`micro-quickstart`单机配置,如果使用的是其他配置,在`bin`目录下有每一种配置对应的脚本,如`bin/start-single-server-small` + +在`apache-druid-0.17.0`安装包的根目录下执行命令: + +```json +./bin/start-micro-quickstart +``` +然后将在本地计算机上启动Zookeeper和Druid服务实例,例如: + +```json +$ ./bin/start-micro-quickstart +[Fri May 3 11:40:50 2019] Running command[zk], logging to[/apache-druid-0.17.0/var/sv/zk.log]: bin/run-zk conf +[Fri May 3 11:40:50 2019] Running command[coordinator-overlord], logging to[/apache-druid-0.17.0/var/sv/coordinator-overlord.log]: bin/run-druid coordinator-overlord conf/druid/single-server/micro-quickstart +[Fri May 3 11:40:50 2019] Running command[broker], logging to[/apache-druid-0.17.0/var/sv/broker.log]: bin/run-druid broker conf/druid/single-server/micro-quickstart +[Fri May 3 11:40:50 2019] Running command[router], logging to[/apache-druid-0.17.0/var/sv/router.log]: bin/run-druid router conf/druid/single-server/micro-quickstart +[Fri May 3 11:40:50 2019] Running command[historical], logging to[/apache-druid-0.17.0/var/sv/historical.log]: bin/run-druid historical conf/druid/single-server/micro-quickstart +[Fri May 3 11:40:50 2019] Running command[middleManager], logging to[/apache-druid-0.17.0/var/sv/middleManager.log]: bin/run-druid middleManager conf/druid/single-server/micro-quickstart +``` + +所有的状态(例如集群元数据存储和服务的segment文件)将保留在`apache-druid-0.17.0`软件包根目录下的`var`目录中, 服务的日志位于 `var/sv`。 + +稍后,如果您想停止服务,请按`CTRL-C`退出`bin/start-micro-quickstart`脚本,该脚本将终止Druid进程。 + +集群启动后,可以访问[http://localhost:8888](http://localhost:8888)来Druid控制台,控制台由Druid Router进程启动。 + +![tutorial-quickstart](img/tutorial-quickstart-01.png) + +所有Druid进程完全启动需要花费几秒钟。 如果在启动服务后立即打开控制台,则可能会看到一些可以安全忽略的错误。 + +#### 加载数据 +##### 教程使用的数据集 + +对于以下数据加载教程,我们提供了一个示例数据文件,其中包含2015年9月12日发生的Wikipedia页面编辑事件。 + +该样本数据位于Druid包根目录的`quickstart/tutorial/wikiticker-2015-09-12-sampled.json.gz`中,页面编辑事件作为JSON对象存储在文本文件中。 + +示例数据包含以下几列,示例事件如下所示: + +* added +* channel +* cityName +* comment +* countryIsoCode +* countryName +* deleted +* delta +* isAnonymous +* isMinor +* isNew +* isRobot +* isUnpatrolled +* metroCode +* namespace +* page +* regionIsoCode +* regionName +* user + +```json +{ + "timestamp":"2015-09-12T20:03:45.018Z", + "channel":"#en.wikipedia", + "namespace":"Main", + "page":"Spider-Man's powers and equipment", + "user":"foobar", + "comment":"/* Artificial web-shooters */", + "cityName":"New York", + "regionName":"New York", + "regionIsoCode":"NY", + "countryName":"United States", + "countryIsoCode":"US", + "isAnonymous":false, + "isNew":false, + "isMinor":false, + "isRobot":false, + "isUnpatrolled":false, + "added":99, + "delta":99, + "deleted":0, +} +``` + +##### 数据加载 + +以下教程演示了将数据加载到Druid的各种方法,包括批处理和流处理用例。 所有教程均假定您使用的是上面提到的`micro-quickstart`单机配置。 + +* [加载本地文件](../Tutorials/chapter-1.md) - 本教程演示了如何使用Druid的本地批处理摄取来执行批文件加载 +* [从Kafka加载流数据](../Tutorials/chapter-2.md) - 本教程演示了如何从Kafka主题加载流数据 +* [从Hadoop加载数据](../Tutorials/chapter-3.md) - 本教程演示了如何使用远程Hadoop集群执行批处理文件加载 +* [编写一个自己的数据摄取规范](../Tutorials/chapter-10.md) - 本教程演示了如何编写新的数据摄取规范并使用它来加载数据 + +##### 重置集群状态 + +如果要在清理服务后重新启动,请删除`var`目录,然后再次运行`bin/start-micro-quickstart`脚本。 + +一旦每个服务都启动,您就可以加载数据了。 + +##### 重置Kafka + +如果您完成了[教程:从Kafka加载流数据](../Tutorials/chapter-2.md)并希望重置集群状态,则还应该清除所有Kafka状态。 + +在停止ZooKeeper和Druid服务之前,使用`CTRL-C`关闭`Kafka Broker`,然后删除`/tmp/kafka-logs`中的Kafka日志目录: + +``` +rm -rf /tmp/kafka-logs +``` diff --git a/GettingStarted/chapter-3.md b/GettingStarted/chapter-3.md new file mode 100644 index 0000000..a232c9e --- /dev/null +++ b/GettingStarted/chapter-3.md @@ -0,0 +1,69 @@ + + + + + + +### 单服务器部署 + +Druid包括一组参考配置和用于单机部署的启动脚本: + +* `nano-quickstart` +* `micro-quickstart` +* `small` +* `medium` +* `large` +* `large` +* `xlarge` + +`micro-quickstart`适合于笔记本电脑等小型机器,旨在用于快速评估测试使用场景。 + +`nano-quickstart`是一种甚至更小的配置,目标是具有1个CPU和4GB内存的计算机。它旨在在资源受限的环境(例如小型Docker容器)中进行有限的评估测试。 + +其他配置旨在用于一般用途的单机部署,它们的大小适合大致基于亚马逊i3系列EC2实例的硬件。 + +这些示例配置的启动脚本与Druid服务一起运行单个ZK实例,您也可以选择单独部署ZK。 + +通过[Coordinator配置文档](../Configuration/configuration.md#Coordinator)中描述的可选配置`druid.coordinator.asOverlord.enabled = true`可以在单个进程中同时运行Druid Coordinator和Overlord。 + +虽然为大型单台计算机提供了示例配置,但在更高规模下,我们建议在集群部署中运行Druid,以实现容错和减少资源争用。 + +#### 单服务器参考配置 +##### Nano-Quickstart: 1 CPU, 4GB 内存 + +* 启动命令: `bin/start-nano-quickstart` +* 配置目录: `conf/druid/single-server/nano-quickstart` + +##### Micro-Quickstart: 4 CPU, 16GB 内存 + +* 启动命令: `bin/start-micro-quickstart` +* 配置目录: `conf/druid/single-server/micro-quickstart` + +##### Small: 8 CPU, 64GB 内存 (~i3.2xlarge) + +* 启动命令: `bin/start-small` +* 配置目录: `conf/druid/single-server/small` + +##### Medium: 16 CPU, 128GB 内存 (~i3.4xlarge) + +* 启动命令: `bin/start-medium` +* 配置目录: `conf/druid/single-server/medium` + +##### Large: 32 CPU, 256GB 内存 (~i3.8xlarge) + +* 启动命令: `bin/start-large` +* 配置目录: `conf/druid/single-server/large` + +##### X-Large: 64 CPU, 512GB 内存 (~i3.16xlarge) + +* 启动命令: `bin/start-xlarge` +* 配置目录: `conf/druid/single-server/xlarge` + +--- \ No newline at end of file diff --git a/GettingStarted/chapter-4.md b/GettingStarted/chapter-4.md new file mode 100644 index 0000000..597c3b5 --- /dev/null +++ b/GettingStarted/chapter-4.md @@ -0,0 +1,421 @@ + + + + + + +## 集群部署 + +Apache Druid旨在作为可伸缩的容错集群进行部署。 + +在本文档中,我们将安装一个简单的集群,并讨论如何对其进行进一步配置以满足您的需求。 + +这个简单的集群将具有以下特点: +* 一个Master服务同时起Coordinator和Overlord进程 +* 两个可伸缩、容错的Data服务来运行Historical和MiddleManager进程 +* 一个Query服务,运行Druid Broker和Router进程 + +在生产中,我们建议根据您的特定容错需求部署多个Master服务器和多个Query服务器,但是您可以使用一台Master服务器和一台Query服务器将服务快速运行起来,然后再添加更多服务器。 +### 选择硬件 +#### 首次部署 + +如果您现在没有Druid集群,并打算首次以集群模式部署运行Druid,则本指南提供了一个包含预先配置的集群部署示例。 + +##### Master服务 + +Coordinator进程和Overlord进程负责处理集群的元数据和协调需求,它们可以运行在同一台服务器上。 + +在本示例中,我们将在等效于AWS[m5.2xlarge](https://aws.amazon.com/ec2/instance-types/m5/)实例的硬件环境上部署。 + +硬件规格为: + +* 8核CPU +* 31GB内存 + +可以在`conf/druid/cluster/master`下找到适用于此硬件规格的Master示例服务配置。 + +##### Data服务 + +Historical和MiddleManager可以分配在同一台服务器上运行,以处理集群中的实际数据,这两个服务受益于CPU、内存和固态硬盘。 + +在本示例中,我们将在等效于AWS[i3.4xlarge](https://aws.amazon.com/cn/ec2/instance-types/i3/)实例的硬件环境上部署。 + +硬件规格为: +* 16核CPU +* 122GB内存 +* 2 * 1.9TB 固态硬盘 + +可以在`conf/druid/cluster/data`下找到适用于此硬件规格的Data示例服务配置。 + +##### Query服务 + +Druid Broker服务接收查询请求,并将其转发到集群中的其他部分,同时其可以可选的配置内存缓存。 Broker服务受益于CPU和内存。 + +在本示例中,我们将在等效于AWS[m5.2xlarge](https://aws.amazon.com/ec2/instance-types/m5/)实例的硬件环境上部署。 + +硬件规格为: + +* 8核CPU +* 31GB内存 + +您可以考虑将所有的其他开源UI工具或者查询依赖等与Broker服务部署在同一台服务器上。 + +可以在`conf/druid/cluster/query`下找到适用于此硬件规格的Query示例服务配置。 + +##### 其他硬件配置 + +上面的示例集群是从多种确定Druid集群大小的可能方式中选择的一个示例。 + +您可以根据自己的特定需求和限制选择较小/较大的硬件或较少/更多的服务器。 + +如果您的使用场景具有复杂的扩展要求,则还可以选择不将Druid服务混合部署(例如,独立的Historical Server)。 + +[基本集群调整指南](../Operations/basicClusterTuning.md)中的信息可以帮助您进行决策,并可以调整配置大小。 + +#### 从单服务器环境迁移部署 + +如果您现在已有单服务器部署的环境,例如[单服务器部署示例](./chapter-3.md)中的部署,并且希望迁移到类似规模的集群部署,则以下部分包含一些选择Master/Data/Query服务等效硬件的准则。 + +##### Master服务 + +Master服务的主要考虑点是可用CPU以及用于Coordinator和Overlord进程的堆内存。 + +首先计算出来在单服务器环境下Coordinator和Overlord已分配堆内存之和,然后选择具有足够内存的Master服务硬件,同时还需要考虑到为服务器上其他进程预留一些额外的内存。 + +对于CPU,可以选择接近于单服务器环境核数1/4的硬件。 + +##### Data服务 + +在为集群Data服务选择硬件时,主要考虑可用的CPU和内存,可行时使用SSD存储。 + +在集群化部署时,出于容错的考虑,最好是部署多个Data服务。 + +在选择Data服务的硬件时,可以假定一个分裂因子`N`,将原来的单服务器环境的CPU和内存除以`N`,然后在新集群中部署`N`个硬件规格缩小的Data服务。 + +##### Query服务 + +Query服务的硬件选择主要考虑可用的CPU、Broker服务的堆内和堆外内存、Router服务的堆内存。 + +首先计算出来在单服务器环境下Broker和Router已分配堆内存之和,然后选择可以覆盖Broker和Router内存的Query服务硬件,同时还需要考虑到为服务器上其他进程预留一些额外的内存。 + +对于CPU,可以选择接近于单服务器环境核数1/4的硬件。 + +[基本集群调优指南](../Operations/basicClusterTuning.md)包含有关如何计算Broker和Router服务内存使用量的信息。 + +### 选择操作系统 + +我们建议运行您喜欢的Linux发行版,同时还需要: + +* **Java 8** + +> [!WARNING] +> Druid服务运行依赖Java 8,可以使用环境变量`DRUID_JAVA_HOME`或`JAVA_HOME`指定在何处查找Java,有关更多详细信息,请运行`verify-java`脚本。 + +### 下载发行版 + +首先,下载并解压缩发布安装包。最好首先在单台计算机上执行此操作,因为您将编辑配置,然后将修改后的配置分发到所有服务器上。 + +[下载](https://www.apache.org/dyn/closer.cgi?path=/druid/0.17.0/apache-druid-0.17.0-bin.tar.gz)Druid最新0.17.0release安装包 + +在终端中运行以下命令来提取Druid + +``` +tar -xzf apache-druid-0.17.0-bin.tar.gz +cd apache-druid-0.17.0 +``` + +在安装包中有以下文件: + +* `LICENSE`和`NOTICE`文件 +* `bin/*` - 启停等脚本 +* `conf/druid/cluster/*` - 用于集群部署的模板配置 +* `extensions/*` - Druid核心扩展 +* `hadoop-dependencies/*` - Druid Hadoop依赖 +* `lib/*` - Druid核心库和依赖 +* `quickstart/*` - 与[快速入门](./chapter-2.md)相关的文件 + +我们主要是编辑`conf/druid/cluster/`中的文件。 + +#### 从单服务器环境迁移部署 + +在以下各节中,我们将在`conf/druid/cluster`下编辑配置。 + +如果您已经有一个单服务器部署,请将您的现有配置复制到`conf/druid /cluster`以保留您所做的所有配置更改。 + +### 配置元数据存储和深度存储 +#### 从单服务器环境迁移部署 + +如果您已经有一个单服务器部署,并且希望在整个迁移过程中保留数据,请在更新元数据/深层存储配置之前,按照[元数据迁移](../Operations/metadataMigration.md)和[深层存储迁移](../Operations/DeepstorageMigration.md)中的说明进行操作。 + +这些指南针对使用Derby元数据存储和本地深度存储的单服务器部署。 如果您已经在单服务器集群中使用了非Derby元数据存储,则可以在新集群中可以继续使用当前的元数据存储。 + +这些指南还提供了有关从本地深度存储迁移段的信息。集群部署需要分布式深度存储,例如S3或HDFS。 如果单服务器部署已在使用分布式深度存储,则可以在新集群中继续使用当前的深度存储。 + +#### 元数据存储 + +在`conf/druid/cluster/_common/common.runtime.properties`中,使用您将用作元数据存储的服务器地址来替换"metadata.storage.*": + +* `druid.metadata.storage.connector.connectURI` +* `druid.metadata.storage.connector.host` + +在生产部署中,我们建议运行专用的元数据存储,例如具有复制功能的MySQL或PostgreSQL,与Druid服务器分开部署。 + +[MySQL扩展](../Configuration/core-ext/mysql.md)和[PostgreSQL](../Configuration/core-ext/postgresql.md)扩展文档包含有关扩展配置和初始数据库安装的说明。 + +#### 深度存储 + +Druid依赖于分布式文件系统或大对象(blob)存储来存储数据,最常用的深度存储实现是S3(适合于在AWS上)和HDFS(适合于已有Hadoop集群)。 + +##### S3 + +在`conf/druid/cluster/_common/common.runtime.properties`中, + +* 在`druid.extension.loadList`配置项中增加"druid-s3-extensions"扩展 +* 注释掉配置文件中用于本地存储的"Deep Storage"和"Indexing service logs" +* 打开配置文件中关于"For S3"部分中"Deep Storage"和"Indexing service logs"的配置 + +上述操作之后,您将看到以下的变化: + +```json +druid.extensions.loadList=["druid-s3-extensions"] + +#druid.storage.type=local +#druid.storage.storageDirectory=var/druid/segments + +druid.storage.type=s3 +druid.storage.bucket=your-bucket +druid.storage.baseKey=druid/segments +druid.s3.accessKey=... +druid.s3.secretKey=... + +#druid.indexer.logs.type=file +#druid.indexer.logs.directory=var/druid/indexing-logs + +druid.indexer.logs.type=s3 +druid.indexer.logs.s3Bucket=your-bucket +druid.indexer.logs.s3Prefix=druid/indexing-logs +``` +更多信息可以看[S3扩展](../Configuration/core-ext/s3.md)部分的文档。 + +##### HDFS + +在`conf/druid/cluster/_common/common.runtime.properties`中, + +* 在`druid.extension.loadList`配置项中增加"druid-hdfs-storage"扩展 +* 注释掉配置文件中用于本地存储的"Deep Storage"和"Indexing service logs" +* 打开配置文件中关于"For HDFS"部分中"Deep Storage"和"Indexing service logs"的配置 + +上述操作之后,您将看到以下的变化: + +```json +druid.extensions.loadList=["druid-hdfs-storage"] + +#druid.storage.type=local +#druid.storage.storageDirectory=var/druid/segments + +druid.storage.type=hdfs +druid.storage.storageDirectory=/druid/segments + +#druid.indexer.logs.type=file +#druid.indexer.logs.directory=var/druid/indexing-logs + +druid.indexer.logs.type=hdfs +druid.indexer.logs.directory=/druid/indexing-logs +``` + +同时: + +* 需要将Hadoop的配置文件(core-site.xml, hdfs-site.xml, yarn-site.xml, mapred-site.xml)放置在Druid进程的classpath中,可以将他们拷贝到`conf/druid/cluster/_common`目录中 + +更多信息可以看[HDFS扩展](../Configuration/core-ext/hdfs.md)部分的文档。 + +### Hadoop连接配置 + +如果要从Hadoop集群加载数据,那么此时应对Druid做如下配置: + +* 在`conf/druid/cluster/_common/common.runtime.properties`文件中更新`druid.indexer.task.hadoopWorkingPath`配置项,将其更新为您期望的一个用于临时文件存储的HDFS路径。 通常会配置为`druid.indexer.task.hadoopWorkingPath=/tmp/druid-indexing` +* 需要将Hadoop的配置文件(core-site.xml, hdfs-site.xml, yarn-site.xml, mapred-site.xml)放置在Druid进程的classpath中,可以将他们拷贝到`conf/druid/cluster/_common`目录中 + +请注意,您无需为了可以从Hadoop加载数据而使用HDFS深度存储。例如,如果您的集群在Amazon Web Services上运行,即使您使用Hadoop或Elastic MapReduce加载数据,我们也建议使用S3进行深度存储。 + +更多信息可以看[基于Hadoop的数据摄取](../DataIngestion/hadoopbased.md)部分的文档。 + +### Zookeeper连接配置 + +在生产集群中,我们建议使用专用的ZK集群,该集群与Druid服务器分开部署。 + +在 `conf/druid/cluster/_common/common.runtime.properties` 中,将 `druid.zk.service.host` 设置为包含用逗号分隔的host:port对列表的连接字符串,每个对与ZK中的ZooKeeper服务器相对应。(例如" 127.0.0.1:4545"或"127.0.0.1:3000,127.0.0.1:3001、127.0.0.1:3002") + +您也可以选择在Master服务上运行ZK,而不使用专用的ZK集群。如果这样做,我们建议部署3个Master服务,以便您具有ZK仲裁。 + +### 配置调整 +#### 从单服务器环境迁移部署 +##### Master服务 + +如果您使用的是[单服务器部署示例](./chapter-3.md)中的示例配置,则这些示例中将Coordinator和Overlord进程合并为一个合并的进程。 + +`conf/druid/cluster/master/coordinator-overlord` 下的示例配置同样合并了Coordinator和Overlord进程。 + +您可以将现有的 `coordinator-overlord` 配置从单服务器部署复制到`conf/druid/cluster/master/coordinator-overlord` + +##### Data服务 + +假设我们正在从一个32CPU和256GB内存的单服务器部署环境进行迁移,在老的环境中,Historical和MiddleManager使用了如下的配置: + +Historical(单服务器) + +```json +druid.processing.buffer.sizeBytes=500000000 +druid.processing.numMergeBuffers=8 +druid.processing.numThreads=31 +``` + +MiddleManager(单服务器) + +```json +druid.worker.capacity=8 +druid.indexer.fork.property.druid.processing.numMergeBuffers=2 +druid.indexer.fork.property.druid.processing.buffer.sizeBytes=100000000 +druid.indexer.fork.property.druid.processing.numThreads=1 +``` + +在集群部署中,我们选择一个分裂因子(假设为2),则部署2个16CPU和128GB内存的Data服务,各项的调整如下: + +Historical + +* `druid.processing.numThreads`设置为新硬件的(`CPU核数 - 1`) +* `druid.processing.numMergeBuffers` 使用分裂因子去除单服务部署环境的值 +* `druid.processing.buffer.sizeBytes` 该值保持不变 + +MiddleManager: + +* `druid.worker.capacity`: 使用分裂因子去除单服务部署环境的值 +* `druid.indexer.fork.property.druid.processing.numMergeBuffers`: 该值保持不变 +* `druid.indexer.fork.property.druid.processing.buffer.sizeBytes`: 该值保持不变 +* `druid.indexer.fork.property.druid.processing.numThreads`: 该值保持不变 + +调整后的结果配置如下: + +新的Historical(2 Data服务器) + +```json + druid.processing.buffer.sizeBytes=500000000 + druid.processing.numMergeBuffers=8 + druid.processing.numThreads=31 + ``` + +新的MiddleManager(2 Data服务器) + +```json +druid.worker.capacity=4 +druid.indexer.fork.property.druid.processing.numMergeBuffers=2 +druid.indexer.fork.property.druid.processing.buffer.sizeBytes=100000000 +druid.indexer.fork.property.druid.processing.numThreads=1 +``` + +##### Query服务 + +您可以将现有的Broker和Router配置复制到`conf/druid/cluster/query`下的目录中,无需进行任何修改. + +#### 首次部署 + +如果您正在使用如下描述的示例集群规格: + +* 1 Master 服务器(m5.2xlarge) +* 2 Data 服务器(i3.4xlarge) +* 1 Query 服务器(m5.2xlarge) + +`conf/druid/cluster`下的配置已经为此硬件确定了,一般情况下您无需做进一步的修改。 + +如果您选择了其他硬件,则[基本的集群调整指南](../Operations/basicClusterTuning.md)可以帮助您调整配置大小。 + +### 开启端口(如果使用了防火墙) + +如果您正在使用防火墙或其他仅允许特定端口上流量准入的系统,请在以下端口上允许入站连接: + +#### Master服务 + +* 1527(Derby元数据存储,如果您正在使用一个像MySQL或者PostgreSQL的分离的元数据存储则不需要) +* 2181(Zookeeper,如果使用了独立的ZK集群则不需要) +* 8081(Coordinator) +* 8090(Overlord) + +#### Data服务 + +* 8083(Historical) +* 8091,8100-8199(Druid MiddleManager,如果`druid.worker.capacity`参数设置较大的话,则需要更多高于8199的端口) + +#### Query服务 + +* 8082(Broker) +* 8088(Router,如果使用了) + +> [!WARNING] +> 在生产中,我们建议将ZooKeeper和元数据存储部署在其专用硬件上,而不是在Master服务器上。 + +### 启动Master服务 + +将Druid发行版和您编辑的配置文件复制到Master服务器上。 + +如果您一直在本地计算机上编辑配置,则可以使用rsync复制它们: + +```json +rsync -az apache-druid-0.17.0/ MASTER_SERVER:apache-druid-0.17.0/ +``` + +#### 不带Zookeeper启动 + +在发行版根目录中,运行以下命令以启动Master服务: +```json +bin/start-cluster-master-no-zk-server +``` + +#### 带Zookeeper启动 + +如果计划在Master服务器上运行ZK,请首先更新`conf/zoo.cfg`以标识您计划如何运行ZK,然后,您可以使用以下命令与ZK一起启动Master服务进程: +```json +bin/start-cluster-master-with-zk-server +``` + +> [!WARNING] +> 在生产中,我们建议将ZooKeeper运行在其专用硬件上。 + +### 启动Data服务 + +将Druid发行版和您编辑的配置文件复制到您的Data服务器。 + +在发行版根目录中,运行以下命令以启动Data服务: +```json +bin/start-cluster-data-server +``` + +您可以在需要的时候增加更多的Data服务器。 + +> [!WARNING] +> 对于具有复杂资源分配需求的集群,您可以将Historical和MiddleManager分开部署,并分别扩容组件。这也使您能够利用Druid的内置MiddleManager自动伸缩功能。 + +### 启动Query服务 +将Druid发行版和您编辑的配置文件复制到您的Query服务器。 + +在发行版根目录中,运行以下命令以启动Query服务: + +```json +bin/start-cluster-query-server +``` + +您可以根据查询负载添加更多查询服务器。 如果增加了查询服务器的数量,请确保按照[基本集群调优指南](../Operations/basicClusterTuning.md)中的说明调整Historical和Task上的连接池。 + +### 加载数据 + +恭喜,您现在有了Druid集群!下一步是根据使用场景来了解将数据加载到Druid的推荐方法。 + +了解有关[加载数据](../DataIngestion/index.md)的更多信息。 + + diff --git a/GettingStarted/img/tutorial-quickstart-01.png b/GettingStarted/img/tutorial-quickstart-01.png new file mode 100644 index 0000000000000000000000000000000000000000..d6ee11bac1798c414db42dab81f99d2ef54471d4 GIT binary patch literal 67013 zcma%jbyQVd*RLW6ZdBsX($dlm(hUlSI)F$w$f3Kt?&f*l@B8E4 z$1(00dpPzu?6uZhzZrY(xqj1dWknfOWJ2U;&z_;m$x5m|dj=1C_6#lv@fGk3yX`c~ zvuEVbZ3JdAWv%g$H z3P@hcU{?ksTtzr)v46iJo`vvvz+;j>|Mv_03=SJc`HaKq-MlB&}#Ssg;>wo+7*qCyQ8zf z@FoJ`>M)HVSFFS`GZzx01KgYdr=I;PZghDTMG*B}L;+BLuQ!eq@DCbH|fl zu>T%Tr^Dm07y{SXsFn$ccwM2Vup0G<(mhCti3R2OaH?IQgTWVQ*=aS{Pa1S4gG=SK zP+zXUI$llfaM0a%TxvlT?Zj(xyGDL%)C?0ziZSP2xnzjv#xGNNa*@$Qu|-|(FU&e) zmsy4zZILOJ;6n8%;fAeOJ)O*@98OCuBv!w&I5ofg(no^z$t(#q$I*fquV@u4#~2+K zTRsQIWdCp#70sjx*{^ZNfqjA|!uk2V=RRo)Sfq}6iFb?nvx5R{$L-`Ytgn9eh|hJ( za*EeK0Mcqc@Mp2PY`kY4N-n+-6~g4ax6HYsY3YT1rc=51m8&g#9@%A*QA;xI5uR^w zGid-?x;!0<@G9BliGgCwr2~=@CZFt^Jbh!BuJp0Yz&1?F!*VtwqB6&?6=Yy zS_y|mu_L)q2DN)#tKJ({n!Du7XT4@MyfWLK6V)(8;uO9)BuEbv1k>qt=+9Q$Jz}Wc z@2_9;sR>}Ss*(pUqXg~=I7^cJCO_YrZssoK**AvIQxJv?8ByycMIsi=qvO}UXCa#E zx>nHoZg%+2Kq`sp8YiAwG5F=+^j6D*gyC95cud9S_U{V>gIFk9^4s@uFv?RNG`rT` zqmwSHX4gMg1GQdQ`1lN2%Op$;pL>kqWm<6N-mnmvKCT2hA8m!B#Y_@V986WrYugzA zWYD@OZ*spRB^C9)`I&twq45J}nXY}ALT_X*ibUZnxyT30Tl{IK#SOzYvQn($jwjzn z{|GP1R;t_lX`oi#aev5@3a)Giw~=GhePhp?#w(mJS$LkVG~k361J=Q+rOTf5vRb3F z3MB6V6S5P)R znsfO$%dZiXfaj#oAyIF3m}BO)o+03a9#5wbQ5roj&?e%rgI%m~?fX8n7M}H<>Os;_ ztD&+V(h8KN+qQT8QW|6VF*AmFbvPItrh0aJ6WJ&FWa*ex^oE2}5Ov5b#h+aq!@U zi{4l{uSqXE21~%UlWFdLRYDc|{1h6&f(jJB^!Ko;nl);B z&1Ta?m*>+J1JZ?Z$+9}VN@$BV*7^L5Yf<#se@{j<^8CU1OvB(&{IY-w%ELtdOLe4TUr7X}Dp53lDk84~5bD2D{LUl-nJo7h|-KKEX|i z1OC;=#(Sr%6TIlWZ;L( zsOsvWMBy13#k)^lJE^+7rJvsujOE<^h%2drXxK^Y!}w2ecg7eqDiZX`wuAXf>R3j2F}Cj%QpDRdEB0%?IR92; zA<8kiHRS1*U5BXaiD%S*Q9d@+<9BUa^q-dmCvcgK%AXtAg}nvOc&?mi+?~w(m5qE` z*J<#`8@3~Mhu3=Tww}d-QKH*yT09@wT2efqD>KbwI`I}6(d%=MLWuI!EU@(r!sxNwz_dQ9L`pi#xcv8Mv>f6 znX|EYTX3jf%)@wuVM4;f>}^hXYXhk-NP}#vzOtMCm>#04)J!^5sbBD9)IT4n-JEIj z=PhK_jscK;SASBF^yTJYQE;KdlMFO>DGrlFVlTErFdz6zN}83$7kG>ukjjIQQnlzj zk)il_P#bFWfvozUVD&PDsR)AGV}0nWJ>8vzvNmqgDjj z4SIG*m3#elz?S3e^hXx@Ar{8VVE5W&^(%r46qDdO z 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 Iol`;+0Kf24BLDyZ literal 0 HcmV?d00001 diff --git a/design/index.md b/design/index.md index d803a70..64fdba5 100644 --- a/design/index.md +++ b/design/index.md @@ -1,28 +1,7 @@ ---- -id: index -title: "Introduction to Apache Druid" ---- +# Druid 介绍 +本页面对 Druid 的基本情况进行了一些介绍和简要说明。 - - -## What is Druid? +## 什么是 Druid Apache Druid is a real-time analytics database designed for fast slice-and-dice analytics ("[OLAP](http://en.wikipedia.org/wiki/Online_analytical_processing)" queries) on large data sets. Druid is most often @@ -74,27 +53,69 @@ offers exact count-distinct and exact ranking. 10. **Automatic summarization at ingest time.** Druid optionally supports data summarization at ingestion time. This summarization partially pre-aggregates your data, and can lead to big costs savings and performance boosts. -## When should I use Druid? -Druid is used by many companies of various sizes for many different use cases. Check out the -[Powered by Apache Druid](/druid-powered) page +Apache Druid是一个实时分析型数据库,旨在对大型数据集进行快速的查询分析("[OLAP](https://en.wikipedia.org/wiki/Online_analytical_processing)"查询)。Druid最常被当做数据库来用以支持实时摄取、高性能查询和高稳定运行的应用场景,同时,Druid也通常被用来助力分析型应用的图形化界面,或者当做需要快速聚合的高并发后端API,Druid最适合应用于面向事件类型的数据。 -Druid is likely a good choice if your use case fits a few of the following descriptors: +Druid通常应用于以下场景: -- Insert rates are very high, but updates are less common. -- Most of your queries are aggregation and reporting queries ("group by" queries). You may also have searching and -scanning queries. -- You are targeting query latencies of 100ms to a few seconds. -- Your data has a time component (Druid includes optimizations and design choices specifically related to time). -- You may have more than one table, but each query hits just one big distributed table. Queries may potentially hit more -than one smaller "lookup" table. -- You have high cardinality data columns (e.g. URLs, user IDs) and need fast counting and ranking over them. -- You want to load data from Kafka, HDFS, flat files, or object storage like Amazon S3. +* 点击流分析(Web端和移动端) +* 网络监测分析(网络性能监控) +* 服务指标存储 +* 供应链分析(制造类指标) +* 应用性能指标分析 +* 数字广告分析 +* 商务智能 / OLAP -Situations where you would likely _not_ want to use Druid include: +Druid的核心架构吸收和结合了[数据仓库](https://en.wikipedia.org/wiki/Data_warehouse)、[时序数据库](https://en.wikipedia.org/wiki/Time_series_database)以及[检索系统](https://en.wikipedia.org/wiki/Search_engine_(computing))的优势,其主要特征如下: -- You need low-latency updates of _existing_ records using a primary key. Druid supports streaming inserts, but not streaming updates (updates are done using -background batch jobs). -- You are building an offline reporting system where query latency is not very important. -- You want to do "big" joins (joining one big fact table to another big fact table) and you are okay with these queries -taking a long time to complete. +1. **列式存储**,Druid使用列式存储,这意味着在一个特定的数据查询中它只需要查询特定的列,这样极地提高了部分列查询场景的性能。另外,每一列数据都针对特定数据类型做了优化存储,从而支持快速的扫描和聚合。 +2. **可扩展的分布式系统**,Druid通常部署在数十到数百台服务器的集群中,并且可以提供每秒数百万条记录的接收速率,数万亿条记录的保留存储以及亚秒级到几秒的查询延迟。 +3. **大规模并行处理**,Druid可以在整个集群中并行处理查询。 +4. **实时或批量摄取**,Druid可以实时(已经被摄取的数据可立即用于查询)或批量摄取数据。 +5. **自修复、自平衡、易于操作**,作为集群运维操作人员,要伸缩集群只需添加或删除服务,集群就会在后台自动重新平衡自身,而不会造成任何停机。如果任何一台Druid服务器发生故障,系统将自动绕过损坏。 Druid设计为7*24全天候运行,无需出于任何原因而导致计划内停机,包括配置更改和软件更新。 +6. **不会丢失数据的云原生容错架构**,一旦Druid摄取了数据,副本就安全地存储在[深度存储介质](Design/../chapter-1.md)(通常是云存储,HDFS或共享文件系统)中。即使某个Druid服务发生故障,也可以从深度存储中恢复您的数据。对于仅影响少数Druid服务的有限故障,副本可确保在系统恢复时仍然可以进行查询。 +7. **用于快速过滤的索引**,Druid使用[CONCISE](https://arxiv.org/pdf/1004.0403.pdf)或[Roaring](https://roaringbitmap.org/)压缩的位图索引来创建索引,以支持快速过滤和跨多列搜索。 +8. **基于时间的分区**,Druid首先按时间对数据进行分区,另外同时可以根据其他字段进行分区。这意味着基于时间的查询将仅访问与查询时间范围匹配的分区,这将大大提高基于时间的数据的性能。 +9. **近似算法**,Druid应用了近似count-distinct,近似排序以及近似直方图和分位数计算的算法。这些算法占用有限的内存使用量,通常比精确计算要快得多。对于精度要求比速度更重要的场景,Druid还提供了精确count-distinct和精确排序。 +10. **摄取时自动汇总聚合**,Druid支持在数据摄取阶段可选地进行数据汇总,这种汇总会部分预先聚合您的数据,并可以节省大量成本并提高性能。 + + +## 我应该在什么时候使用 Druid + +许多公司都已经将 Druid 应用于多种不同的应用场景。请访问 [使用 Apache Druid 的公司](https://druid.apache.org/druid-powered) 页面来了解都有哪些公司使用了 Druid。 + +如果您的使用场景符合下面的一些特性,那么Druid 将会是一个非常不错的选择: + +- 数据的插入频率非常高,但是更新频率非常低。 +- 大部分的查询为聚合查询(aggregation)和报表查询(reporting queries),例如我们常使用的 "group by" 查询。同时还有一些检索和扫描查询。 +- 查询的延迟被限制在 100ms 到 几秒钟之间。 +- 你的数据具有时间组件(属性)。针对时间相关的属性,Druid 进行特殊的设计和优化。 +- 你可能具有多个数据表,但是查询通常只针对一个大型的分布数据表,但是,查询又可能需要查询多个较小的 `lookup` 表。 +- 如果你的数据中具有高基数(high cardinality)数据字段,例如 URLs、用户 IDs,但是你需要对这些字段进行快速计数和排序。 +- 你需要从 Kafka,HDFS,文本文件,或者对象存储(例如,AWS S3)中载入数据。 + + +如果你的使用场景是下面的一些情况的话,Druid **不是**一个较好的选择: + +- 针对一个已经存在的记录,使用主键(primary key)进行低延迟的更新操作。Druid 支持流式插入(streaming inserts)数据,但是并不很好的支持流式更新(streaming updates)数据。 + Druid 的更新操作是通过后台批处理完成的。 +- 你的系统类似的是一个离线的报表系统,查询的延迟不是系统设计的重要考虑。 +- 使用场景中需要对表(Fact Table)进行连接查询,并且针对这个查询你可以介绍比较高的延迟来等待查询的完成。 + + +### 高基数 +在 SQL 中,基数(cardinality)的定义为一个数据列中独一无二数据的数量。 + +高基数(High-Cardinality)的定义为在一个数据列中的数据基本上不重复,或者说重复率非常低。 + +例如我们常见的识别号,邮件地址,用户名等都可以被认为是高基数数据。 +例如我们常定义的 USERS 数据表中的 USER_ID 字段,这个字段中的数据通常被定义为 1 到 n。每一次一个新的用户被作为记录插入到 USERS 表中,一个新的记录将会被创建, +字段 USER_ID 将会使用一个新的数据来标识这个被插入的数据。因为 USER_ID 中插入的数据是独一无二的,因此这个字段的数据技术就可以被考虑认为是 高基数(High-Cardinality) 数据。 + + +### Fact Table +与 Fact Table 对应的表是 Dimension Table。 + +这 2 个表是数据仓库的两个概念,为数据仓库的两种类型表。 从保存数据的角度来说,本质上没区别,都是表。 +区别主要在数据和用途上,Fact Table 用来存 fact 数据,就是一些可以计量的数据和可加性数据,数据数量,金额等。 +Dimension Table 用来存描述性的数据,比如说用来描述 Fact 表中的数据,如区域,销售代表,产品等。 \ No newline at end of file