精华 同样数据和表,命令行可导入、http导入失败
发布于 5 个月前 作者 kikanjuu 950 次浏览 来自 问答

我有一批csv数据,首先尝试用clickhouse-client命令行导入成功;然后用curl进行http post导入失败。所以怀疑是curl命令行不正确,如编码。 具体如下图:

aa.jpg

求助。感觉ClickHouse报错信息好少。

附: 表结构: CREATE TABLE IF NOT EXISTS client_log_100w ( serverDate Date, channel String, version String, carrierOperator String, deviceId String, deviceName String, deviceType String, manufacturer String, networkMode String, os String, ip String, userAgent String, serverTime UInt64, uid String, height UInt32, width UInt32, latitude Float64, longitude Float64, responseCode String, resource String, clientTime UInt64, tid String, traffic String, playResource String, srcPage String, srcPageId String, srcModule String, srcPosition String, srcSubModule String, moduleType String, item String, itemId String, appName String, x_abtest_bucketIds String, offline_data_gentime UInt64, x_client_sendtime UInt64, type String, copy UInt32 ) ENGINE = MergeTree(serverDate, (deviceId), 8192)

curl命令行: curl -H “Content-Type:text/plain; charset=utf-8” --data-ascii @test.csv ‘http://localhost:8123/?query=INSERT INTO client_log_100w FORMAT CSVWithNames VALUES

csv源数据 test.csv: === START === serverDate,channel,version,carrierOperator,deviceId,deviceName,deviceType,manufacturer,networkMode,os,ip,userAgent,serverTime,uid,height,width,latitude,longitude,responseCode,resource,clientTime,tid,traffic,playResource,srcPage,srcPageId,srcModule,srcPosition,srcSubModule,moduleType,item,itemId,props[appName],props[x-abtest-bucketIds],props[offline_data_gentime],props[x_client_sendtime],props[type],copy 2018-04-16,and-inapp,6.3.81,中国移动,00000000-0a8f-ceff-cb60-80493a7fdafe,android,M3s,Meizu,WIFI,Android22,1.1.1.1,“aa(M3s,Android22)”,1523888919327,1280,720,99.61421585083008,99.93814086914062,xm_source:relationRecommend&xm_medium:track&rec_track:ItemG.105&rec_src:MAIN,1523888982890,1669616570337501418,album,12262096,TAB,button,content,event,100146,1523888284727,1523888982509,0 2018-04-16,and-d10,6.3.84,中国联通,ffffffff-a0b5-e647-b8f0-f9933d7ff2ee,android,MIX 2,Xiaomi,WIFI,Android26,1.1.1.2,“aa(MIX+2,Android26)”,1523888924229,52992687,2030,1080,99.09974670410156,99.2834243774414,xm_source:search&xm_term:学会说话,1523888924539,2762763508220026884,album,12473536,TAB,button,content,event,100146,1523888924382,1523888924382,0 === END ===

40 回复

问题已解决。

  1. 我应该用INSERT INTO … FORMAT CSVWithNames而不是INSERT INTO … FORMAT CSVWithNames VALUES 应该去掉最后的VALUES。加了VALUES,就变成SQL标准语法,后面必须是一个左括号了。

  2. curl要加–data-binary参数。否则curl会把换行都去掉。

大神,CSV数据导入到其中一个节点,其他两个节点没有同步,这个正常吗?我直接插入的时候都是同步的

@mayday 我没看明白您的问题。请描述下技术参数——表引擎、副本数、副本设置、节点部署拓扑、同步机制是什么,等等

@kikanjuu这是我的配置文件 <yandex>

<clickhouse_remote_servers> <perftest_3shards_1replicas>

    <shard>
        <weight>1</weight>
        <internal_replication>false</internal_replication>
        <replica>
            <host>data1</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data2</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data3</host>
            <port>9000</port>
        </replica>
    </shard>

    <shard>
        <weight>2</weight>
        <internal_replication>false</internal_replication>
        <replica>
            <host>data1</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data2</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data3</host>
            <port>9000</port>
        </replica>
    </shard>

    <shard>
        <weight>3</weight>
        <internal_replication>false</internal_replication>
        <replica>
            <host>data1</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data2</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data3</host>
            <port>9000</port>
        </replica>
    </shard>

</perftest_3shards_1replicas>

</clickhouse_remote_servers> 引擎是MergeTree,我在三个节点都创建了同一张表,在data1上导入csv文件,进入data1能查到数据,但是在data2和data3上没有数据

@mayday 你还要基于各个节点的MergeTree表,建立一张分布式表 https://clickhouse.yandex/docs/en/table_engines/distributed/

