如何在数据库中增加读取查询/秒?

时间:2012-02-22 17:21:11

标签: mysql database redis hbase

我是数据库的新手,但我遇到的问题似乎无法弄明白。提前抱歉,如果这太长了,我想总结一下我的所有努力,这样你就知道到目前为止我做了什么。我有一个应用程序有一些逻辑,然后对数据库进行3次查询。第一个查询检查是否存在值,第二个检查是否存在另一个(相关)值,第三个查询是否存在,如果不存在则添加相关值。想想我对数字2进行查询,如果存在,我检查3并在需要时添加它。我做这个循环很多次(我正在查看整体查询,但我怀疑这个程序比写入更重读)。我曾经在我的程序中只使用哈希表但是由于我添加了多个进程,因此我遇到了同步问题,因此我决定使用数据库,以便多个内核可以同时处理这个问题。

起初我试过,mysql并使用了一个内存存储引擎(它可能都适合内存),制作了一个复合主键来复制我在程序中的字典,索引它,禁用锁定但我只能得到每秒11,000次查询。

然后我尝试了redis(听说它就像memcache)并创建了我之前拥有的相同键/值dict(这里是实际模式Can I make two columns unique to each other? or use composite primary key's in redis?)并删除了所有fsync的东西,所以它希望永远不会遇到硬盘i / o但我仍然只能获得大约30,000个查询/秒。我看了系统改进(我正在使用linux),让程序在ramdrive等运行,但结果仍然相似。

我有一个安装脚本并尝试使用高cpu实例在ec2上执行此操作,但结果类似(对于两个解决方案,查询都不会增加太多)。我有点在我的智慧结束,但不想放弃,因为我在stackoverflow上读到人们谈论他们如何在独立上获得100,000k +查询。我觉得我的数据模型非常简单(两列INT或我可以使它成为一个字符串,两个INT组合在一起,但这似乎没有慢下来)和一旦数据被创建(并由另一个进程查询)我有不需要持久性(这也是我试图不写入硬盘的原因)。我缺少什么设置,允许开发人员获得这种性能?在创建表之外是否需要特殊配置?或者是通过分布式数据库获得此类性能的唯一方法?我知道问题出在数据库中,因为当我关闭数据库中间进程时,我的python应用程序在每个核心上运行100%(尽管它没有写入),它让我觉得等待的过程(对于读取,我怀疑)是什么减慢了它(我有足够的CPU /内存,所以我想知道为什么它没有最大化,我有50%的CPU和80%的内存空闲在这些工作,所以我不知道最新情况。)

我有mysql,redis和hbase。希望我能做些什么来让这些解决方案中的一个能够以我想要的速度运行,但如果没有,我可以使用任何解决方案(它实际上只是一个临时散列表,分布式过程可以查询)。

我该怎么办?

谢谢!

更新:根据评论中的要求,这里有一些代码(在特定的应用程序逻辑之后似乎没有问题):

    cursor.execute(""" SELECT value1 FROM data_table WHERE key1='%s' AND value1='%s' """ % (s - c * x, i))
    if cursor.rowcount == 1:
       cursor.execute(""" SELECT value1 FROM data_table WHERE key1='%s' AND value1='%s' """ % (s, i+1))
       if cursor.rowcount == 0:
           cursor.execute (""" INSERT INTO data_table (key1, value1) VALUES ('%s', '%s')""" % (s, i+1))
           conn.commit() #this maybe not needed
           #print 'commited ', c

上面是在mysql上进行3次查找的代码。我也尝试过一次大查找(但实际上速度较慢):

       cursor.execute ("""
 INSERT INTO data_table (key1, value1) 
  SELECT  '%s', '%s'
  FROM dual
  WHERE ( SELECT COUNT(*) FROM data_table WHERE key1='%s' AND value1='%s' )
        = 1
    AND NOT EXISTS
        ( SELECT * FROM data_table WHERE key1='%s' AND value1='%s' )
          """ % ((s), (i+1), (s - c * x), (i), (s), (i+1)))   

这是mysql上的表设计:

cursor.execute ("DROP TABLE IF EXISTS data_table")
cursor.execute ("""
    CREATE TABLE data_table(
        key1    INT SIGNED NOT NULL,
        value1    INT SIGNED NOT NULL,
        PRIMARY KEY (key1,value1)
    )  ENGINE=MEMORY
""")
cursor.execute("CREATE INDEX ValueIndex ON data_table (key1, value1)")

在Redis上,它是3个查询结构的simlair(因为它是我可以获得的最快的mysql,但如果值存在我不需要进行查找,我只是覆盖它来保存查询):< / p>

if r_server.sismember(s - c * x, i):
    r_server.sadd(s, i + 1)

我的redis数据结构是在链接的问题中(基本上是一个列表,3 =&gt; 1 2 3而不是mysql有3行代表3 = 1,3 = 2,3 = 3.

希望有帮助,其他任何问题请告诉我。

1 个答案:

答案 0 :(得分:5)

查看提供的代码片段,我想说这里的主要瓶颈是网络或TCP环回的rountrips。 MySQL和Redis都是同步客户端/服务器存储。每次发送查询并等待回复时,您需要支付内核调度,网络延迟,CPU缓存命中率等...

在TCP服务器上每秒运行数十万个查询的人不使用单个套接字来定位服务器,而是使用多个连接来实现客户端并行和/或pipeline their queries以限制影响这种延迟。

实际上,如果您有一个唯一的套接字并按顺序发送您的查询而没有任何流水线操作,那么您不会测量服务器可以达到的最大吞吐量,而是测量网络或IPC的延迟。

希望大多数NoSQL服务器使用的协议通常支持流水线操作。所以这里有一些关于Redis实现的建议。

您可能需要先阅读the Redis benchmark page。描述了在对Redis进行基准测试时可能遇到的所有典型性能瓶颈。

以下是一些实现基准测试最大吞吐量的建议:

  • 使用有效的语言(Python,Ruby,Javascript比C慢)
  • 尽可能地管理您的查询
  • 如果客户端和服务器在同一个盒子上,请使用unix域套接字而不是TCP环回。
  • 仅在优化软件(NUMA,NIC配置等)后在系统和网络级别进行优化

我使用hiredis(C Redis客户端)运行了一个简单的测试,以在Xeon X5670@2.93GHz上模拟您的用例。可以找到代码here

if r_server.sismember(s - c * x, i):
    r_server.sadd(s, i + 1)

该程序实现了类似的代码,管道化查询。它批量处理项目并发送一堆sismember命令来知道项目是否存在,然后是一堆必须添加的项目的sadd命令。

<强>结果:

  • 没有流水线操作,TCP loopback =&gt; 66268 q / s
  • 没有流水线,使用unix域套接字=&gt; 89485 q / s
  • 使用流水线和TCP环回=&gt; 273757 q / s
  • 使用流水线和unix域套接字=&gt; 278254 q / s

因此,当未实现往返时,使用unix域套接字的影响很大,并且一旦使用管道传输,则变得非常低。大部分收益来自流水线。这就是为什么你应该首先关注软件/协议优化。

通过调整系统/网络配置可以进一步改善结果,但获得更多吞吐量的下一步通常是运行多个Redis实例并使用散列机制对数据进行分片(尝试在服务器端并行化)。