松果时序数据库(PinusDB)数据写入测试报告

松果时序数据库(PinusDB)是一款以简单、易用、高性能为目标的开源时序数据库。本篇简单介绍松果时序数据库写入测试。要获取其他信息请参考官方网站或开源仓库,当然,若有好的意见或建议也可以在开源仓库给我们提交Issue或给我们发邮件:

官方网站:http://www.pinusdb.cn

码云仓库:https://gitee.com/pinusdb/pinusdb

邮    件:[email protected]  [email protected]

为了帮助用户了解松果时序数据库的性能指标,简单测试松果时序数据库的写入性能。通过调研选择了上海市出租车定位数据作为本次测试的数据集。

下载地址:https://www.cse.ust.hk/scrg/

这个数据集中包含4316辆出租车在2007年2月20日的定位数据,包括:车辆编号,时间,经度,纬度,速度,航向,状态。由于松果时序数据库有写入时间窗口的限制,为了简单将数据中时间的日期修改为当前日期

测试环境:

服务器

操作系统:Windows Server 2016

CPU:Intel Core i3-370

内存:8GB

网卡:千兆网卡

磁盘:C盘:120GB SSD 安装操作系统。

      D盘:1TB HDD  存储compressDataPath、 commitLogPath及sysLogPath。

      E盘:120GB SSD 存储normalDataPath及tabPath。

注意:本测试并不涉及到压缩文件。

客户端

操作系统:Windows 10

CPU:Intel Core i5-6200U

内存:8GB

网卡:千兆网卡

服务器与客户段机器通过一台千兆交换机连接。

准备环境

在服务器上安装松果时序数据库,安装步骤参考官网安装文档。安装后服务配置文件config.ini如下所示:

松果时序数据库(PinusDB)数据写入测试报告_第1张图片

创建数据表

在松果数据库上创建出租车数据表 taxi 表,建表语句如下:

create table taxi
(
  devid bigint,
  tstamp datetime,
  logitude real6,
  latitude real6,
  speed bigint,
  angle bigint,
  status bigint
)

测试程序

本次测试程序使用c#编写,单线程执行每次插入1000条数据,松果时序数据库提供两种协议的数据写入:SQL语句的文本协议以及二进制协议;其中二进制协议性能较高,这里使用二进制协议进行测试,用户直接构建好DataTable写入即可,既方便性能又高,也是我们推荐使用的方式。

测试程序将所有数据读取到内存,并按照时间排序,尽量多个设备同时写入,而不是写完一个设备的数据再写下一个设备的数据。

测试源码在本篇博客最后,只需修改数据库连接串及数据集的路径即可:

测试结果

经过多次测试,基本上写入性能在10万条/秒左右,执行过程中服务器松果时序数据库进程CPU占用在10%左右。写入结果如下图所示:

松果时序数据库(PinusDB)数据写入测试报告_第2张图片

本篇博客只是简单的测试了单线程批量写入的场景,基本上性能可以满足大多数物联网场景的写入数据要求。后面我们会测试更多的场景。

测试源码

using System;
using System.Collections.Generic;
using PDB.DotNetSDK;
using System.Data;
using System.IO;
using System.Diagnostics;
using System.Linq;

namespace ProformaceTest
{
  class Program
  {
    static string dataPath = "C:\\Users\\frank\\Downloads\\taxi\\Taxi_070220";
    static string connStr = "server=192.168.3.81;port=8105;username=sa;password=pin123";
    static string tabName = "taxi";
    static List devIdList = null;

    class TaxiRec
    {
      public long devid;
      public DateTime tstamp;
      public double logitude;
      public double latitude;
      public long speed;
      public long angle;
      public long status;
    }
    static List ReadDataForFile()
    {
      devIdList = new List();
      List recList = new List();
      
      int days = (DateTime.Now - Convert.ToDateTime("2007-02-20")).Days;
      string[] taxiFiles = Directory.GetFiles(dataPath);
      foreach(string taxiFile in taxiFiles)
      {
        StreamReader sReader = new StreamReader(taxiFile);
        string lineStr = null;
        while((lineStr = sReader.ReadLine()) != null)
        {
          string[] partArr = lineStr.Split(',');
          if (partArr.Count() != 7)
            continue;

          TaxiRec rec = new TaxiRec();
          rec.devid = Convert.ToInt64(partArr[0]);
          DateTime tstamp = Convert.ToDateTime(partArr[1]);
          rec.tstamp = tstamp.AddDays(days);
          rec.logitude = Convert.ToDouble(partArr[2]);
          rec.latitude = Convert.ToDouble(partArr[3]);
          rec.speed = Convert.ToInt64(partArr[4]);
          rec.angle = Convert.ToInt64(partArr[5]);
          rec.status = Convert.ToInt64(partArr[6]);

          recList.Add(rec);
          if (devIdList.Count() == 0 || devIdList.Last() != rec.devid)
          {
            devIdList.Add(rec.devid);
          }
        }
        sReader.Close();
      }

      recList.Sort(delegate (TaxiRec a, TaxiRec b) { return a.tstamp.CompareTo(b.tstamp); });
      return recList;
    }

