Los*_*oul 9 mysql database hbase redis
我是数据库的新手,但我遇到了一个我似乎无法弄清楚的问题.提前抱歉,如果这太长了,我想总结我所有的努力,以便你知道到目前为止我做了什么.我有一个应用程序有一些逻辑,然后对数据库进行3次查询.第一个查询检查是否存在值,第二个检查是否存在另一个(相关)值,第三个查询是否存在,如果不存在则添加相关值.想想我对数字2进行查询,如果存在,我检查3并在需要时添加它.我做这个循环很多次(我正在查看整体查询,但我怀疑这个程序比写入更重读).我曾经在我的程序中只使用哈希表但是由于我添加了多个进程,因此我遇到了同步问题,因此我决定使用数据库,以便多个内核可以同时处理这个问题.
起初我试过,mysql并使用了一个内存存储引擎(它可能都适合内存),制作了一个复合主键来复制我在程序中的字典,索引它,禁用锁定但我只能获得大约11,000个查询/第二个来自它.
然后我尝试了redis(听说它就像memcache)并创建了我之前拥有的相同键/值dict(这是实际模式我可以使两列彼此独特吗?或者在redis中使用复合主键?)并删除所有fsync的东西所以它希望永远不会击中硬盘i/o但我仍然只能获得大约30,000个查询/秒.我通过让程序在ramdrive等中运行来查看系统改进(我正在使用linux),但结果仍然相似.
我有一个安装脚本,并尝试使用高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
Run Code Online (Sandbox Code Playgroud)
上面是在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)))
Run Code Online (Sandbox Code Playgroud)
这是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)")
Run Code Online (Sandbox Code Playgroud)
在Redis上,它是3个查询结构的simlair(因为它是我可以获得的最快的mysql,除了我不需要查找,如果值存在,我只是覆盖它以保存查询):
if r_server.sismember(s - c * x, i):
r_server.sadd(s, i + 1)
Run Code Online (Sandbox Code Playgroud)
我的redis数据结构是在链接的问题中(基本上是一个列表,3 => 1 2 3而不是mysql有3行代表3 = 1,3 = 2,3 = 3.
希望有所帮助,任何其他问题请告诉我.
看看提供的代码片段,我想说这里的主要瓶颈是网络或TCP环回的rountrips.MySQL和Redis都是同步客户端/服务器存储.每次发送查询并等待回复时,您需要支付内核调度,网络延迟,CPU缓存命中率等等...
谁TCP服务器上运行的每秒查询数以十万计的人不使用一个单一的插座为目标的服务器,但是客户端并行性和/或多个连接管道他们的查询,以限制这种延迟的影响.
实际上,如果您有一个唯一的套接字并按顺序发送您的查询而没有任何流水线操作,那么您不会测量服务器可以实现的最大吞吐量,而是测量网络或IPC的延迟.
希望大多数NoSQL服务器使用的协议通常支持流水线操作.所以这里有一些关于Redis实现的建议.
您可能希望首先阅读Redis基准页面.描述了在对Redis进行基准测试时可能遇到的所有典型性能瓶颈.
以下是一些实现基准测试最大吞吐量的建议:
我使用hiredis(C Redis客户端)运行了一个简单的测试,以在Xeon X5670@2.93GHz上模拟您的用例.代码可以在这里找到.
if r_server.sismember(s - c * x, i):
r_server.sadd(s, i + 1)
Run Code Online (Sandbox Code Playgroud)
该程序实现了类似的代码,管道化查询.它批量处理项目并发送一堆sismember命令来知道项目是否存在,然后是一堆必须添加的项目的sadd命令.
结果:
因此,当未实现往返时,使用unix域套接字的影响很大,并且一旦使用流水线操作,则变得非常低.大部分收益来自流水线.这就是为什么你应该首先关注软件/协议优化.
结果可通过调整系统/网络配置可以进一步提高,但接下来的步骤,以获得更多的吞吐量是正常运行几个Redis的实例和分片使用散列机构(试图并行服务器端)的数据.