<internal_replication>false</internal_replication> 设置正确,会导致写入多个副本。 然而internal_replication这个配置,是由分布式表识别的。光有MergeTree表还不够。

看这贴:http://www.clickhouse.com.cn/topic/5b04ba079d28dfde2ddc6078 你缺了下图红框中的分布式表。 image.png

@kikanjuu 好的,我试一试

@kikanjuu 大神,不好意思,还得再麻烦你一下,这是我的建表语句(YYMMDD是当天的日期如180528) CREATE TABLE nc.zc_gmap_ho_bdr${YYMMDD} ( start_time Int64, start_time_ns Int64, end_time Int64, end_time_ns Int64, cdr_id Int64, cdr_result Int64, frontno Int64, sour_ip Int64, dest_ip Int64, opc Int64, dpc Int64, calling_ssn Int64, called_ssn Int64, calling_gt String, called_gt String, sccp_opc Int64, sccp_dpc Int64, operate_code Int64, result Int64, error_code Int64, msisdn String, msisdn_type Int64, imsi String, imei String, tmsi Int64, sour_msc String, dest_msc String, target_msc String, sour_lac Int64, dest_lac Int64, sour_sac Int64, sour_ci Int64, dest_ci Int64, ho_num String, reloc_num String, ho_ref1 Int64, ho_ref2 Int64, ho_type Int64, ho_cause Int64, ho_result Int64, hofailure_cause Int64, resp_delay Int64, ho_time Int64, session_time Int64, udt_count Int64, udts_count Int64, proc_result Int64, EventDate Date) ENGINE=MergeTree(EventDate,(start_time,EventDate),8192) 分布式表:CREATE TABLE nc.zc_gmap_ho_bdr${YYMMDD}_all AS nc.zc_gmap_ho_bdr${YYMMDD} ENGINE = Distributed(perftest_3shards_1replicas,nc,zc_gmap_ho_bdr${YYMMDD},rand()) 我在data1导入CSV数据以后,是有数据的图片.png 但data2和data3都没有,图片.png 你说的这个配置<internal_replication>false</internal_replication>是要将false改完true吗? 还有个小问题,perftest_3shards_1replicas这个是自定义在配置文件里的吗?我看你的是bip_ck_cluster

@kikanjuu 实在不好意思,我刚接触这个,问题可能比较多。分布式表后面的参数我理解为(集群名称,数据库名,本地表名)后面那个rand()我不太清楚,大神能解释下吗?是这么理解的吗?

@mayday

  1. 没必要CREATE TABLE nc.zc_gmap_hobdr${YYMMDD}这样每天建一张表。 只要对一张表,每天建一个分区即可。请阅读 https://clickhouse.yandex/docs/en/table_engines/mergetree/

    同理,也没有必要每天新建一张zc_gmap_ho_bdr${YYMMDD}_all表。

  2. 你的INSERT语句,应该往zc_gmap_ho_bdr${YYMMDD}_all里写入,而不是往nc.zc_gmap_hobdr${YYMMDD}里写入。这里没搞错吧?

  3. <internal_replication>false</internal_replication>设置为false是正确的,不要设置为true

  4. 关于rand()的含义,请阅读https://clickhouse.yandex/docs/en/table_engines/distributed/

perftest_3shards_1replicas 是定义在config.xml里的。

@kikanjuu 是我写错表了,写到分布式表里就有数据了,每个节点上的分布式表的select count(1)都是本地表的三倍,你看看我的配置文件可行吗?这样是不是太浪费空间了?

@mayday “每个节点上的分布式表的select count(1)都是本地表的三倍” 这不应该出现。 分布式表查询一个shard时,只会访问这个shard里的三个replica中的一个。所以select count(1)还是返回一倍的数据量,不会是三倍。

参见:https://clickhouse.yandex/docs/en/table_engines/distributed/ When specifying replicas, one of the available replicas will be selected for each of the shards when reading.

按说上面说的,一个shard的3个副本里,只有一个副本在查询时会被读到。所以还是返回一倍的数据。

@mayday 你既然做了3副本(一个shard里有三个replica),那么就是在浪费空间,换取数据备份、高可用。这是正常的。

@kikanjuu 意思就是我现在是九份数据了,每个节点三份数据?我想要的是三个节点每个节点一份数据就够了,是配置不对吗?

@mayday 改成这样对吗?这样是高可用吗?我最后想要的结果是每个节点一份数据,任何一个节点或两个节点宕了其余节点依然能查到数据 <shard> <weight>1</weight> <internal_replication>false</internal_replication> <replica> <host>data1</host> <port>9000</port> </replica> </shard>

