【问题标题】:Cassandra approach of RDBMS nested insertionsRDBMS 嵌套插入的 Cassandra 方法
【发布时间】:2017-01-27 16:42:48
【问题描述】:

我经常收到两类数据:

网络流量,每秒数千:

{
    'stamp' : '2017-01-19 01:37:22'
    'host' : '192.168.2.6',
    'ip_src' : '10.29.78.3',
    'ip_dst' : '8.8.4.4',
    'iface_in' : 19,
    'iface_out' : 20,
    (... etc ..)
}

还有界面表,​​每小时一次:

[
    {
        'stamp' : '2017-01-19 03:00:00'
        'host' : '192.168.2.6',
        'iface_id' : 19
        'iface_name' : 'Fa0/0'
    },{
        'stamp' : '2017-01-19 03:00:00'
        'host' : '192.168.2.6',
        'iface_id' : 20
        'iface_name' : 'Fa0/1'
    },{
        'stamp' : '2017-01-19 03:00:00'
        'host' : '192.168.157.38',
        'iface_id' : 20
        'iface_name' : 'Gi0/3'
    }
]

我想根据最新匹配的 host/iface_id 值在 Cassandra 中插入这些流,使用接口名称而不是 ID。我不能依赖纯内存解决方案,否则每次重新启动应用程序时我可能会丢失长达一小时的流量。

我的想法是使用两个 Cassandra 表:一个保存流,另一个保存 latest host/iface_id 表。然后,当接收到一个流时,我会使用这些数据来正确填写接口名称。

理想情况下,我想让 Cassandra 负责这件事。在我看来,这似乎比每次都从应用程序端提取接口名称更有效。

问题是我无法弄清楚如何做到这一点 - 并且以前从未使用过 NoSQL,我什至不确定这是正确的方法......有人能指出我正确的方向吗?

在接口表中插入数据并只保留最新版本是非常简单的,但我无法围绕“在流记录中插入接口名称”部分。在传统的 RDBMS 中,我会使用嵌套查询,但这些似乎在 Cassandra 中不存在。

