我正在使用C#.Net客户端库将数据从本地文件流插入Bigquery数据库。我使用我的代码成功插入所有数据,但性能(插入速度)非常慢。我的加载速度为20KB / sec。例如,我有一个大小为323MB的文件,程序需要大约20分钟才能加载。我测试了我的带宽,上传速度就像3MB /秒我想知道是否有办法提高性能?(我想它应该快得多)
这是我的代码:
namespace BigQuery_Test
{
class StreamDatacs
{
private static ServiceAccountCredential credential;
public StreamDatacs()
{
Credential2().Wait();
}
public async Task Credential2()
{
string certificateFile = "C:\\xxxxxx.p12";
string serviceAccountEmail = "xxxxxxxxxxxx@developer.gserviceaccount.com";
var certificate = new X509Certificate2(certificateFile, "notasecret", X509KeyStorageFlags.Exportable);
credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { StorageService.Scope.DevstorageReadWrite,
BigqueryService.Scope.Bigquery }
}.FromCertificate(certificate));
Console.WriteLine(credential.Token);
Console.WriteLine(credential.TokenServerUrl);
}
public void ReadData(string path)
{
var logs = new List<TableDataInsertAllRequest.RowsData>();
using (StreamReader sr = new StreamReader(path))
{
string line = "";
string [] aLog = new string[1000];
Log Loga = new Log();
int count = 0;
int i = 0;
while((line = sr.ReadLine()) != null)
{
var theLog = new TableDataInsertAllRequest.RowsData();
string[] token = line.Split('\t');
theLog.Json = new Dictionary<string, object>();
theLog.Json.Add("Timestamp", token[0]);
theLog.Json.Add("ClientIpAddress", token[1]);
theLog.Json.Add("Username", token[2]);
theLog.Json.Add("GroupID", token[3]);
theLog.Json.Add("CompanyID", token[4]);
theLog.Json.Add("FullOrSiteLogging", token[5]);
theLog.Json.Add("PolicyFlags", token[6]);
theLog.Json.Add("ActionsTaken", token[7]);
theLog.Json.Add("ResponseStatus", token[8]);
logs.Add(theLog);
count++;
if (count > 20000)
{
BQStreamInsert(logs);
logs.Clear();
count = 0;
}
}
}
Task.WaitAll(tasks.ToArray());
}
public void BQStreamInsert(List<TableDataInsertAllRequest.RowsData> rows)
{
string projectId= "ws-2015-logs";
string datasetId = "CompanyGroup1";
string tableId ="RawLogsTest7";
var service = new BigqueryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "BQ test"
});
try
{
var content = new TableDataInsertAllRequest();
content.Rows = rows;
content.Kind = "bigquery#tableDataInsertAllRequest";
content.IgnoreUnknownValues = true;
content.SkipInvalidRows = true;
var insertTask = service.Tabledata.InsertAll(content, projectId, datasetId, tableId);
TableDataInsertAllResponse response = insertTask.Execute();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
在program.cs中:
class Program
{
static void Main(string[] args)
{
var sw = Stopwatch.StartNew();
StreamDatacs sd = new StreamDatacs();
sd.ReadData(@"C:\2015071600.csv");
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Stop();
Console.Read();
}
在代码中,我逐行读取文件,每隔20,000行停止并插入BQ,直到插入所有行。我在这里尝试了不同的缓冲区大小(500行,1000行,50,000行),但没有看到很大的区别。 我感谢你的任何建议。非常感谢。
答案 0 :(得分:2)
由于流媒体的有效载荷大小有限,请参阅Quota policy更容易谈论时间,因为有效载荷以同样的方式限制在我们两个人身上,但我也会提到其他副作用。
您需要正确实施限制:
否则你会收到错误。因此,它被称为流式插入,因此您可以运行许多并行流程而不是一项大工作。
我们为每个流媒体请求测量1200-2500毫秒,这在过去的一个月中是一致的,如图所示。
我们看到了几种副作用,但是:
对于所有这些,我们在付费Google Enterprise支持中打开了案例,但不幸的是他们没有解决它。它接缝推荐的选项,因为这是一个指数退避与重试,甚至支持告诉这样做。哪个人不会让我开心。
您选择的方法如果花费数小时就意味着it does not scale
,并且无法扩展。您需要使用async processes
重新考虑该方法。为了更快地完成,您需要并行运行多个工作程序,流式传输性能将是相同的。只有10名工人并行,这意味着时间将减少10倍。
后台处理IO绑定或cpu绑定任务现在是大多数Web应用程序中的常见做法。有很多软件可以帮助构建后台作业,其中一些基于Beanstalkd等消息传递系统。
基本上,您需要在封闭网络中分配插入作业,确定优先级,然后使用(运行)它们。嗯,这正是Beanstalkd提供的。
Beanstalkd提供了在管中组织作业的可能性,每个管对应于作业类型。
你需要一个API /生产者,它可以将作业放在一个管上,让我们说一下该行的json表示。这是我们用例的杀手级功能。所以我们有一个获取行的API,并将它们放在管上,这只需要几毫秒,因此您可以实现快速响应时间。
另一方面,你现在在一些管子上有一堆工作。你需要一个代理人。代理人/消费者可以预约工作。
它还可以帮助您进行作业管理和重试:成功处理作业后,消费者可以从管中删除作业。在失败的情况下,消费者可以埋葬这份工作。这项工作不会被推回管中,但可供进一步检查。
消费者可以释放一份工作,Beanstalkd会将这项工作推回管中,并将其提供给其他客户。
可以在大多数常见语言中找到Beanstalkd客户端,web interface可用于调试。