<shard>
    <weight>2</weight>
    <internal_replication>false</internal_replication>
    <replica>
        <host>data2</host>
        <port>9000</port>
    </replica>
    </shard>

<shard>
    <weight>3</weight>
    <internal_replication>false</internal_replication>
    <replica>
    <host>data3</host>
        <port>9000</port>
    </replica>
</shard>

请解答下我的这四个问题:

  1. 你希望有几个shard ?
  2. 你希望有几个副本?
  3. <weight></weight>是控制写入流量权重,不是用来控制副本数、Shard数的。为什么把weight分别设为了1, 2, 3 ?
  4. 关于Shard和副本的区别是什么,<weight>的概念,请阅读全文:https://clickhouse.yandex/docs/en/table_engines/distributed/ 这篇文章读过了吗?

@kikanjuu 你好,我理解的shard就是分片服务器,副本数就是数据备份数,weight是写文件的权重。我现在三台机器,希望每台机器各有一个副本

@kikanjuu clickhouse如何实现并发导入呢?我现在是把表分成了三部分,每个节点导入几张表,但单节点一张表的数据导入完了才能开始导入第二张表,能否同时导入多张表?

@mayday 可以并发导入。你的写入程序发起多个并发的连接,分别插入数据,就实现并发写入了。

@kikanjuu 大神,我现在有两张表,都是100亿条记录的数据,zc_gmap_mm_bdr1806这个表相当于单机模式下的表,只在data1上有;zc_gmap_mm_bdr1806_3 这个相当于集群模式下的表,在data1、2、3上都有(本地表和分布式表),我想对比一下两者的查询速度,结果都是差不多的,是我哪里配置有问题吗?三台机器内存都是128G,集群模式下的查询不应该把三台机器都利用起来吗? 图片.png 附上建表脚本,两个表都是一样的 图片.png

你所查询的zc_gmap_mm_bdr1806_3是一张ENGINE=MergeTree表。你应当查询一张ENGINE=Distributed的表,以实现并发、分布式查询。

@kikanjuu 为什么我现在查询分布式表count(1)还是返回三倍数据呢?本地表100亿,分布式表300亿 <clickhouse_remote_servers> <perftest_3shards_1replicas>

    <shard>
        <internal_replication>false</internal_replication>
        <replica>
            <host>data1</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data2</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data3</host>
            <port>9000</port>
        </replica>
    </shard>

    <shard>
        <internal_replication>false</internal_replication>
        <replica>
            <host>data1</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data2</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data3</host>
            <port>9000</port>
        </replica>
    </shard>

    <shard>
        <internal_replication>false</internal_replication>
        <replica>
            <host>data1</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data2</host>
            <port>9000</port>
        </replica>
        <replica>
        <host>data3</host>
            <port>9000</port>
        </replica>
    </shard>

</perftest_3shards_1replicas>

</clickhouse_remote_servers> 三个shard,三个replica,查询时不是应该只返回三个replica中的一个吗?

(1) 同一个host,只能出现在一个<shard>元素里。比如你的data2,在三个<shard>里都有,就查出重复数据了。 请读一下JackGao的PPT http://www.clickhouse.com.cn/topic/5b04ba079d28dfde2ddc6078 特别是这张: image.png 上图中,任何一台机器的ip,都只在一个<shard>里出现一次,没有出现两次以上。

(2) 如果你想做成多台机器,互为副本,互相备份,并且不能读出重复的数据, 参见 https://www.altinity.com/blog/2018/5/10/circular-replication-cluster-topology-in-clickhouse image.png 如上图,要正确设置<default_database>

@kikanjuu 我现在是设置成了3个分片1个副本 <shard> <replica> <host>data1</host> <port>9000</port> </replica> <shard>

<shard>
    <replica>
        <host>data2</host>
        <port>9000</port>
    </replica>
</shard>

<shard>
    <replica>
        <host>data3</host>
        <port>9000</port>
    </replica>
</shard>
为什么我在查询分布式表和本地表速度有时差不多有时快呢?是sql的原因吗?还是配置的问题?

企业微信截图_15294817273291.png

0.366 v.s. 0.644 ,显然是查询分布式表快。

@kikanjuu <shard> <internal_replication>false</internal_replication> <replica> <host>data1</host> <port>9000</port> </replica> </shard>

<shard>
    <internal_replication>false</internal_replication>
    <replica>
        <host>data2</host>
        <port>9000</port>
    </replica>
</shard>

<shard>
    <internal_replication>false</internal_replication>
    <replica>
        <host>data3</host>
        <port>9000</port>
    </replica>
