UID835
现金0
在线时间0 小时
注册时间2018-11-19
黑狼菜鸟
- 积分
- 0
|
泉源:阿飞的博客
写在前面:假如对分库分表还不是很认识的,可以参考笔者之前的文章《分库分表技能演进&最佳实践》。
在这篇文章中提到了一个场景,即电商的订单。我们都知道订单表有三大重要查询:基于订单ID查询,基于商户编号查询,基于用户ID查询。且那篇文章给出的方案是基于订单ID、商户编号、用户ID都有一份分库分表的数据。那么为什么要这么做?可否只基于某一列比方用户ID分库分表,答案肯定是不能。
笔者基于sharding-sphere(GitHub地点:http://github.com/apache/incubator-shardingsphere)举行了一个简朴的测试,测试情况如下:
- 128个分表:image_${0..127};
- 数据库服务器:32C64G;
- 数据库版本:MySQL-5.7.23;
- 操纵体系:CentOS 6.9 Final;
- 毗连池:druid 1.1.6;
- mysql-connector-java:6.0.5;
- mybatis:3.4.5;
- mybatis-spring:1.3.1;
- springboot:1.5.9.RELEASE;
- sharding-sphere-3.1.0;
- JVM参数:-Xmx2g -Xms2g -Xmn1g -Xss256k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:+AlwaysPreTouch;
- druid设置:默认参数;
表信息如下:
-- id是分片键。备注,DDL是伪SQL
CREATE TABLE `image_${0..127}` (
`id` varchar(32) NOT NULL,
`image_no` varchar(50) NOT NULL,
`file_name` varchar(200) NOT NULL COMMENT '影像文件名称',
`source` varchar(32) DEFAULT NULL COMMENT '影像泉源',
`create_date` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '影像文件创建时间',
PRIMARY KEY (`id`),
KEY `idx_image_no` (`image_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
第1个测试场景如下:
- 每个分表大概160w数据;
- 累计1w次跨分片(imageNo)查询 PK. 带分片(id)查询;
测试效果如下:
分片键PK.跨分片键结论:由测试效果可知,跨分片查询相比带分片键查询的性能衰减了许多。
第2个测试场景如下:
- 每个分表大概160w数据;
- 累计1w次分别测试跨1个分表,8个分表、16个分表、32个分表、64个分表、128个分表,效果如下:
跨分片键查询压力测试结论:跨的分表数目越大,跨分表查询的性能越差;
我们要弄明确跨分片查询为什么这么慢之前,起首要把握跨分片查询原理。以sharding-sphere为例,其跨分片查询的原理是:通过线程池并发哀求到全部符合路由规则的目的分表,然后对全部效果举行归并。必要阐明的是,当路由效果只有1个,即不跨分片操纵时sharding-sphere不会通过线程池异步实行,而是直接同步实行,这么做的缘故原由是为了淘汰线程开销,焦点源码在ShardingExecuteEngine.java中)。
既然是这个实行原理,为什么跨分片查询,随着跨分片数目越多,性能会越来越差?我们再看一下第2个测试场景,当测试跨1个分表时,1w次查询只必要5889ms,即均匀1次查询不到1ms。以是性能瓶颈不应该在SQL实行阶段,而应该在效果归并阶段。为了验证这个料想,笔者空跑sharding-sphere依靠的并发实行组件google-guava的MoreExecutors。其效果如下:
Multi-Thread Executor Test结论:由这个测试效果可知,当并发实行越来越多,其效果归并的代价越来越大。
附--空跑sharding-sphere依靠的并发实行组件google-guava的MoreExecutors的部门源码如下:
public class ConcurrentExecutorTest {
private static final ListeningExecutorService executorService;
public static final int CONCURRENT_COUNT = 64;
public static final int batchSize = CONCURRENT_COUNT;
public static final int EXECUTOR_SIZE = 8;
static {
executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(EXECUTOR_SIZE));
MoreExecutors.addDelayedShutdownHook(executorService, 60, TimeUnit.SECONDS);
}
private static List execute(final Collection<I> inputs) {
if (inputs.isEmpty()) {
return Collections.emptyList();
}
// 并发实行
Collection allFutures = asyncExecute(inputs);
// 效果归并
return getResults(allFutures);
}
private static Collection asyncExecute(final Collection<I> inputs) {
Collection result = new ArrayList(inputs.size());
for (final I each : inputs) {
// 异步实行时直接返回效果
result.add(executorService.submit(() -> (O) each));
}
return result;
}
private static List getResults(final Collection allFutures) {
List result = new LinkedList();
for (ListenableFuture each : allFutures) {
result.add(each.get());
}
return result;
}
}
总结
跨分片查询的性能这么差,为什么sharding-sphere还要去做呢?笔者以为起首sharding-sphere是一个通用的分库分表中心件,而不是在某些特定条件才气利用的中心件,以是应该要尽大概的兼容全部SQL。其次,纵然跨分片查询性能这么差,这个重要是在OLTP体系中利用时要警惕,在一些OLAP大概背景管理体系等一些低频次操纵的体系中,照旧可以利用的。
好比,账户表已经根据账户ID分表,但是在运营操纵的背景管理体系中维护账户信息时,肯定有一些操纵的SQL是不会带有分片键账户ID的,好比查询账户余额最多的88个土豪用户。这个时间,我们可以通过sharding-sphere中心件直接实行这条低频次SQL。而不必要为了这些操纵引入es大概其他组件来办理这种低频次的题目(固然,随着体系的演进,末了大概照旧必要引入es等一些中心件来办理这些题目)。以是,分库分表中心件的跨分片查询在项目特定阶段可以或许大大淘汰开辟本钱,从而以最短的时间上线业务需求。
号外:近来整理了之前编写的一系列内容做成了PDF,关注我并复兴相应口令获取:
- 001 领取:《Spring Boot底子教程》
- 002 领取:《Spring Cloud底子教程》
更多内容连续奉上,敬请等待
- END -
近期热文:
- 别看不起分区表:我要为你点个赞
- Spring Cloud Greenwich 正式发布
- 用认知和人性来做最棒的步伐员
- Gitlab-CI连续集成的完备实践
- 在前后端分离的路上蒙受了多少痛?
- 你真的会高效的在GitHub上搜刮开源项目吗?
- 中台是个什么鬼?
看完,赶紧点个“悦目”鸭
点鸭点鸭
↓↓↓↓ |
上一篇:手把手教你安装ApacheHive下一篇:LinuxCentOS体系下载安装教程
|