HTTP 客户端

HTTP 接口可以让你通过任何平台和编程语言来使用 ClickHouse。我们用 Java 和 Perl 以及 shell 脚本来访问它。在其他的部门中,HTTP 接口会用在 Perl,Python 以及 Go 中。HTTP 接口比 TCP 原生接口更为局限,但是却有更好的兼容性。

默认情况下,clickhouse-server 会在端口 8123 上监控 HTTP 请求(这可以在配置中修改)。 如果你发送了一个不带参数的 GET 请求,它会返回一个字符串 "Ok"(结尾有换行)。可以将它用在健康检查脚本中。

$ curl 'http://localhost:8123/'
Ok.

通过 URL 中的 query 参数来发送请求,或者发送 POST 请求,或者将查询的开头部分放在 URL 的 query 参数中,其他部分放在 POST 中(我们会在后面解释为什么这样做是有必要的)。URL 的大小会限制在 16 KB,所以发送大型查询时要时刻记住这点。

如果请求成功,将会收到 200 的响应状态码和响应主体中的结果。 如果发生了某个异常,将会收到 500 的响应状态码和响应主体中的异常描述信息。

当使用 GET 方法请求时,readonly 会被设置。换句话说,若要作修改数据的查询,只能发送 POST 方法的请求。可以将查询通过 POST 主体发送,也可以通过 URL 参数发送。

Examples:

$ curl 'http://localhost:8123/?query=SELECT%201'
1

$ wget -O- -q 'http://localhost:8123/?query=SELECT 1'
1

$ GET 'http://localhost:8123/?query=SELECT 1'
1

$ echo -ne 'GET /?query=SELECT%201 HTTP/1.0\r\n\r\n' | nc localhost 8123
HTTP/1.0 200 OK
Connection: Close
Date: Fri, 16 Nov 2012 19:21:50 GMT

1

可以看到,curl 命令由于空格需要 URL 转义,所以不是很方便。尽管 wget 命令对url做了 URL 转义,但我们并不推荐使用他,因为在 HTTP 1.1 协议下使用 keep-alive 和 Transfer-Encoding: chunked 头部设置它并不能很好的工作。

$ echo 'SELECT 1' | curl 'http://localhost:8123/' --data-binary @-
1

$ echo 'SELECT 1' | curl 'http://localhost:8123/?query=' --data-binary @-
1

$ echo '1' | curl 'http://localhost:8123/?query=SELECT' --data-binary @-
1

如果一部分请求是通过参数发送的,另外一部分通过 POST 主体发送,两部分查询之间会一行空行插入。 错误示例:

$ echo 'ECT 1' | curl 'http://localhost:8123/?query=SEL' --data-binary @-
Code: 59, e.displayText() = DB::Exception: Syntax error: failed at position 0: SEL
ECT 1
, expected One of: SHOW TABLES, SHOW DATABASES, SELECT, INSERT, CREATE, ATTACH, RENAME, DROP, DETACH, USE, SET, OPTIMIZE., e.what() = DB::Exception

默认情况下,返回的数据是 TabSeparated 格式的,更多信息,见 "[数据格式]" 部分。 可以使用 FORMAT 设置查询来请求不同格式。

$ echo 'SELECT 1 FORMAT Pretty' | curl 'http://localhost:8123/?' --data-binary @-
┏━━━┓
┃ 1 ┃
┡━━━┩
│ 1 │
└───┘

INSERT 必须通过 POST 方法来插入数据。这种情况下,你可以将查询的开头部分放在 URL 参数中,然后用 POST 主体传入插入的数据。插入的数据可以是,举个例子,从 MySQL 导出的以 tab 分割的数据。在这种方式中,INSERT 查询取代了 LOAD DATA LOCAL INFILE from MySQL。

示例: 创建一个表:

echo 'CREATE TABLE t (a UInt8) ENGINE = Memory' | POST 'http://localhost:8123/'

使用类似 INSERT 的查询来插入数据:

echo 'INSERT INTO t VALUES (1),(2),(3)' | POST 'http://localhost:8123/'

数据可以从查询中单独发送:

echo '(4),(5),(6)' | POST 'http://localhost:8123/?query=INSERT INTO t VALUES'

可以指定任何数据格式。值的格式和写入表 t 的值的格式相同:

echo '(7),(8),(9)' | POST 'http://localhost:8123/?query=INSERT INTO t FORMAT Values'

若要插入 tab 分割的数据,需要指定对应的格式:

echo -ne '10\n11\n12\n' | POST 'http://localhost:8123/?query=INSERT INTO t FORMAT TabSeparated'

从表中读取内容。由于查询处理是并行的,数据以随机顺序输出。

$ GET 'http://localhost:8123/?query=SELECT a FROM t'
7
8
9
10
11
12
1
2
3
4
5
6

删除表。

POST 'http://localhost:8123/?query=DROP TABLE t'

成功请求后并不会返回数据,返回一个空的响应体。

可以通过压缩来传输数据。压缩的数据没有一个标准的格式,但你需要指定一个压缩程序来使用它(sudo apt-get install compressor-metrika-yandex)。

如果在 URL 中指定了 compress=1 ,服务会返回压缩的数据。 如果在 URL 中指定了 decompress=1 ,服务会解压通过 POST 方法发送的数据。

可以通过为每份数据进行立即压缩来减少大规模数据传输中的网络压力。

可以指定 'database' 参数来指定默认的数据库。

$ echo 'SELECT number FROM numbers LIMIT 10' | curl 'http://localhost:8123/?database=system' --data-binary @-
0
1
2
3
4
5
6
7
8
9

默认情况下,默认数据库会在服务的配置中注册,默认是 default。或者,也可以在表名之前使用一个点来指定数据库。

用户名密码可以通过以下两种方式指定:

  1. 通过 HTTP Basic Authentication。示例:
echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
  1. 通过 URL 参数 中的 'user' 和 'password'。示例:
echo 'SELECT 1' | curl 'http://localhost:8123/?user=user&password=password' -d @-

如果用户名没有指定,默认的用户是 default。如果密码没有指定,默认会使用空密码。 可以使用 URL 参数指定配置或者设置整个配置文件来处理单个查询。示例:http://localhost:8123/?profile=web&max_rows_to_read=1000000000&query=SELECT+1

更多信息,参见 "设置" 部分。

$ echo 'SELECT number FROM system.numbers LIMIT 10' | curl 'http://localhost:8123/?' --data-binary @-
0
1
2
3
4
5
6
7
8
9

更多关于其他参数的信息,参见 "设置" 部分。

相比起 TCP 原生接口,HTTP 接口不支持会话和会话设置的概念,不允许中止查询(准确地说,只在少数情况下允许),不显示查询处理的进展。执行解析和数据格式化都是在服务端处理,网络上会比 TCP 原生接口更低效。

可选的 query_id 参数可能当做 query ID 传入(或者任何字符串)。更多信息,参见 "设置 replace_running_query" 部分。

可选的 quota_key 参数可能当做 quota key 传入(或者任何字符串)。更多信息,参见 "配额" 部分。

HTTP 接口允许传入额外的数据(外部临时表)来查询。更多信息,参见 "外部数据查询处理" 部分。

响应缓冲

可以在服务器端启用响应缓冲。提供了 buffer_sizewait_end_of_query 两个URL 参数来达此目的。

buffer_size 决定了查询结果要在服务内存中缓冲多少个字节数据. 如果响应体比这个阈值大,缓冲区会写入到 HTTP 管道,剩下的数据也直接发到 HTTP 管道中。

为了确保整个响应体被缓冲,可以设置 wait_end_of_query=1。这种情况下,存入内存的数据会被缓冲到服务端的一个临时文件中。

示例:

curl -sS 'http://localhost:8123/?max_result_bytes=4000000&buffer_size=3000000&wait_end_of_query=1' -d 'SELECT toUInt8(number) FROM system.numbers LIMIT 9000000 FORMAT RowBinary'

查询请求响应状态码和 HTTP 头被发送到客户端后,若发生查询处理出错,使用缓冲区可以避免这种情况的发生。在这种情况下,响应主体的结尾会写入一条错误消息,而在客户端,只能在解析阶段检测到该错误。