【问题讨论】:

    标签: cassandra nosql


    【解决方案1】:

    阅读您的问题,我希望接口表中每小时收到的数据不会太大。所以我们可以将数据(单行)保存在内存和 cassandra 数据库中。每隔一小时,内存中的数据都会更新,并有一个新的插入到数据库中。我们可以用下表定义保存接口数据-

         create table interface_by_hour(
            year int,
            month int,
            day int,
            hour int,
            data text, -- enitre json string for one hour interface data.
            primary key((year,month,day,hour)));
    

    很少的插入语句--

        insert into interface_by_hour (year,month,day,hour,data) values (2017,1,27,23,'{complete json.........}');
        insert into interface_by_hour (year,month,day,hour,data) values (2017,1,27,00,'{complete json.........}');
        insert into interface_by_hour (year,month,day,hour,data) values (2017,1,28,1,'{complete json.........}');
    

    在此表中保留每小时接口数据,并在内存中更新它。拥有内存数据的好处是您不必每秒从表中读取数千次。如果应用程序出现故障,您可以使用以下查询从表中读取当前/上一小时的数据,并构建内存缓存。

        cqlsh:mykeyspace> select * from interface_by_hour where year=2017 and month=1 and day=27 and hour=0;
    
         year | month | day | hour | data
        ------+-------+-----+------+--------------------------
         2017 |     1 |  27 |    0 | {complete json.........}
    

    现在是流量数据--

    由于我们在内存中缓存了当前小时接口表数据,我们可以快速将接口名称映射到主机。使用下表保存流量数据。

        create table flow(
        iface_name text,
        createdon bingint, -- time stamp in milliseconds.
        host text, -----this is optionl, if you want dont use it as column.
        flowdata text, -- entire json string 
        primarykey(iface_name,createdon,host));
    

    我在上表中看到的唯一问题是它不会在分区之间均匀分布数据,如果一个接口名称的流数据过多,整个数据将插入一个分区。

    我设计这个表只是为了保存数据,如果你能指定你将如何使用这些数据,我会做更多的思考。

    希望这会有所帮助。

    【讨论】:

    • 我喜欢直接为接口存储每小时 JSON 对象的方法。如果在插入流时出现问题,它还允许“回顾”,而不是仅使用最后一个值。
    • 只要考虑到 10MB 的 json 数据对 cassandra 不利,不要只保存原始数据,使用结构或将其保存到多个不同的块中,这样就可以了。通常每个块不要超过 10 或 100k 也使用时间来生存,因为在历史上过多可能会花费你大量的存储空间。
    【解决方案2】:

    嗨,据我所知,接口数据在写入方面并没有那么重,以至于需要按时间分区。它每小时仅更改一次,因此无需每小时保存最新版本的数据。另外我会假设你想以某种方式查询这个我不知道怎么做,所以我只会为接口提出一些一般性的建议,并将威胁作为时间序列数据的流:

    create table interface(
        iface_name text primary key,
        iface_id int,
        host text, 
        stamp timestamp
    );
    
    insert into interface(iface_name, iface_id, host, stamp) values ('Fa0/0', 19, '192.168.2.6', '2017-01-19 03:00:00');
    insert into interface(iface_name, iface_id, host, stamp) values ('Fa0/1', 20, '192.168.2.6', '2017-01-19 03:00:00');
    insert into interface(iface_name, iface_id, host, stamp) values ('Gi0/3', 20, '192.168.157.38', '2017-01-19 03:00:00');
    

    通常这是与 cassandra 的反模式:

    cqlsh:test> select * from interface;
    
     iface_name | host           | iface_id | stamp
    ------------+----------------+----------+---------------------------------
          Fa0/0 |    192.168.2.6 |       19 | 2017-01-19 02:00:00.000000+0000
          Gi0/3 | 192.168.157.38 |       20 | 2017-01-19 02:00:00.000000+0000
          Fa0/1 |    192.168.2.6 |       20 | 2017-01-19 02:00:00.000000+0000
    

    但据我所知,你没有那么多接口

    所以基本上任何多达数千的东西都可以。在最坏的情况下,您可能想要 使用令牌功能从分区中获取数据,但问题是这会节省你 空间很大,您不需要按小时保存。

    我也会简单地将这张表保存在内存中,然后在数据进入时丰富数据。 如果有更新,请更新内存缓存......但也将写入内容写入 cassandra。 如果出现故障,则只需从接口表恢复并继续。

    基本上你的流量信息会变成

    {
        'stamp' : '2017-01-19 01:37:22'
        'host' : '192.168.2.6',
        'ip_src' : '10.29.78.3',
        'ip_dst' : '8.8.4.4',
        'iface_in' : 19,
        'iface_out' : 20,
    
        'iface_name' : 'key put from in memory cache',
    }
    

    这就是您将获得最大性能的方式现在节省流量只是 然后,时间序列数据,考虑到您正在访问集群 每秒有数千个,当你按时间分区时,你 每秒至少获得 7000 列(如果不是更多列)(使用模型 我在这里提议)通常你会想要多达 100 000 列 在单个分区内,这表示您的分区超出 理想的尺寸在 20 秒甚至更少,所以我什至建议使用 随机桶(插入时只使用定义范围内的一些数字 比方说 10):

    create table flow(
        time_with_minute text,
        artificial_bucket int,
        stamp timeuuid,
        host text,
        ip_src text,
        ip_dst text,
        iface_in int,
        iface_out int,
        iface_name text,
        primary key((time_with_minute, artificial_bucket), stamp)
    );
    

    当想要随时间推移获取流时,您只需使用 一个时间戳加上同时进行 10 个查询或一个一个查询来访问所有数据。这里有各种技术,您只需要详细说明您的用例即可。

    插入类似于:

    insert into flow(time_with_minute, artificial_bucket, stamp, host, ip_src, ip_dst, iface_in, iface_out, iface_name)
        values ('2017-01-19 01:37', 1, now(), '192.168.2.6', '10.29.78.3', '8.8.4.4', 19, 20, 'Fa0/0');
    

    我现在只是举个例子,用https://github.com/apache/cassandra/blob/cassandra-2.1/src/java/org/apache/cassandra/utils/UUIDGen.java 使用插入流的时间生成 timeuuid。我也将 1 插入到人工桶中,在这里你将插入随机数,范围至少为 0-10。有些人,根据负载随机插入多个桶,甚至60个或更多。这完全取决于写入的重量。如果你只是每分钟一分钟,集群中的一组节点就会很热,并且会切换。拥有热节点通常不是一个好主意。

    使用 cassandra,您正在编写您需要的信息,而不是在做 写入过程中的任何连接或类似的东西。将数据保存在您需要的内存中 用您需要的信息标记数据,然后直接插入而不进行非规范化。

    您还可以以关系方式对解决方案进行建模,然后告诉您您希望如何 访问数据,然后我们可以深入了解。

    【讨论】:

    • 我也是得出这个结论,接口数据确实没有那么大(假设5000个设备@每个32个接口,它应该达到每小时+/- 10MB)并且可以保存在内存中。
    • 如果它是 10 MB,它完全是一个内存缓存候选者,如果出现问题,它会回退到 cassandra :) 我不建议 gunwant 在单个分区中使用 10 MB 数据的方法,因为从单个分区中获取 10MB将需要很长时间(几秒钟)......但如果它在崩溃后加载它甚至可能没问题。一旦我在分区中有大约 300kB 的数据,并且确实需要很长时间才能获取它。
    • 我现在正在考虑为此使用嵌入式 sqlite3 内存数据库。
    • 这也是一个选项,我猜是多语言持久化时代。 imho cassandra 只是不太擅长检查然后设置。
    • 使用 redis 缓存而不是 sqlite。你将来可以用它来抓很多东西。
    猜你喜欢
    • 2019-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    • 2014-01-20
    • 1970-01-01
    相关资源
    最近更新 更多