</shard>
虽然是快三倍,但是查分布式表数据量还是本地表的三倍啊,我的host在每一个shard也没重复啊,这是个什么问题?我很郁闷啊

企业微信截图_15295598244200.png

查询分布式表,得到的是三个节点的物理表的数据总和,所以是每个节点的数据量的三倍。这很正常吧? 比如,A, B, C三个节点,各有10条数据;那么通过分布式表查出来,就是30条数据。这不代表数据重复了三遍。

这30条数据可以是完全不同的,在写入时分发到A,B,C三个节点上的。

写入时怎么分发呢?两种方案:

  1. 通过分布式表写入,而不是写单个节点的物理表。用INSERT INTO <分布式表> …
  2. 应用在客户端自己实现分发逻辑,分别连接各个ClickHouse节点,把每一条记录分发到A,B,C三个节点中的一个去。

你是用以上哪种方式实现写入时的分发的?

如果都不是,那么你的写入逻辑有问题,没有实现分发,就会导致一条记录写入了多个节点,产生了重复。

我个人感觉,你对分布式表与final表的区别,shard和副本的区别,理解得比较模糊。 个人建议你完整、细读以下两篇文章。希望你确保这两篇文章完全理解了,以解决基本概念问题: https://clickhouse.yandex/docs/en/table_engines/distributed/ https://clickhouse.yandex/docs/en/table_engines/mergetree/

我用的第一种方式,写分布式表,单表的数据量总共肯定只有100亿,如果我这么配置本地表和分布式表查出来就都是100亿了,但是这样不是只利用了一台机器吗?我想的是三台并发查询,提升速度 <shard> <internal_replication>false</internal_replication> <replica> <host>data1</host> <port>9000</port> </replica> <replica> <host>data2</host> <port>9000</port> </replica> <replica> <host>data3</host> <port>9000</port> </replica> </shard>

数据总量100亿,那么分布式表查出来也是100亿是正常的。如果本地表查出来也是100亿,说明数据全部写到其中一个节点上去了,没有均分到三个节点。

你说的本地表查出来是100亿,是指哪台机器的本地表? 其他两台机器的本地表有多少条记录?

@kikanjuu 三台机器的本地表都是100亿

@mayday 那么通过分布式表查出来应该是300亿。请贴出完整的(不要只贴部分):

  1. 本地表建表语句

  2. 分布式表建表语句

  3. config.xml全文 注意三台机器的config.xml内容应该完全相同

    另外,你说每个节点上的本地表都有100亿数据。那么不同节点的数据是重复的吗?

你发给我邮箱,论坛上其他人看不到,没法帮你。你想办法共享出来吧,用有道云笔记、云存储之类。

@kikanjuu 好像可以了,我再试下

@mayday 另外提个小建议,没有必要每天建一张表。我在本帖中已经解释过这个问题了,表太多管理起来麻烦。

“ 没必要CREATE TABLE nc.zc_gmap_hobdr${YYMMDD}这样每天建一张表。 只要对一张表,每天建一个分区即可。请阅读 https://clickhouse.yandex/docs/en/table_engines/mergetree/

同理,也没有必要每天新建一张zc_gmap_ho_bdr${YYMMDD}_all表。 ”

@kikanjuu 谢谢,这个之前考虑过,但是数据量太大,公司还是决定建天表,会有定期自动删表的脚本

@mayday 数据量大对表没有影响。一张大表底层还是按日期分目录的,物理结构和你手工分表一样。也可以用DROP PARTITION按天删数据。

做成大表的好处是,可以用一句SELECT跨天查询。按天建表,跨天查询会比较麻烦。

@kikanjuu 好的,我试试 有两个小问题 1、csv数据导入速度会受主机内存大小影响吗?我现在单个导入的话速度是750 thousand rows/s,正常吗? 2、理论上N个节点查询速度就是单节点的N倍吗?clickhouse有节点上限吗?

  1. csv数据导入速度会受主机内存大小影响吗?我现在单个导入的话速度是750 thousand rows/s,正常吗? 我只能这样说:内存够到一定量,加内存也不会加速导入。内存太小,会影响导入速度。 具体情况要看场景。硬件、网络、数据格式、数据量等等。

  2. 每秒75万条的插入速度,我认为很不错了。

@kikanjuu clickhouse有odbc的连接方式吗?我现在后台能查询,想通过界面查询,官网我只看到了jdbc,这个有文档吗?

@mayday 我用Java,所以只用JDBC,不清楚ODBC。 JDBC的资料,也只有这些:https://github.com/yandex/clickhouse-jdbc

回到顶部