代码之家  ›  专栏  ›  技术社区  ›  Bikas Katwal

基于分区键的令牌范围查询的性能?

  •  3
  • Bikas Katwal  · 技术社区  · 6 年前

    我正在根据分区键的标记范围从Cassandra节点选择所有记录。

    代码如下:

    public static synchronized List<Object[]> getTokenRanges(
          final Session session) {
    
        if (cluster == null) {
          cluster = session.getCluster();
        }
    
        Metadata metadata = cluster.getMetadata();
    
        return unwrapTokenRanges(metadata.getTokenRanges());
      }
    
      private static List<Object[]> unwrapTokenRanges(Set<TokenRange> wrappedRanges) {
    
        final int tokensSize = 2;
        List<Object[]> tokenRanges = new ArrayList<>();
        for (TokenRange tokenRange : wrappedRanges) {
          List<TokenRange> unwrappedTokenRangeList = tokenRange.unwrap();
          for (TokenRange unwrappedTokenRange : unwrappedTokenRangeList) {
            Object[] objects = new Object[tokensSize];
            objects[0] = unwrappedTokenRange.getStart().getValue();
            objects[1] = unwrappedTokenRange.getEnd().getValue();
            tokenRanges.add(objects);
          }
        }
        return tokenRanges;
      }
    

    getTokenRanges 给出了所有节点上的所有令牌范围的Vnode。

    然后我使用这些令牌范围来查询Cassandra。 object[0] 持有Vnode的开始令牌,并且 object[1] 结束令牌。

    生成以下查询:

    SELECT * FROM my_key_space.tablename WHERE token(id)><start token number> AND token(id)<= <end token number>;
    

    在上面 id 列是分区键。

    在Cassandra中,不建议执行范围查询,因此,是否将执行此查询?

    据我所知,这个查询只调用单个分区/vnode,不会调用多个分区,因此不应该有任何性能问题?这是正确的吗?

    Cassandra版本:3.x

    2 回复  |  直到 6 年前
        1
  •  1
  •   Alex Ott    6 年前

    对令牌范围的查询被执行,spark使用它们来有效地获取数据。但你需要记住- getTokenRanges 将为您提供所有现有的令牌范围,但也有一些边缘情况-最后一个范围将是表示第一个范围的正数到负数,因此,您的查询将不会执行任何操作。基本上你错过了 MIN_TOKEN 和第一个令牌,以及在最后一个令牌和 MAX_TOKEN . 火花连接器 generates different CQL statements 基于令牌。另外,您需要将查询路由到正确的节点-这可以通过 setRoutingToken .

    类似的方法可以在Java代码中使用( full code ):

        Metadata metadata = cluster.getMetadata();
        Metadata metadata = cluster.getMetadata();
        List<TokenRange> ranges = new ArrayList(metadata.getTokenRanges());
        Collections.sort(ranges);
        System.out.println("Processing " + (ranges.size()+1) + " token ranges...");
    
        Token minToken = ranges.get(0).getStart();
        String baseQuery = "SELECT id, col1 FROM test.range_scan WHERE ";
        Map<String, Token> queries = new HashMap<>();
        // generate queries for every range
        for (int i = 0; i < ranges.size(); i++) {
            TokenRange range = ranges.get(i);
            Token rangeStart = range.getStart();
            Token rangeEnd = range.getEnd();
            if (i == 0) {
                queries.put(baseQuery + "token(id) <= " + minToken, minToken);
                queries.put(baseQuery + "token(id) > " + rangeStart + " AND token(id) <= " + rangeEnd, rangeEnd);
            } else if (rangeEnd.equals(minToken)) {
                queries.put(baseQuery + "token(id) > " + rangeStart, rangeEnd);
            } else {
                queries.put(baseQuery + "token(id) > " + rangeStart + " AND token(id) <= " + rangeEnd, rangeEnd);
            }
        }
    
        // Note: It could be speedup by using async queries, but for illustration it's ok
        long rowCount = 0;
        for (Map.Entry<String, Token> entry: queries.entrySet()) {
            SimpleStatement statement = new SimpleStatement(entry.getKey());
            statement.setRoutingToken(entry.getValue());
            ResultSet rs = session.execute(statement);
            // .... process data
       }
    
        2
  •  1
  •   Nadav Har'El    6 年前

    对, 令牌范围 与对实际分区键的普通范围查询不同,查询确实是执行的,因为它们可以按顺序从磁盘读取(分区按顺序令牌顺序存储在磁盘上)和从同一节点读取顺序数据(相邻令牌属于同一节点)。

    Cassandra向您提供了一个提示,这类查询的性能很好,因为它不需要您使用“allow filtering”。如果您试图对实际的分区键(而不是它的标记)进行范围查询,则需要添加一个“允许筛选”,以表明您知道这将具有糟糕的性能。