【问题标题】:Cassandra System.OutOfMemoryException, is it a Thrift bug?Cassandra System.OutOfMemoryException,这是一个 Thrift 错误吗?
【发布时间】:2011-12-10 23:17:56
【问题描述】:

我使用 Cassandra 0.8.7、Aquiles 作为 C# 客户端和 Thrift 0.7,我试图从具有以下定义的 SuperColumnFamily 中获取大量数据:

create column family SCF with column_type=Super and comparator=TimeUUIDType and subcomparator=AsciiType;

我想将从 Cassandra 获取的数据插入到 DataTable 中,这样我就能够过滤行并基于此生成一些报告,但我总是收到 OutOfMemoryException。

[OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.]
   Thrift.Transport.TFramedTransport.ReadFrame() +191
   Thrift.Transport.TFramedTransport.Read(Byte[] buf, Int32 off, Int32 len) +101
   Thrift.Transport.TTransport.ReadAll(Byte[] buf, Int32 off, Int32 len) +76
   Thrift.Protocol.TBinaryProtocol.ReadAll(Byte[] buf, Int32 off, Int32 len) +66
   Thrift.Protocol.TBinaryProtocol.ReadI32() +47
   Thrift.Protocol.TBinaryProtocol.ReadMessageBegin() +75
   Apache.Cassandra.Client.recv_multiget_slice() in D:\apache-cassandra-0.8.0-beta2\interface\gen-csharp\Apache\Cassandra\Cassandra.cs:304
   Apache.Cassandra.Client.multiget_slice(List`1 keys, ColumnParent column_parent, SlicePredicate predicate, ConsistencyLevel consistency_level) in D:\apache-cassandra-0.8.0-beta2\interface\gen-csharp\Apache\Cassandra\Cassandra.cs:286

我尝试了几种方法来优化我的代码,我的最终版本是分割时间段(以及键的数量,如果它们超过前缀数字)我用来将 SuperColumn 分割成更小的范围但什么都没有,最终我总是得到相同的异常。

这可能是 Thrift 库的错误吗?当我得到异常时,它总是指向 Thrift.Transport.TFramedTransport 中的以下代码部分:

private void ReadFrame()
        {
            byte[] i32rd = new byte[header_size];
            transport.ReadAll(i32rd, 0, header_size);
            int size =
                ((i32rd[0] & 0xff) << 24) |
                ((i32rd[1] & 0xff) << 16) |
                ((i32rd[2] & 0xff) <<  8) |
                ((i32rd[3] & 0xff));

            byte[] buff = new byte[size]; //Here the exception is thrown
            transport.ReadAll(buff, 0, size);
            readBuffer = new MemoryStream(buff);
        }

以下是我要运行的代码:

    string columnFamily = "SCF";
    ICluster cluster = AquilesHelper.RetrieveCluster(ConfigurationManager.AppSettings["CLUSTERNAME"].ToString());
    ColumnParent columnParent = new ColumnParent()
        {
            Column_family = columnFamily
        };
    List<byte[]> keys = //Function that return the list of the key i want to query

    SlicePredicate predicate = new SlicePredicate();
    foreach (DateTime[] dates in dateList)
    {
       from = GuidGenerator.GenerateTimeBasedGuid(dates[0]);
       to = GuidGenerator.GenerateTimeBasedGuid(dates[1]);
       predicate = new SlicePredicate()
       {
          Slice_range = new SliceRange()
          {


     Count = int.MaxValue,
         Reversed = false,
         Start = Aquiles.Helpers.Encoders.ByteEncoderHelper.UUIDEnconder.ToByteArray(from),
         Finish = Aquiles.Helpers.Encoders.ByteEncoderHelper.UUIDEnconder.ToByteArray(to)
      },
   };
   cluster.Execute(new ExecutionBlock(delegate(CassandraClient client)
   {
      int maxKeys = Convert.ToInt32(ConfigurationManager.AppSettings["maxKeys"]);
      CassandraMethods.TableCreator(ref dt, columnParent, predicate, keys, client, maxKeys);
      return null;
   }), ConfigurationManager.AppSettings["KEYSPACE"].ToString());
}

这是应该将来自 cassandra 的数据插入 DataTable 的函数:

public static DataTable TableCreator(ref DataTable dt, ColumnParent columnParent, SlicePredicate predicate, List<byte[]> keys, CassandraClient client, int maxKeys)
{
   int keyCount = keys.Count;
   if (keyCount < maxKeys)
      CassandraMethods.CassandraToDataTable(ref dt, client.multiget_slice(keys, columnParent, predicate, ConsistencyLevel.ONE));
   else
   {
      int counter = 0;
      while (counter < keyCount)
      {
         if (counter + maxKeys <= keyCount)
            CassandraMethods.CassandraToDataTable(ref dt, client.multiget_slice(keys.GetRange(counter, maxKeys), columnParent, predicate, ConsistencyLevel.ONE));
         else
            CassandraMethods.CassandraToDataTable(ref dt, client.multiget_slice(keys.GetRange(counter, keyCount - counter), columnParent, predicate, ConsistencyLevel.ONE));
         counter += maxKeys;
      }
   }
   return dt;
}

我错过了什么吗?我做错了什么?

更新 1:我也尝试使用 Cassandra 1.0、Aquiles 1.0、Thrift 的 0.6 和 0.7 版本,但没有,仍然是同样的例外。

更新 2:问题已解决,请阅读下面的答案

【问题讨论】:

    标签: c# .net nosql cassandra thrift


    【解决方案1】:

    问题解决了 :) 我玩弄了内存使用和垃圾收集器,并解决了这个问题。

    发生的情况是,每当我的应用程序达到 1.5 GB 的 Ram 时,由于 Visual Studio 将其编译为 32 位应用程序,就会引发异常。

    以 x64 编译和运行解决了问题,为了确保不会使用太多内存,现在我在每个 Cassandra multiget_slice 调用之前添加了以下 3 行代码。

    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    GC.WaitForPendingFinalizers();
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    

    谢谢,N.

    【讨论】:

      【解决方案2】:

      您的 SuperColumnFamily 中的数据有多大? Thrift 的默认最大帧大小为 15 Mb。这是在/etc/cassandra/conf/cassandra.yaml 中设置的 - 你可以尝试增加这个吗?

      请注意,不能将数据拆分为小于单个超列。

      【讨论】:

      • 我已经尝试增加该参数。我认为这不是数据大小的问题,如果是这样,当我查询太大的行时,我应该总是得到异常。例如,如果我从 2011 年 1 月 1 日到 2011 年 3 月 31 日查询,我可能会在 2 月 28 日遇到异常;如果是大数据问题,我应该总是在 2 月 28 日得到例外,对吗?相反,如果我那天开始我的切片,一切都会顺利进行一段时间,我稍后会遇到异常。
      猜你喜欢
      • 2011-01-29
      • 2012-09-18
      • 2012-03-25
      • 2010-12-22
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多