为什么我的Cassandra数据库中的数据插入有时稳定且有时很慢?

时间:2016-01-13 07:06:58

标签: python cassandra scrapy apache-kafka

如果Cassandra数据库中存在或不存在当前数据ID,则这是我的查询:

row = session.execute("SELECT * FROM articles where id = %s", [id]) 

Kafka中已解析的消息,然后确定Cassandra数据库中是否存在此消息(如果该消息不存在),则应执行插入操作,如果确实存在,则不应将其插入数据中。

messages = consumer.get_messages(count=25)

if len(messages) == 0:
    print 'IDLE'
    sleep(1)
    continue

for message in messages:
    try:
        message = json.loads(message.message.value)
        data = message['data']
        if data:
            for article in data:
                source = article['source']
                id = article['id']
                title = article['title']
                thumbnail = article['thumbnail']
                #url = article['url']
                text = article['text']
                print article['created_at'],type(article['created_at'])
                created_at = parse(article['created_at'])
                last_crawled = article['last_crawled']
                channel = article['channel']#userid
                category = article['category']
                #scheduled_for = created_at.replace(minute=created_at.minute + 5, second=0, microsecond=0)
                scheduled_for=(datetime.utcnow() + timedelta(minutes=5)).replace(second=0, microsecond=0)
                row = session.execute("SELECT * FROM articles where id = %s", [id])
                if len(list(row))==0:
                #id parse base62
                    ids = [id[0:2],id[2:9],id[9:16]]
                    idstr=''
                    for argv in ids:
                        num = int(argv)
                        idstr=idstr+encode(num)
                    url='http://weibo.com/%s/%s?type=comment' % (channel,idstr)
                    session.execute("INSERT INTO articles(source, id, title,thumbnail, url, text, created_at, last_crawled,channel,category) VALUES (%s,%s, %s, %s, %s, %s, %s, %s, %s, %s)", (source, id, title,thumbnail, url, text, created_at, scheduled_for,channel,category))
                    session.execute("INSERT INTO schedules(source,type,scheduled_for,id) VALUES (%s, %s, %s,%s) USING TTL 86400", (source,'article', scheduled_for, id))
                    log.info('%s %s %s %s %s %s %s %s %s %s' % (source, id, title,thumbnail, url, text, created_at, scheduled_for,channel,category))

    except Exception, e:
        log.exception(e)
        #log.info('error %s %s' % (message['url'],body))
        print e
        continue

我有一个ID只有一个唯一的表行,我希望这样。一旦我为唯一ID添加了不同的scheduled_for时间,我的系统就会崩溃。添加此if len(list(row))==0:是正确的想法,但之后我的系统非常慢。

这是我的表格描述:

DROP TABLE IF EXISTS schedules;

CREATE TABLE schedules (
 source text,
 type text,
 scheduled_for timestamp,
 id text,
 PRIMARY KEY (source, type, scheduled_for, id)
);

此scheduled_for是可更改的。这也是一个具体的例子:

Hao article 2016-01-12 02:09:00+0800 3930462206848285
Hao article 2016-01-12 03:09:00+0801 3930462206848285
Hao article 2016-01-12 04:09:00+0802 3930462206848285
Hao article 2016-01-12 05:09:00+0803 3930462206848285

以下是我的文章CQL架构:

CREATE TABLE crawler.articles (
    source text,
    created_at timestamp,
    id text,
    category text,
    channel text,
    last_crawled timestamp,
    text text,
    thumbnail text,
    title text,
    url text,
    PRIMARY KEY (source, created_at, id)
) WITH CLUSTERING ORDER BY (created_at DESC, id ASC)
AND bloom_filter_fp_chance = 0.01
AND caching = '{"keys":"ALL", "rows_per_partition":"ALL"}'
AND comment = ''
AND compaction = {'sstable_size_in_mb': '160', 'enabled': 'true', 'unchecked_tombstone_compaction': 'false', 'tombstone_compaction_interval': '86400', 'tombstone_threshold': '0.2', 'class': 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy'}
AND compression = {'sstable_compression': 'org.apache.cassandra.io.compress.LZ4Compressor'}
AND dclocal_read_repair_chance = 0.1
AND default_time_to_live = 604800
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = '99.0PERCENTILE';

CREATE INDEX articles_id_idx ON crawler.articles (id);
CREATE INDEX articles_url_idx ON crawler.articles (url);

1 个答案:

答案 0 :(得分:1)

查看您的SCHEMA以及您使用它的方式我可以假设ID字段上的二级索引正在创建问题并减慢查询速度。您可以通过Google搜索来查看更多有关二级索引在许多地方出错的详细信息(source是一个良好的开端,也是DataStax documentation page)。基本上,当您在5节点集群中使用二级索引时,必须点击每个节点以查找您要查找的项目,并且在使用主键时,每个节点都知道哪个节点保存数据。

如果您使用具有高基数的数据(当您添加更多项目时性能下降)并且您使用每篇文章的ID不同,则辅助索引会特别糟糕。当你使用低基数时,如果你有一定数量的类别,你可以使用低基数,例如按周计算一些数据(你知道一周只有7天所以你可以预测索引表的大小)或类别

我建议再创建一个表article_by_id,它将是你的文章表的反向索引。您可以先使用Lightweight Transaction并对该表执行INSERT ... IF NOT EXISTS,如果操作返回true(意味着插入已完成,因此以前没有记录),您可以定期执行INSERT {{1如果它返回articles(意味着数据未插入,因为它已经存在),您可以跳过INSERT到false表。

这是表格(我建议使用UUID而不是文本作为ID,但我根据你的文章表创建了表格):

articles

这样,您始终可以根据ID找到密钥的所有部分。如果ID是您的输入参数,则从该表中选择将为您提供source和created_at。

这是插入查询,它将返回true或false:

CREATE TABLE article_by_id (
    id text,
    source text,
    created_at timestamp,
    PRIMARY KEY (id)
) WITH comment = 'Article by id.';

更多提示,如果您可以根据实体中的某些不可更改的数据找到关键字,而不是您不需要第二个表格。例如,如果source和created_at唯一标识系统中的文章并且永远不会更改,则可以删除id并使用原始表。