我有user
表与innoDB
引擎,其中有大约百万个驱动程序
CREATE TABLE user (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Column2` varchar(14) NOT NULL,
`Column3` varchar(14) NOT NULL,
`lat` double NOT NULL,
`lng` double NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB
我有一个移动应用程序跟踪用户的位置并将其发送到服务器并保存。
现在确定当它上线并让数百万的司机发送他们的位置......数据库将会停机或非常慢。
当普通用户使用应用程序(读/写记录)时,如何避免Mysql数据库性能下降
我正在考虑创建新数据库以跟踪驱动程序位置,然后我将通过cronjob更新主数据库,例如每隔特定时间用lat / lng更新users
表
我在这里有一些限制......我不能在这个阶段切换到无sql数据库
答案 0 :(得分:0)
每秒插入3333行。务必以某种方式“批量”插入。要获得更高的插入率,请参阅http://mysql.rjweb.org/doc.php/staging_table
DOUBLE
对于lat / lng来说是过度的,浪费了空间。表的大小可能导致性能问题(当表变得“巨大”时)。对于定位车辆,FLOAT
可能更好 - 2个浮点数为8个字节,2个双点数为16个字节。分辨率为1.7米(5.6英尺)。参考:
http://mysql.rjweb.org/doc.php/latlng#representation_choices
另一方面,如果每个用户只有一个lat / lng,那么一百万行将小于100MB,而不是一个非常大的表。
要执行哪些查询?对桌子的一百万行可能是昂贵的。 “查找10英里(或公里)范围内的所有用户”将需要进行表扫描。建议查看边界框以及几个二级索引。
更多强>
更新位置的调用应该连接,更新,断开连接。这将花费几分之一秒,可能不会超载max_connections
。那个环境不应该太高;它可能会引发麻烦。同时将back_log
设置为大约相同的值。
考虑“连接池”,其详细信息取决于您的应用语言,Web服务器,MySQL版本等。
与WHERE
中的“边界框”一起,INDEX(lat), INDEX(lng)
;优化器会在它们之间进行选择。
现在服务器中有很多CPU核心?将Web服务器线程数限制为大约两倍。这提供了另一种限制机制来避免“雷鸣般的群体同步”。
同时使用query_cache_size=0
和query_cache_type=0
关闭查询缓存。否则,质量控制会花费一些开销,而基本上从不提供任何好处。
批量INSERTs
是可行的。但是您需要批量UPDATEs
。这比较棘手。通过在表中收集更新,然后执行单个多表UPDATE
从该表复制到主表中,它应该是实用的。这个额外的表可以像我在“staging_table”链接中讨论的乒乓球一样工作。但是......首先让我们看看其他修复是否足够。
使用innodb_flush_log_at_trx_commit = 2
。否则,瓶颈将是记录事务。缺点(丢失1秒的更新)可能不是你的应用程序的问题 - 因为你很快就会得到另一个lat / lng。
寻找附近的车辆 - 这比边界框更好,但它更复杂:http://mysql.rjweb.org/doc.php/latlng。经常寻找“近处”。我希望它不是3333 /秒;这在单个服务器中不实用。 (多个Slave可以提供解决方案。)无论如何,结果集不会很快变化。
答案 1 :(得分:0)
这里要解开很多......
首先,考虑使用spatial data types存储lat和long。反过来,这将允许您使用空间索引,这些索引针对在边界框中查找人员进行了优化。
其次,如果您期望如此高的流量,您可能需要一些奇特的解决方案。
首先 - 设置一个测试装备,与生产硬件类似,这样你就可以找到瓶颈。如果您希望在5分钟内插入100K,那么您每秒平均看到100.000 / 5/60 = 333次插入。但是平均缩放通常是一个坏主意 - 你需要扩展到峰值。我的经验法则是,如果平均值在1到10分钟范围内,你需要能够将平均值提高10倍,所以你需要寻找大约3000次插入/秒。
我使用负载测试工具(JMeter很棒) - 并确保负载测试基础架构中的瓶颈不在目标服务器上。计算出目标系统开始达到可接受的响应时间边界的负载 - 对于简单的插入语句,我将其设置为1秒。如果您使用的是现代硬件,没有触发器和精心设计的表格,我预计每秒至少会有500次插入(我的Macbook接近这一点)。
使用此测试装备来优化数据库架构和索引 - 您可以从MySQL中获得很多性能!
下一步是痛苦的 - 你可以做很少的事情来提高MySQL插入的原始性能(大量的内存,快速的SSD驱动器,快速的CPU;你可以使用一个没有的临时表)索引得到另外几个百分点的改进)。如果你无法用" vanilla"来达到你的目标性能目标。 MySQL,你现在需要看看更具异国情调的解决方案。
第一个是最简单的 - 让你的应用程序不那么健谈。这将有助于整个解决方案的可扩展性(我假设您在应用程序和数据库之间有Web /应用程序服务器 - 它们也需要扩展)。例如,可能应用程序可以存储1分钟,5分钟,10分钟,60分钟,2400分钟的数据并将其作为批处理发送,而不是发送实时更新。如果您有100万每日活跃用户,其活跃用户数达到100.000,则每天可以更容易地扩展到100万笔交易,而不是每5分钟扩展到100,000笔交易。
第二个选项是将message queuing server放在数据库前面。消息队列系统比数据库更容易扩展,但是您要为架构增加显着的额外复杂性。
第三个选项是clustering。这允许负载分布在多个物理数据库服务器上 - 但再次引入了额外的复杂性和成本。