    static bool AddDev()
    {
      DataTable dtDev = new DataTable("sys_dev");
      dtDev.Columns.Add(new DataColumn("tabname", typeof(string)));
      dtDev.Columns.Add(new DataColumn("devid", typeof(long)));

      using (PDBConnection conn = new PDBConnection(connStr))
      {
        conn.Open();
        PDBCommand cmd = conn.CreateCommand();

        foreach(long devId in devIdList)
        {
          DataRow devRow = dtDev.NewRow();
          devRow[0] = tabName;
          devRow[1] = devId;
          dtDev.Rows.Add(devRow);

          if (dtDev.Rows.Count == 1000)
          {
            PDBErrorCode retCode = cmd.ExecuteInsert(dtDev);
            if (retCode != PDBErrorCode.PdbE_OK)
            {
              Console.WriteLine("添加设备失败:" + PDBErrorMsg.GetErrorMsg(retCode));
              return false;
            }
            dtDev.Rows.Clear();
          }
        }

        if (dtDev.Rows.Count != 0)
        {
          PDBErrorCode retCode = cmd.ExecuteInsert(dtDev);
          if (retCode != PDBErrorCode.PdbE_OK)
          {
            Console.WriteLine("添加设备失败:" + PDBErrorMsg.GetErrorMsg(retCode));
            return false;
          }
        }
      }

      return true;
    }

    static void InsertData(List recList)
    {
      DataTable dtRec = new DataTable(tabName);
      dtRec.Columns.Add(new DataColumn("devid", typeof(long)));
      dtRec.Columns.Add(new DataColumn("tstamp", typeof(DateTime)));
      dtRec.Columns.Add(new DataColumn("logitude", typeof(double)));
      dtRec.Columns.Add(new DataColumn("latitude", typeof(double)));
      dtRec.Columns.Add(new DataColumn("speed", typeof(long)));
      dtRec.Columns.Add(new DataColumn("angle", typeof(long)));
      dtRec.Columns.Add(new DataColumn("status", typeof(long)));

      using (PDBConnection conn = new PDBConnection(connStr))
      {
        conn.Open();
        PDBCommand cmd = conn.CreateCommand();

        Stopwatch sw = new Stopwatch();
        sw.Restart();

        foreach(TaxiRec rec in recList)
        {
          DataRow recRow = dtRec.NewRow();
          recRow[0] = rec.devid;
          recRow[1] = rec.tstamp;
          recRow[2] = rec.logitude;
          recRow[3] = rec.latitude;
          recRow[4] = rec.speed;
          recRow[5] = rec.angle;
          recRow[6] = rec.status;

          dtRec.Rows.Add(recRow);

          if (dtRec.Rows.Count == 1000)
          {
            PDBErrorCode retCode = cmd.ExecuteInsert(dtRec);
            if (retCode != PDBErrorCode.PdbE_OK)
            {
              Console.WriteLine("插入数据失败:" + PDBErrorMsg.GetErrorMsg(retCode));
              return;
            }

            dtRec.Rows.Clear();
          }
        }

        if (dtRec.Rows.Count != 0)
        {
          PDBErrorCode retCode = cmd.ExecuteInsert(dtRec);
          if (retCode != PDBErrorCode.PdbE_OK)
          {
            Console.WriteLine("插入数据失败:" + PDBErrorMsg.GetErrorMsg(retCode));
            return;
          }
        }
        sw.Stop();
        Console.WriteLine("插入{0}条数据耗时:{1}毫秒, 平均每秒插入:{2}条", recList.Count, sw.ElapsedMilliseconds, (recList.Count / (sw.ElapsedMilliseconds / 1000)));
      }
    }

    static void Main(string[] args)
    {
      List dtList = ReadDataForFile();
      if (AddDev())
      {
        InsertData(dtList);
      }
      Console.WriteLine("输入回车退出...");
      Console.ReadLine();
    }
  }
}

 

你可能感兴趣的:(松果时序数据库)