我知道这个问题在stackoverflow中被问了很多次。我发布这个问题是为了找出我的设计的最佳选择。我的工作细节如下。
_unique_key varchar(256) NULL
_job_handle varchar(256) NULL
_data varchar(1024) NULL
_user_id int(11) NULL
_server_ip varchar(39) NULL
_app_version varchar(256) NULL
_state int(11) NULL
_is_set_stopped bool
我们在这张桌子上做什么操作:
- 对于每个作业,我们将对此表进行一次更新和10次选择查询。所以我们需要高频率的读写
- 有许多应用程序通过对以下项进行筛选来操作此表:
- _unique_key
- _州
- is_set_stopped
- _user_id
- _数据字段大小根据应用程序和用户的类型从5KB到1MB不等
- 应用程序可以更新选择性属性
我们认为的解决方案:
MySQL InnoDB
我认为MySQL由于对高读写的要求而无法扩展。
MySQL内存表
这个解决方案的问题是
- 它不支持动态字段大小。MEMORY表使用固定长度的行存储格式。可变长度类型(如VARCHAR)使用固定长度进行存储。来源http://dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html
- 选择。。。。更新它将锁定整个表。我不知道这会不会是个问题
Redis
Redis看起来是个不错的选择。但我认为我的表不适合键值缓存服务器。
- 它只支持一组let’s数据类型。我只能在列表中存储字符串。我需要将字段存储为JSON或其他格式
- 若客户端想要更新特定的属性,他们需要下载完整的值,然后对对象进行解析并重新发布到服务器。也许我错了,有办法吗
- 无法根据值进行筛选。也许我错了,有办法吗
TMPFS文件系统上的MySQL InnoDB
这看起来很有希望。但不要不,在内存表中,它的规模会足够类似于Redis或MySQL。
在这个问题中,您混淆了原始性能(即效率)和可伸缩性。它们是不同的概念。
在InnoDB和内存引擎之间,InnoDB可能是最具可扩展性的。InnoDB支持多版本并发控制,有大量的优化来处理争用,因此它将比内存引擎更好地处理并发访问。即使在某些I/O受限的情况下速度可能较慢。
Redis是一个单线程服务器。所有操作都是序列化的。它的可扩展性为零。这并不意味着它效率低下。相反,它可能会支持比MySQL更多的连接(由于其基于epoll的事件循环)和更多的流量(由于其非常高效的无锁实现和内存中的数据结构)。
为了回答您的问题,我将尝试使用InnoDB访问MySQL。如果配置得当(没有同步提交、足够的缓存缓冲区等),它可以保持良好的吞吐量。我会考虑SSD硬件,而不是在tmpfs上运行它。
现在,如果你更喜欢使用Redis(它不是关系存储btw),你当然可以这样做。没有必要系统地序列化/反序列化你的数据。过滤确实是可能的,前提是您可以预测所有访问路径并找到合适的数据结构。
例如:
- 每个作业一个哈希对象。密钥是_unique_key。散列的字段应该与关系表的列相对应
- 每个状态值一组
- is_set_stopped 2套
- 每个userid值一组
对于每个作业插入,您需要通过管道传输以下命令:
HMSET job:AAA job_handle BBB data CCC user_id DDD server_ip EEE app_version FFF state GGG is_set_stopped HHH
SADD state:GGG AAA
SADD is_set_stopped:HHH AAA
SADD user_id:DDD AAA
只要维护相应的集合,就可以轻松地单独更新任何字段。
可以通过交叉集合来执行筛选查询。例如:
SINTER is_set_stopped:HHH state:GGG
对于Redis,瓶颈可能是网络,尤其是在数据字段很大的情况下。我希望你能有更多5KB的工作,而不是1MB的工作。例如,1 MB对象的1000次写入/秒表示8 GB/秒,可能超过您的网络所能承受的速度。Redis和MySQL都是如此。
我建议postgresql,它比mysql更有能力(有更多的功能,更好地支持复杂的查询和数据类型),并且有很多调优选项。
如果您给postgresql足够的内存并正确调整参数,它将缓存内存中的所有内容。
或者,如果你喜欢的话,你也可以在tmpfs上使用它,并使用流式复制到磁盘上的数据库来进行硬拷贝。
流复制有异步、接收和fsync三种操作模式。如果使用第一个异步,则不必等待同步到复制服务器上的磁盘,因此tmpfs的任何更新都会非常快。
由于您似乎也有很多文本字段,另一个功能可能会有所帮助,postgresql可以在一行上存储一个文本搜索向量,您可以在该向量上添加一个索引,并通过触发器更新它,其中包含您正在搜索的所有行的连接内容。与在mysql中编写文本搜索的任何方式相比,在多列上进行文本搜索时,这将极大地提高性能。
无论使用何种数据库:
你说_data是varchar[1024],但你说它包含5K到1M的数据?这真的是一个斑点吗?即使是长度错误,mysql也不支持长度超过65535字节的varchar字段!我想它没有其他行更新得那么多,明智的做法是将其分为两个表,一个表包含静态数据,另一个表具有动态数据,以最大限度地减少磁盘访问。