.Net 下高性能分表分库组件-连ShardingCore接模式原理

ShardingCore 一款ef-core下高性能、轻量级针对分表分库读写分离的解决方案,具有零依赖、零学习成本、零业务代码入侵。


Github Source Code 助力dotnet 生态 Gitee Source Code


介绍

在分表分库领域java有着很多的解决方案,尤其是客户端解决方案(ShardingSphere),因为客户端解决方案有着极高的性能,但是缺点也很明显数据库链接的消耗相对较高,使用语言的限制让我们.Net望而却步,但是哪怕是有着这些缺点其实也不足以掩盖客户端分表分库带来的便捷与高效。
目前本人所开发的ShardingCore 是.Net下基于efcore2+的所有版本的分表分库很多都是借鉴了ShardingSphere,并且对其很多缺点进行了弥补。这边可能有人就要说了,你为什么做个efcore的不做个ado.net的呢,说实话我这边确实有一个ado.net版本的分表分库,你可以理解为ShardingSphere的.Net复刻版本sharding-conector 最最最初版本的分表聚合已经实现底层原理和ShardingSphere一致使用的Antlr4的分词。为什么不对这个版本进行推进转而对efcoresharding-core版本进行升级维护呢,这边主要有两点,第一点如果我是在ado.net上进行的推进那么势必可以支持更多的orm框架,但是orm框架下的很多特性将可能无法使用,并且需要维护各个数据库版本之间的差异。比如efcore下的批量操作等一些列优化语法是很难被支持的。第二点针对某个orm的扩展性能和使用体验上远远可以大于通用性组件。这就是我为什么针对ShardingCore进行有段优化和升级的原因。

性能

其实性能一直是大家关注的一个点,我用了ShardingCore那么针对特定的查询他的损耗是多少是一个比较令人关注的话题。接下来我放出之前做的两次性能比较,当然这两次比较并不是特意准备的,是我边开发边跑的一个是sqlserver 一个是mysql

性能测试

以下所有数据均在开启了表达式编译缓存的情况下测试,并且电脑处于长时间未关机并且开着很多vs和idea的情况下仅供参考,所有测试都是基于ShardingCore x.3.1.63+ version

以下所有数据均在源码中有案例

efcore版本均为6.0 表结构为string型id的订单取模分成5张表

N代表执行次数

sql server 2012,data rows 7734363 =773w

// * Summary *

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.100
[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT

MethodNMeanErrorStdDevMedian
NoShardingIndexFirstOrDefaultAsync102.154 ms0.1532 ms0.4443 ms1.978 ms
ShardingIndexFirstOrDefaultAsync104.293 ms0.1521 ms0.4485 ms4.077 ms
NoShardingNoIndexFirstOrDefaultAsync10823.382 ms16.0849 ms18.5233 ms821.221 ms
ShardingNoIndexFirstOrDefaultAsync10892.276 ms17.8131 ms16.6623 ms894.880 ms
NoShardingNoIndexCountAsync10830.754 ms16.5309 ms38.6405 ms821.736 ms
ShardingNoIndexCountAsync10915.630 ms8.8511 ms7.3911 ms914.107 ms
NoShardingNoIndexLikeToListAsync107,008.918 ms139.4664 ms166.0248 ms6,955.674 ms
ShardingNoIndexLikeToListAsync107,044.168 ms135.3814 ms132.9626 ms7,008.057 ms
NoShardingNoIndexToListAsync10787.129 ms10.5812 ms8.8357 ms785.798 ms
ShardingNoIndexToListAsync10935.880 ms16.3354 ms15.2801 ms940.369 ms

mysql 5.7,data rows 7553790=755w innerdb_buffer_size=3G

// * Summary *

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.100
[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT

MethodNMeanErrorStdDevMedian
NoShardingIndexFirstOrDefaultAsync105.020 ms0.1245 ms0.3672 ms4.855 ms
ShardingIndexFirstOrDefaultAsync107.960 ms0.1585 ms0.2514 ms7.974 ms
NoShardingNoIndexFirstOrDefaultAsync1011,336.083 ms623.8044 ms1,829.5103 ms11,185.590 ms
ShardingNoIndexFirstOrDefaultAsync105,422.259 ms77.5386 ms72.5296 ms5,390.019 ms
NoShardingNoIndexCountAsync1014,229.819 ms82.8929 ms77.5381 ms14,219.773 ms
ShardingNoIndexCountAsync103,085.268 ms55.5942 ms49.2828 ms3,087.704 ms
NoShardingNoIndexLikeToListAsync1027,046.390 ms71.2034 ms59.4580 ms27,052.316 ms
ShardingNoIndexLikeToListAsync105,707.009 ms106.8713 ms99.9675 ms5,672.453 ms
NoShardingNoIndexToListAsync1026,001.850 ms89.2787 ms69.7030 ms25,998.407 ms
ShardingNoIndexToListAsync105,490.659 ms71.8199 ms67.1804 ms5,477.891 ms

具体可以通过first前两次结果来计算得出结论单次查询的的损耗为0.2-0.3毫秒之间,通过数据聚合和数据路由的损耗单次在0.3ms-0.4ms,其中创建dbcontext为0.1毫秒目前没有好的优化方案,0.013毫秒左右是路由表达式解析和编译,复杂表达式可能更加耗时,剩下的0.2毫秒为数据源和表后缀的解析等操作包括实例的反射创建和数据的聚合,
sqlserver的各项数据在分表和未分表的情况下都几乎差不多可以得出在770w数据集情况下数据库还并未是数据瓶颈的关键,但是mysql可以看到在分表和未分表的情况下如果涉及到没有索引的全表扫描那么性能的差距将是分表后的表数目之多,测试中为5-6倍,也就是分表数目

如果你可以接受单次查询的损耗在0.2ms-0.3ms的那相信这款框架将会是efcore下非常完美的一款分表分库组件


链接模式

说了这么多这边需要针对ShardingCore在查询下面涉及到N表查询后带来的链接消耗是一个不容小觑的客观因素。所以这边参考ShardingSphere进行了类似原理的实现。就是如果查询涉及不同库那么直接并发,如果是同库的将根据用户配置的单次最大链接进行串行查询,并且动态选择使用流式聚合和内存聚合。

首先我们看下ShardingSphere的链接模式在限制链接数的情况下是如何进行处理的
03e4cb86c1845deb978ae87298417c53.png
针对不同的数据库采用并行执行,针对同一个数据库根据用户配置的最大连接数进行分库串行执行,并且因为需要控制链接数所以会将结果集保存在内存中,最后通过合并返回给客户端数据。
之后我们会讲这个模式的缺点并且ShardingCore是如何进行优化的

你可能已经蒙了这么多名称完全没有一个概念。接下来我将一一进行讲解,首先我们来看下链接模式下有哪些参数

MaxQueryConnectionsLimit

最大并发链接数,就是表示单次查询sharding-core允许使用的dbconnection,默认会加上1就是说如果你配置了MaxQueryConnectionsLimit=10那么实际sharding-core会在同一次查询中开启11条链接最多,为什么是11不是10因为sharding-core会默认开启一个链接用来进行空dbconnection的使用。如果不设置本参数那么默认是cpu线程数Environment.ProcessorCount

ConnectionMode

链接模式,可以由用户自行指定,使用内存限制,和连接数限制或者系统自行选择最优

链接模式,有三个可选项,分别是:

MEMORY_STRICTLY

内存限制模式最小化内存聚合 流式聚合 同时会有多个链接

MEMORY_STRICTLY的意思是最小化内存使用率,就是非一次性获取所有数据然后采用流式聚合

CONNECTION_STRICTLY

连接数限制模式最小化并发连接数 内存聚合 连接数会有限制

CONNECTION_STRICTLY的意思是最小化连接并发数,就是单次查询并发连接数为设置的连接数MaxQueryConnectionsLimit。因为有限制,所以无法一直挂起多个连接,数据的合并为内存聚合采用最小化内存方式进行优化,而不是无脑使用内存聚合

SYSTEM_AUTO

系统自动选择内存还是流式聚合

系统自行选择会根据用户的配置采取最小化连接数,但是如果遇到分页则会根据分页策略采取内存限制,因为skip过大会导致内存爆炸

解释

MEMORY_STRICTLY

MEMORY_STRICTLY内存严格模式,用户使用本属性后将会严格控制查询的聚合方式,将会采用流式聚合的迭代器模式,而不是一次性全部去除相关数据在内存中排序获取,通过用户配置的MaxQueryConnectionsLimit连接数来进行限制,比如MaxQueryConnectionsLimit=2,并且本次查询涉及到一个库3张表,因为程序只允许单次查询能并发2个链接,所以本次查询会被分成2组每组两个,其中第二组只有一个,在这种情况下第一次并发查询2条语句因为采用内存严格所以不会将数据获取到内存,第二次在进行一次查询并将迭代器返回一共组合成3个迭代器后续通过流式聚合+优先级队列进行返回所要的数据,在这种情况下程序的内存是最少的但是消耗的链接也是最大的。当用户手动选择MEMORY_STRICTLYMaxQueryConnectionsLimit将变成并行数目. 该模式下ShardingCoreShardingSphere的处理方式类似基本一致
40c2958c893eceee8b7e8ad4b0e218fe.png

CONNECTION_STRICTLY

CONNECTION_STRICTLY连接数严格模式,用户使用本属性后将会严格控制查询后的同一个数据库下的同时查询的链接数,不会因为使用流式内存而导致迭代器一致开着,因为一个迭代器查询开着就意味着需要一个链接,如果查询需要聚合3张表那么就需要同时开着三个链接来迭代保证流式聚合。通过用户配置的MaxQueryConnectionsLimit连接数来进行限制,比如MaxQueryConnectionsLimit=2,并且本次查询涉及到一个库3张表,因为程序只允许单次查询能并发2个链接,所以本次查询会被分成2组每组两个,其中第二组只有一个,在这种情况下第一次并发查询2条语句因为采用连接数严格所以不会一直持有链接,会将链接结果进行每组进行合并然后将连接放回,合并时还是采用的流式聚合,会首先将第一组的两个链接进行查询之后将需要的结果通过流式聚合取到内存,然后第二组会自行独立查询并且从第二次开始后会将上一次迭代的内存聚合数据进行和本次查询的流式聚合分别一起聚合,保证在分页情况下内存数据量最少。因为如果每组都是用独立的内存聚合那么你有n组就会有n*(skip+take)的数目,而ShardingSphere采用的是更加简单的做法,就是将每组下面的各自节点都自行进行内存聚合,那么如果在skip(10).take(10)的情况下sql会被改写成各组的各个节点分别进行skip(0).take(20)的操作那么2组执行器的第一组将会有40条数据第二组将会有20条数据一共会有60条数据远远操作了我们所需要的20条。所以在这个情况下ShardingCore第一组内存流式聚合会返回20条数据,第二组会将第一组的20条数据和第二组的进行流式聚合内存中还是只有20条数据,虽然是连接数严格但是也做到了最小化内存单元。当用户手动选择CONNECTION_STRICTLYMaxQueryConnectionsLimit将是正则的最小化链接数限制

e4f40e6fe483de267f8664fe30b91ce5.png

SYSTEM_AUTO

SYSTEM_AUTO系统自行选择,这是一个非常帮的选择,因为在这个选择下系统会自动根据用户配置的MaxQueryConnectionsLimit来自行控制是采用流式聚合还是内存聚合,并且因为我们采用的是同数据库下面最小化内存相比其他的解决方案可以更加有效和高性能的来应对各种查询。仅仅只需要配置一个最大连接数限制既可以适配好连接模式。

这边极力推荐大家在不清楚应该用什么模式的时候使用SYSTEM_AUTO并且手动配置MaxQueryConnectionsLimit来确定各个环境下的配置一直而不是采用默认的cpu线程数。

首先我们通过每个数据库被路由到了多少张表进行计算期望用户在配置了xx后应该的并行数来进行分组,sqlCount :表示这个数据库被路由到的表数目,exceptCount :表示计算出来的应该的单次查询并行数

//代码本质就是向上取整int exceptCount =Math.Max(0 == sqlCount % maxQueryConnectionsLimit? sqlCount / maxQueryConnectionsLimit: sqlCount / maxQueryConnectionsLimit + 1, 1);

第二次我们通过判断sqlCountmaxQueryConnectionsLimit的大小来确定链接模式的选择

private ConnectionModeEnum CalcConnectionMode(int sqlCount){switch (_shardingConfigOption.ConnectionMode){case ConnectionModeEnum.MEMORY_STRICTLY:case ConnectionModeEnum.CONNECTION_STRICTLY: return _shardingConfigOption.ConnectionMode;default:{return _shardingConfigOption.MaxQueryConnectionsLimit < sqlCount? ConnectionModeEnum.CONNECTION_STRICTLY: ConnectionModeEnum.MEMORY_STRICTLY; ;}}}

比较

针对ShardingSphere的流程图我们可以看到在获取普通数据的时候是没有什么问题的,但是如果遇到分页也就是

select * from order limit 10,10

这种情况下会被改写成

select * from order limit 0,20

我们可以看到如果是ShardingSphere的流程模式那么在各个节点处虽然已经将连接数控制好了但是对于每个节点而言都有着20条数据,这种情况下其实是一种非常危险的,因为一旦节点过多并且limit的跳过页数过多每个节点储存的数据将会非常恐怖。
98b739b5ce8225b02359b3cc9c1e8664.png

所以针对这种情况ShardingCore将同库下的各个节点组的查询使用StreamMerge而不是MemoryMerge,并且会对各个节点间建立联系进行聚合保证在同一个数据库下只会有20条数据被加载到内存中,大大降低了内存的使用,提高了内存使用率。
e127f244fc683b853697919d7ae0f568.png

当然具体情况应该还需要再次进行优化并不是简单的一次优化就搞定的比如当跳过的页数过多之后其实在内存中的一部分数据也会再次进行迭代和新的迭代器比较,这个中间的性能差距可能需要不断地尝试才可以获取一个比较可靠的值

总结

目前已经有很多小伙伴已经在使用SharidingCore了并且在使用的时候也是相对比较简单的配置既可以“完美”目前她在使用的各种框架譬如:AbpVNext....基本上在继承和使用方面可以说是目前efcore生态下最最最完美的了真正做到了三零的框架:零依赖,零学习成本,零业务代码入侵

最后放一张图

是我这边给ShardingSphere提的建议,也证实了我对该聚合模型的优化是可以有效解决在分页下面聚合各数据库节点下的内存使用情况
b5f2deffc1b6bb4b5a3d4acd3e555893.png

分表分库组件求赞求star

您的支持是开源作者能坚持下去的最大动力

  • Github ShardingCore

  • Gitee ShardingCore

ShardingCore 一款ef-core下高性能、轻量级针对分表分库读写分离的解决方案,具有零依赖、零学习成本、零业务代码入侵。


Github Source Code 助力dotnet 生态 Gitee Source Code


介绍

在分表分库领域java有着很多的解决方案,尤其是客户端解决方案(ShardingSphere),因为客户端解决方案有着极高的性能,但是缺点也很明显数据库链接的消耗相对较高,使用语言的限制让我们.Net望而却步,但是哪怕是有着这些缺点其实也不足以掩盖客户端分表分库带来的便捷与高效。
目前本人所开发的ShardingCore 是.Net下基于efcore2+的所有版本的分表分库很多都是借鉴了ShardingSphere,并且对其很多缺点进行了弥补。这边可能有人就要说了,你为什么做个efcore的不做个ado.net的呢,说实话我这边确实有一个ado.net版本的分表分库,你可以理解为ShardingSphere的.Net复刻版本sharding-conector 最最最初版本的分表聚合已经实现底层原理和ShardingSphere一致使用的Antlr4的分词。为什么不对这个版本进行推进转而对efcoresharding-core版本进行升级维护呢,这边主要有两点,第一点如果我是在ado.net上进行的推进那么势必可以支持更多的orm框架,但是orm框架下的很多特性将可能无法使用,并且需要维护各个数据库版本之间的差异。比如efcore下的批量操作等一些列优化语法是很难被支持的。第二点针对某个orm的扩展性能和使用体验上远远可以大于通用性组件。这就是我为什么针对ShardingCore进行有段优化和升级的原因。

性能

其实性能一直是大家关注的一个点,我用了ShardingCore那么针对特定的查询他的损耗是多少是一个比较令人关注的话题。接下来我放出之前做的两次性能比较,当然这两次比较并不是特意准备的,是我边开发边跑的一个是sqlserver 一个是mysql

性能测试

以下所有数据均在开启了表达式编译缓存的情况下测试,并且电脑处于长时间未关机并且开着很多vs和idea的情况下仅供参考,所有测试都是基于ShardingCore x.3.1.63+ version

以下所有数据均在源码中有案例

efcore版本均为6.0 表结构为string型id的订单取模分成5张表

N代表执行次数

sql server 2012,data rows 7734363 =773w

// * Summary *

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.100
[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT

MethodNMeanErrorStdDevMedian
NoShardingIndexFirstOrDefaultAsync102.154 ms0.1532 ms0.4443 ms1.978 ms
ShardingIndexFirstOrDefaultAsync104.293 ms0.1521 ms0.4485 ms4.077 ms
NoShardingNoIndexFirstOrDefaultAsync10823.382 ms16.0849 ms18.5233 ms821.221 ms
ShardingNoIndexFirstOrDefaultAsync10892.276 ms17.8131 ms16.6623 ms894.880 ms
NoShardingNoIndexCountAsync10830.754 ms16.5309 ms38.6405 ms821.736 ms
ShardingNoIndexCountAsync10915.630 ms8.8511 ms7.3911 ms914.107 ms
NoShardingNoIndexLikeToListAsync107,008.918 ms139.4664 ms166.0248 ms6,955.674 ms
ShardingNoIndexLikeToListAsync107,044.168 ms135.3814 ms132.9626 ms7,008.057 ms
NoShardingNoIndexToListAsync10787.129 ms10.5812 ms8.8357 ms785.798 ms
ShardingNoIndexToListAsync10935.880 ms16.3354 ms15.2801 ms940.369 ms

mysql 5.7,data rows 7553790=755w innerdb_buffer_size=3G

// * Summary *

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
.NET SDK=6.0.100
[Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT

MethodNMeanErrorStdDevMedian
NoShardingIndexFirstOrDefaultAsync105.020 ms0.1245 ms0.3672 ms4.855 ms
ShardingIndexFirstOrDefaultAsync107.960 ms0.1585 ms0.2514 ms7.974 ms
NoShardingNoIndexFirstOrDefaultAsync1011,336.083 ms623.8044 ms1,829.5103 ms11,185.590 ms
ShardingNoIndexFirstOrDefaultAsync105,422.259 ms77.5386 ms72.5296 ms5,390.019 ms
NoShardingNoIndexCountAsync1014,229.819 ms82.8929 ms77.5381 ms14,219.773 ms
ShardingNoIndexCountAsync103,085.268 ms55.5942 ms49.2828 ms3,087.704 ms
NoShardingNoIndexLikeToListAsync1027,046.390 ms71.2034 ms59.4580 ms27,052.316 ms
ShardingNoIndexLikeToListAsync105,707.009 ms106.8713 ms99.9675 ms5,672.453 ms
NoShardingNoIndexToListAsync1026,001.850 ms89.2787 ms69.7030 ms25,998.407 ms
ShardingNoIndexToListAsync105,490.659 ms71.8199 ms67.1804 ms5,477.891 ms

具体可以通过first前两次结果来计算得出结论单次查询的的损耗为0.2-0.3毫秒之间,通过数据聚合和数据路由的损耗单次在0.3ms-0.4ms,其中创建dbcontext为0.1毫秒目前没有好的优化方案,0.013毫秒左右是路由表达式解析和编译,复杂表达式可能更加耗时,剩下的0.2毫秒为数据源和表后缀的解析等操作包括实例的反射创建和数据的聚合,
sqlserver的各项数据在分表和未分表的情况下都几乎差不多可以得出在770w数据集情况下数据库还并未是数据瓶颈的关键,但是mysql可以看到在分表和未分表的情况下如果涉及到没有索引的全表扫描那么性能的差距将是分表后的表数目之多,测试中为5-6倍,也就是分表数目

如果你可以接受单次查询的损耗在0.2ms-0.3ms的那相信这款框架将会是efcore下非常完美的一款分表分库组件


链接模式

说了这么多这边需要针对ShardingCore在查询下面涉及到N表查询后带来的链接消耗是一个不容小觑的客观因素。所以这边参考ShardingSphere进行了类似原理的实现。就是如果查询涉及不同库那么直接并发,如果是同库的将根据用户配置的单次最大链接进行串行查询,并且动态选择使用流式聚合和内存聚合。

首先我们看下ShardingSphere的链接模式在限制链接数的情况下是如何进行处理的
9c7c412de001b38564d2073cccd40203.png
针对不同的数据库采用并行执行,针对同一个数据库根据用户配置的最大连接数进行分库串行执行,并且因为需要控制链接数所以会将结果集保存在内存中,最后通过合并返回给客户端数据。
之后我们会讲这个模式的缺点并且ShardingCore是如何进行优化的

你可能已经蒙了这么多名称完全没有一个概念。接下来我将一一进行讲解,首先我们来看下链接模式下有哪些参数

MaxQueryConnectionsLimit

最大并发链接数,就是表示单次查询sharding-core允许使用的dbconnection,默认会加上1就是说如果你配置了MaxQueryConnectionsLimit=10那么实际sharding-core会在同一次查询中开启11条链接最多,为什么是11不是10因为sharding-core会默认开启一个链接用来进行空dbconnection的使用。如果不设置本参数那么默认是cpu线程数Environment.ProcessorCount

ConnectionMode

链接模式,可以由用户自行指定,使用内存限制,和连接数限制或者系统自行选择最优

链接模式,有三个可选项,分别是:

MEMORY_STRICTLY

内存限制模式最小化内存聚合 流式聚合 同时会有多个链接

MEMORY_STRICTLY的意思是最小化内存使用率,就是非一次性获取所有数据然后采用流式聚合

CONNECTION_STRICTLY

连接数限制模式最小化并发连接数 内存聚合 连接数会有限制

CONNECTION_STRICTLY的意思是最小化连接并发数,就是单次查询并发连接数为设置的连接数MaxQueryConnectionsLimit。因为有限制,所以无法一直挂起多个连接,数据的合并为内存聚合采用最小化内存方式进行优化,而不是无脑使用内存聚合

SYSTEM_AUTO

系统自动选择内存还是流式聚合

系统自行选择会根据用户的配置采取最小化连接数,但是如果遇到分页则会根据分页策略采取内存限制,因为skip过大会导致内存爆炸

解释

MEMORY_STRICTLY

MEMORY_STRICTLY内存严格模式,用户使用本属性后将会严格控制查询的聚合方式,将会采用流式聚合的迭代器模式,而不是一次性全部去除相关数据在内存中排序获取,通过用户配置的MaxQueryConnectionsLimit连接数来进行限制,比如MaxQueryConnectionsLimit=2,并且本次查询涉及到一个库3张表,因为程序只允许单次查询能并发2个链接,所以本次查询会被分成2组每组两个,其中第二组只有一个,在这种情况下第一次并发查询2条语句因为采用内存严格所以不会将数据获取到内存,第二次在进行一次查询并将迭代器返回一共组合成3个迭代器后续通过流式聚合+优先级队列进行返回所要的数据,在这种情况下程序的内存是最少的但是消耗的链接也是最大的。当用户手动选择MEMORY_STRICTLYMaxQueryConnectionsLimit将变成并行数目. 该模式下ShardingCoreShardingSphere的处理方式类似基本一致
dba7853c4e8564cce8c23125c5bb933c.png

CONNECTION_STRICTLY

CONNECTION_STRICTLY连接数严格模式,用户使用本属性后将会严格控制查询后的同一个数据库下的同时查询的链接数,不会因为使用流式内存而导致迭代器一致开着,因为一个迭代器查询开着就意味着需要一个链接,如果查询需要聚合3张表那么就需要同时开着三个链接来迭代保证流式聚合。通过用户配置的MaxQueryConnectionsLimit连接数来进行限制,比如MaxQueryConnectionsLimit=2,并且本次查询涉及到一个库3张表,因为程序只允许单次查询能并发2个链接,所以本次查询会被分成2组每组两个,其中第二组只有一个,在这种情况下第一次并发查询2条语句因为采用连接数严格所以不会一直持有链接,会将链接结果进行每组进行合并然后将连接放回,合并时还是采用的流式聚合,会首先将第一组的两个链接进行查询之后将需要的结果通过流式聚合取到内存,然后第二组会自行独立查询并且从第二次开始后会将上一次迭代的内存聚合数据进行和本次查询的流式聚合分别一起聚合,保证在分页情况下内存数据量最少。因为如果每组都是用独立的内存聚合那么你有n组就会有n*(skip+take)的数目,而ShardingSphere采用的是更加简单的做法,就是将每组下面的各自节点都自行进行内存聚合,那么如果在skip(10).take(10)的情况下sql会被改写成各组的各个节点分别进行skip(0).take(20)的操作那么2组执行器的第一组将会有40条数据第二组将会有20条数据一共会有60条数据远远操作了我们所需要的20条。所以在这个情况下ShardingCore第一组内存流式聚合会返回20条数据,第二组会将第一组的20条数据和第二组的进行流式聚合内存中还是只有20条数据,虽然是连接数严格但是也做到了最小化内存单元。当用户手动选择CONNECTION_STRICTLYMaxQueryConnectionsLimit将是正则的最小化链接数限制

5fb9bd4d1bbf885440d683d17b9d4c0f.png

SYSTEM_AUTO

SYSTEM_AUTO系统自行选择,这是一个非常帮的选择,因为在这个选择下系统会自动根据用户配置的MaxQueryConnectionsLimit来自行控制是采用流式聚合还是内存聚合,并且因为我们采用的是同数据库下面最小化内存相比其他的解决方案可以更加有效和高性能的来应对各种查询。仅仅只需要配置一个最大连接数限制既可以适配好连接模式。

这边极力推荐大家在不清楚应该用什么模式的时候使用SYSTEM_AUTO并且手动配置MaxQueryConnectionsLimit来确定各个环境下的配置一直而不是采用默认的cpu线程数。

首先我们通过每个数据库被路由到了多少张表进行计算期望用户在配置了xx后应该的并行数来进行分组,sqlCount :表示这个数据库被路由到的表数目,exceptCount :表示计算出来的应该的单次查询并行数

//代码本质就是向上取整int exceptCount =Math.Max(0 == sqlCount % maxQueryConnectionsLimit? sqlCount / maxQueryConnectionsLimit: sqlCount / maxQueryConnectionsLimit + 1, 1);

第二次我们通过判断sqlCountmaxQueryConnectionsLimit的大小来确定链接模式的选择

private ConnectionModeEnum CalcConnectionMode(int sqlCount){switch (_shardingConfigOption.ConnectionMode){case ConnectionModeEnum.MEMORY_STRICTLY:case ConnectionModeEnum.CONNECTION_STRICTLY: return _shardingConfigOption.ConnectionMode;default:{return _shardingConfigOption.MaxQueryConnectionsLimit < sqlCount? ConnectionModeEnum.CONNECTION_STRICTLY: ConnectionModeEnum.MEMORY_STRICTLY; ;}}}

比较

针对ShardingSphere的流程图我们可以看到在获取普通数据的时候是没有什么问题的,但是如果遇到分页也就是

select * from order limit 10,10

这种情况下会被改写成

select * from order limit 0,20

我们可以看到如果是ShardingSphere的流程模式那么在各个节点处虽然已经将连接数控制好了但是对于每个节点而言都有着20条数据,这种情况下其实是一种非常危险的,因为一旦节点过多并且limit的跳过页数过多每个节点储存的数据将会非常恐怖。
3f82061ac599e2f26d2219855bcf81e2.png

所以针对这种情况ShardingCore将同库下的各个节点组的查询使用StreamMerge而不是MemoryMerge,并且会对各个节点间建立联系进行聚合保证在同一个数据库下只会有20条数据被加载到内存中,大大降低了内存的使用,提高了内存使用率。
68a2d2d38e9f0ff86ea557c089f5ad99.png

当然具体情况应该还需要再次进行优化并不是简单的一次优化就搞定的比如当跳过的页数过多之后其实在内存中的一部分数据也会再次进行迭代和新的迭代器比较,这个中间的性能差距可能需要不断地尝试才可以获取一个比较可靠的值

总结

目前已经有很多小伙伴已经在使用SharidingCore了并且在使用的时候也是相对比较简单的配置既可以“完美”目前她在使用的各种框架譬如:AbpVNext....基本上在继承和使用方面可以说是目前efcore生态下最最最完美的了真正做到了三零的框架:零依赖,零学习成本,零业务代码入侵

最后放一张图

是我这边给ShardingSphere提的建议,也证实了我对该聚合模型的优化是可以有效解决在分页下面聚合各数据库节点下的内存使用情况
c6f9e725f88ab3c752d98d5ba7617147.png

分表分库组件求赞求star

您的支持是开源作者能坚持下去的最大动力

  • Github ShardingCore

  • Gitee ShardingCoreShardingCore 一款ef-core下高性能、轻量级针对分表分库读写分离的解决方案,具有零依赖、零学习成本、零业务代码入侵。


    Github Source Code 助力dotnet 生态 Gitee Source Code


    介绍

    在分表分库领域java有着很多的解决方案,尤其是客户端解决方案(ShardingSphere),因为客户端解决方案有着极高的性能,但是缺点也很明显数据库链接的消耗相对较高,使用语言的限制让我们.Net望而却步,但是哪怕是有着这些缺点其实也不足以掩盖客户端分表分库带来的便捷与高效。
    目前本人所开发的ShardingCore 是.Net下基于efcore2+的所有版本的分表分库很多都是借鉴了ShardingSphere,并且对其很多缺点进行了弥补。这边可能有人就要说了,你为什么做个efcore的不做个ado.net的呢,说实话我这边确实有一个ado.net版本的分表分库,你可以理解为ShardingSphere的.Net复刻版本sharding-conector 最最最初版本的分表聚合已经实现底层原理和ShardingSphere一致使用的Antlr4的分词。为什么不对这个版本进行推进转而对efcoresharding-core版本进行升级维护呢,这边主要有两点,第一点如果我是在ado.net上进行的推进那么势必可以支持更多的orm框架,但是orm框架下的很多特性将可能无法使用,并且需要维护各个数据库版本之间的差异。比如efcore下的批量操作等一些列优化语法是很难被支持的。第二点针对某个orm的扩展性能和使用体验上远远可以大于通用性组件。这就是我为什么针对ShardingCore进行有段优化和升级的原因。

    性能

    其实性能一直是大家关注的一个点,我用了ShardingCore那么针对特定的查询他的损耗是多少是一个比较令人关注的话题。接下来我放出之前做的两次性能比较,当然这两次比较并不是特意准备的,是我边开发边跑的一个是sqlserver 一个是mysql

    性能测试

    以下所有数据均在开启了表达式编译缓存的情况下测试,并且电脑处于长时间未关机并且开着很多vs和idea的情况下仅供参考,所有测试都是基于ShardingCore x.3.1.63+ version

    以下所有数据均在源码中有案例

    efcore版本均为6.0 表结构为string型id的订单取模分成5张表

    N代表执行次数

    sql server 2012,data rows 7734363 =773w

    // * Summary *

    BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
    AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
    .NET SDK=6.0.100
    [Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
    DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT

    MethodNMeanErrorStdDevMedian
    NoShardingIndexFirstOrDefaultAsync102.154 ms0.1532 ms0.4443 ms1.978 ms
    ShardingIndexFirstOrDefaultAsync104.293 ms0.1521 ms0.4485 ms4.077 ms
    NoShardingNoIndexFirstOrDefaultAsync10823.382 ms16.0849 ms18.5233 ms821.221 ms
    ShardingNoIndexFirstOrDefaultAsync10892.276 ms17.8131 ms16.6623 ms894.880 ms
    NoShardingNoIndexCountAsync10830.754 ms16.5309 ms38.6405 ms821.736 ms
    ShardingNoIndexCountAsync10915.630 ms8.8511 ms7.3911 ms914.107 ms
    NoShardingNoIndexLikeToListAsync107,008.918 ms139.4664 ms166.0248 ms6,955.674 ms
    ShardingNoIndexLikeToListAsync107,044.168 ms135.3814 ms132.9626 ms7,008.057 ms
    NoShardingNoIndexToListAsync10787.129 ms10.5812 ms8.8357 ms785.798 ms
    ShardingNoIndexToListAsync10935.880 ms16.3354 ms15.2801 ms940.369 ms

    mysql 5.7,data rows 7553790=755w innerdb_buffer_size=3G

    // * Summary *

    BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1500 (1909/November2019Update/19H2)
    AMD Ryzen 9 3900X, 1 CPU, 24 logical and 12 physical cores
    .NET SDK=6.0.100
    [Host] : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
    DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT

    MethodNMeanErrorStdDevMedian
    NoShardingIndexFirstOrDefaultAsync105.020 ms0.1245 ms0.3672 ms4.855 ms
    ShardingIndexFirstOrDefaultAsync107.960 ms0.1585 ms0.2514 ms7.974 ms
    NoShardingNoIndexFirstOrDefaultAsync1011,336.083 ms623.8044 ms1,829.5103 ms11,185.590 ms
    ShardingNoIndexFirstOrDefaultAsync105,422.259 ms77.5386 ms72.5296 ms5,390.019 ms
    NoShardingNoIndexCountAsync1014,229.819 ms82.8929 ms77.5381 ms14,219.773 ms
    ShardingNoIndexCountAsync103,085.268 ms55.5942 ms49.2828 ms3,087.704 ms
    NoShardingNoIndexLikeToListAsync1027,046.390 ms71.2034 ms59.4580 ms27,052.316 ms
    ShardingNoIndexLikeToListAsync105,707.009 ms106.8713 ms99.9675 ms5,672.453 ms
    NoShardingNoIndexToListAsync1026,001.850 ms89.2787 ms69.7030 ms25,998.407 ms
    ShardingNoIndexToListAsync105,490.659 ms71.8199 ms67.1804 ms5,477.891 ms

    具体可以通过first前两次结果来计算得出结论单次查询的的损耗为0.2-0.3毫秒之间,通过数据聚合和数据路由的损耗单次在0.3ms-0.4ms,其中创建dbcontext为0.1毫秒目前没有好的优化方案,0.013毫秒左右是路由表达式解析和编译,复杂表达式可能更加耗时,剩下的0.2毫秒为数据源和表后缀的解析等操作包括实例的反射创建和数据的聚合,
    sqlserver的各项数据在分表和未分表的情况下都几乎差不多可以得出在770w数据集情况下数据库还并未是数据瓶颈的关键,但是mysql可以看到在分表和未分表的情况下如果涉及到没有索引的全表扫描那么性能的差距将是分表后的表数目之多,测试中为5-6倍,也就是分表数目

    如果你可以接受单次查询的损耗在0.2ms-0.3ms的那相信这款框架将会是efcore下非常完美的一款分表分库组件


    链接模式

    说了这么多这边需要针对ShardingCore在查询下面涉及到N表查询后带来的链接消耗是一个不容小觑的客观因素。所以这边参考ShardingSphere进行了类似原理的实现。就是如果查询涉及不同库那么直接并发,如果是同库的将根据用户配置的单次最大链接进行串行查询,并且动态选择使用流式聚合和内存聚合。

    首先我们看下ShardingSphere的链接模式在限制链接数的情况下是如何进行处理的
    e23652f527eea4922206eaedfa4da020.png
    针对不同的数据库采用并行执行,针对同一个数据库根据用户配置的最大连接数进行分库串行执行,并且因为需要控制链接数所以会将结果集保存在内存中,最后通过合并返回给客户端数据。
    之后我们会讲这个模式的缺点并且ShardingCore是如何进行优化的

    你可能已经蒙了这么多名称完全没有一个概念。接下来我将一一进行讲解,首先我们来看下链接模式下有哪些参数

    MaxQueryConnectionsLimit

    最大并发链接数,就是表示单次查询sharding-core允许使用的dbconnection,默认会加上1就是说如果你配置了MaxQueryConnectionsLimit=10那么实际sharding-core会在同一次查询中开启11条链接最多,为什么是11不是10因为sharding-core会默认开启一个链接用来进行空dbconnection的使用。如果不设置本参数那么默认是cpu线程数Environment.ProcessorCount

    ConnectionMode

    链接模式,可以由用户自行指定,使用内存限制,和连接数限制或者系统自行选择最优

    链接模式,有三个可选项,分别是:

    MEMORY_STRICTLY

    内存限制模式最小化内存聚合 流式聚合 同时会有多个链接

    MEMORY_STRICTLY的意思是最小化内存使用率,就是非一次性获取所有数据然后采用流式聚合

    CONNECTION_STRICTLY

    连接数限制模式最小化并发连接数 内存聚合 连接数会有限制

    CONNECTION_STRICTLY的意思是最小化连接并发数,就是单次查询并发连接数为设置的连接数MaxQueryConnectionsLimit。因为有限制,所以无法一直挂起多个连接,数据的合并为内存聚合采用最小化内存方式进行优化,而不是无脑使用内存聚合

    SYSTEM_AUTO

    系统自动选择内存还是流式聚合

    系统自行选择会根据用户的配置采取最小化连接数,但是如果遇到分页则会根据分页策略采取内存限制,因为skip过大会导致内存爆炸

    解释

    MEMORY_STRICTLY

    MEMORY_STRICTLY内存严格模式,用户使用本属性后将会严格控制查询的聚合方式,将会采用流式聚合的迭代器模式,而不是一次性全部去除相关数据在内存中排序获取,通过用户配置的MaxQueryConnectionsLimit连接数来进行限制,比如MaxQueryConnectionsLimit=2,并且本次查询涉及到一个库3张表,因为程序只允许单次查询能并发2个链接,所以本次查询会被分成2组每组两个,其中第二组只有一个,在这种情况下第一次并发查询2条语句因为采用内存严格所以不会将数据获取到内存,第二次在进行一次查询并将迭代器返回一共组合成3个迭代器后续通过流式聚合+优先级队列进行返回所要的数据,在这种情况下程序的内存是最少的但是消耗的链接也是最大的。当用户手动选择MEMORY_STRICTLYMaxQueryConnectionsLimit将变成并行数目. 该模式下ShardingCoreShardingSphere的处理方式类似基本一致
    af8f694d6ea68042fa7d8d9f696eafa5.png

    CONNECTION_STRICTLY

    CONNECTION_STRICTLY连接数严格模式,用户使用本属性后将会严格控制查询后的同一个数据库下的同时查询的链接数,不会因为使用流式内存而导致迭代器一致开着,因为一个迭代器查询开着就意味着需要一个链接,如果查询需要聚合3张表那么就需要同时开着三个链接来迭代保证流式聚合。通过用户配置的MaxQueryConnectionsLimit连接数来进行限制,比如MaxQueryConnectionsLimit=2,并且本次查询涉及到一个库3张表,因为程序只允许单次查询能并发2个链接,所以本次查询会被分成2组每组两个,其中第二组只有一个,在这种情况下第一次并发查询2条语句因为采用连接数严格所以不会一直持有链接,会将链接结果进行每组进行合并然后将连接放回,合并时还是采用的流式聚合,会首先将第一组的两个链接进行查询之后将需要的结果通过流式聚合取到内存,然后第二组会自行独立查询并且从第二次开始后会将上一次迭代的内存聚合数据进行和本次查询的流式聚合分别一起聚合,保证在分页情况下内存数据量最少。因为如果每组都是用独立的内存聚合那么你有n组就会有n*(skip+take)的数目,而ShardingSphere采用的是更加简单的做法,就是将每组下面的各自节点都自行进行内存聚合,那么如果在skip(10).take(10)的情况下sql会被改写成各组的各个节点分别进行skip(0).take(20)的操作那么2组执行器的第一组将会有40条数据第二组将会有20条数据一共会有60条数据远远操作了我们所需要的20条。所以在这个情况下ShardingCore第一组内存流式聚合会返回20条数据,第二组会将第一组的20条数据和第二组的进行流式聚合内存中还是只有20条数据,虽然是连接数严格但是也做到了最小化内存单元。当用户手动选择CONNECTION_STRICTLYMaxQueryConnectionsLimit将是正则的最小化链接数限制

    6d8c9836d41a12f303c782a15152054d.png

    SYSTEM_AUTO

    SYSTEM_AUTO系统自行选择,这是一个非常帮的选择,因为在这个选择下系统会自动根据用户配置的MaxQueryConnectionsLimit来自行控制是采用流式聚合还是内存聚合,并且因为我们采用的是同数据库下面最小化内存相比其他的解决方案可以更加有效和高性能的来应对各种查询。仅仅只需要配置一个最大连接数限制既可以适配好连接模式。

    这边极力推荐大家在不清楚应该用什么模式的时候使用SYSTEM_AUTO并且手动配置MaxQueryConnectionsLimit来确定各个环境下的配置一直而不是采用默认的cpu线程数。

    首先我们通过每个数据库被路由到了多少张表进行计算期望用户在配置了xx后应该的并行数来进行分组,sqlCount :表示这个数据库被路由到的表数目,exceptCount :表示计算出来的应该的单次查询并行数

    //代码本质就是向上取整int exceptCount =Math.Max(0 == sqlCount % maxQueryConnectionsLimit? sqlCount / maxQueryConnectionsLimit: sqlCount / maxQueryConnectionsLimit + 1, 1);

    第二次我们通过判断sqlCountmaxQueryConnectionsLimit的大小来确定链接模式的选择

    private ConnectionModeEnum CalcConnectionMode(int sqlCount){switch (_shardingConfigOption.ConnectionMode){case ConnectionModeEnum.MEMORY_STRICTLY:case ConnectionModeEnum.CONNECTION_STRICTLY: return _shardingConfigOption.ConnectionMode;default:{return _shardingConfigOption.MaxQueryConnectionsLimit < sqlCount? ConnectionModeEnum.CONNECTION_STRICTLY: ConnectionModeEnum.MEMORY_STRICTLY; ;}}}

    比较

    针对ShardingSphere的流程图我们可以看到在获取普通数据的时候是没有什么问题的,但是如果遇到分页也就是

    select * from order limit 10,10

    这种情况下会被改写成

    select * from order limit 0,20

    我们可以看到如果是ShardingSphere的流程模式那么在各个节点处虽然已经将连接数控制好了但是对于每个节点而言都有着20条数据,这种情况下其实是一种非常危险的,因为一旦节点过多并且limit的跳过页数过多每个节点储存的数据将会非常恐怖。
    300401689427e131e8b3c28a3390bdc5.png

    所以针对这种情况ShardingCore将同库下的各个节点组的查询使用StreamMerge而不是MemoryMerge,并且会对各个节点间建立联系进行聚合保证在同一个数据库下只会有20条数据被加载到内存中,大大降低了内存的使用,提高了内存使用率。
    30ad3b50e88397ac1e80257ac354913e.png

    当然具体情况应该还需要再次进行优化并不是简单的一次优化就搞定的比如当跳过的页数过多之后其实在内存中的一部分数据也会再次进行迭代和新的迭代器比较,这个中间的性能差距可能需要不断地尝试才可以获取一个比较可靠的值

    总结

    目前已经有很多小伙伴已经在使用SharidingCore了并且在使用的时候也是相对比较简单的配置既可以“完美”目前她在使用的各种框架譬如:AbpVNext....基本上在继承和使用方面可以说是目前efcore生态下最最最完美的了真正做到了三零的框架:零依赖,零学习成本,零业务代码入侵

    最后放一张图

    是我这边给ShardingSphere提的建议,也证实了我对该聚合模型的优化是可以有效解决在分页下面聚合各数据库节点下的内存使用情况
    81abea9eb35a54d5bddab875ace07506.png

    分表分库组件求赞求star

    您的支持是开源作者能坚持下去的最大动力

    • Github ShardingCore: https://github.com/xuejmnet/sharding-core

    • Gitee ShardingCore: https://gitee.com/dotnetchina/sharding-core 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/294493.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHP 学习1.1

1 链接mysql 数据简单测试 <html><head> <title></title> <meta http-equiv"Content-Type" content"text/html; charsetutf-8" /></head><body><?php $mysqli new mysqli(); $mysqli->connect(&quo…

php 利用http上传协议(表单提交上传图片 )

主要就是利用php 的 fsocketopen 消息传输。 这里先通过upload.html 文件提交&#xff0c;利用chrome抓包&#xff0c;可以看到几个关键的信息。 首先指定了表单类型为multipart/form-data;。 boundary是分隔符 因为上传文件不在使用原有的http协议了。请求内容不再可能以 x…

Nginx Unit 1.27.0 发布

目录 介绍 更新内容 将 HTTP 请求重定向到 HTTPS 为纯路径 URI 提供可配置的文件名 完整的更新日志 其他 平台更新 介绍 Nginx Unit 是一个动态应用服务器&#xff0c;能够与 Nginx Plus 和 Nginx 开源版并行或独立运行。Nginx Unit 支持 RESTful JSON API&#xff0c;…

java搜索string_java – 在数组列表中搜索最常见的String

我想知道如何搜索字符串的ArrayList以找到我创建的“行程”对象中最常出现的“目的地”(其中包含不同目的地的列表.)到目前为止,我有&#xff1a;public static String commonName(ArrayList itinerary){int count 0;int total 0;ArrayList names new ArrayList();Iteratori…

重新认识Docker Compose之Sidecar模式

什么是Docker Compose在微服务盛行的今天&#xff0c;我们通常是这么定义Compose的&#xff1a;对容器的统一启动和关闭的编排工具。但是我以前还是有个疑惑&#xff0c;谁会用Compose在一台服务器上部署多个服务呢&#xff1f;干脆直接用单体服务就行了&#xff01;直到我遇到…

Android面试题总结加强再加强版(四)

http://blog.csdn.net/superjunjin/article/details/7862182 1&#xff0c;双缓冲技术原理以及优缺点&#xff1a; 创建一幅后台图像&#xff0c;将每一帧画入图像&#xff0c;然后调用drawImage()方法将整个后台图像一次画到屏幕上去。 优点&#xff1a;双缓冲技术的优点在于大…

数学家看到就把持不住,高斯被它迷得神魂颠倒,2600年的数学史里的一个奇迹……...

全世界只有3.14 % 的人关注了爆炸吧知识数学的美两个字就能说清数学女神很可能是个洁癖她的苛刻就体现在公式里那每一个符号每一个数字都不允许有哪怕一点杂质如此才是她最认可的孩子因为知道了勾股定理古人们才创造了辉煌因为有了经典力学公式人类才能探索星辰大海因为掌握了质…

JSFL:导入Png图片导出swf

现在项目需要用到某种格式的swf&#xff0c;既这个swf里的舞台上原点有两个MovieClip&#xff0c;分别命名为mc1&#xff0c;mc2. mc1和mc2都是从外部导入的同一个png图片转为mc而来的。然后导出为这个png同名的swf文件&#xff0c;和png同目录。 代码如下&#xff1a; //功能&…

SQLSERVER中的自旋锁

SQLSERVER中的自旋锁 在SQLSERVER中的锁有很多&#xff0c;例如什么意向共享锁&#xff0c;排他锁&#xff0c;行&#xff0c;页锁 这些都属于LOCK 而latch比lock更轻量级&#xff0c;只在内存中存在&#xff0c;一般用来锁住数据页面&#xff0c;防止多人同时修改内存中的一个…

java语言程序设计第六章答案_Java语言程序设计(邵丽萍编著)第六章.doc

Java语言程序设计(邵丽萍编著)第六章第6章(一)判断题(1)抽象类不能实例化。 ( )(2)一个类中&#xff0c;只能拥有一个构造方法。 ( )(3)内部类都是非静态的。 ( )(4)接口中的所有方法都没有被实现。 ( )(5)实现一个接口&#xff0c;则在类中一定要实现接口中的所有方法。 ( )(6…

[改善Java代码]性能考虑,数组是首选

建议60:性能考虑,数组是首选 一、分析 数组在实际的系统开发中使用的越来越少&#xff0c;我们通常只有在阅读一些开源项目时才会看到它们的身影&#xff0c;在Java中它确实没有List、Set、Map这些集合使用起来方便&#xff0c;但是在基本类型处理方面&#xff0c;数组还是占优…

编程语言也环保?C语言领跑,Python、Perl垫底

文 | Travis出品 | OSC开源社区&#xff08;ID&#xff1a;oschina2013&#xff09;毋庸置疑&#xff0c;Python 是世界上最流行的编程语言之一&#xff0c;其被广泛运用于人工智能、数据分析、网络爬虫和 Web 开发等领域。在上个月的 TIOBE 榜单中&#xff0c;Python 一举超过…

Android最全面试题71道题 详解

http://blog.csdn.net/superjunjin/article/details/7772030 Android面试题 1. 下列哪些语句关于内存回收的说明是正确的? (b ) A、 程序员必须创建一个线程来释放内存 B、 内存回收程序负责释放无用内存 C、 内存回收程序允许程序员直接释放内存 D、 内存回收程序可以在指定…

我靠“读书笔记”闷声赚3万:那些你看不上的行业,往往最赚钱

全世界只有3.14 % 的人关注了爆炸吧知识你有没有计算过&#xff1a;你的时间&#xff0c;值多少钱&#xff1f;如果你月薪5000&#xff0c;一个月工作20天&#xff0c;每天8小时&#xff0c;那么你1小时的价值就是32元。然而&#xff0c;现在请一个打扫卫生的钟点工&#xff0c…

12月16日课程安排

12/16: 6-8PM 新主楼 D218 讲座 1) 微软亚洲研究院的研究员 分享研究经验 (韩石 研究员) 2) 互联网创新公司的研发介绍 (王京: 应用汇首席工程师, 北航 6 系校友) 微软亚洲研究院的研究员建议大家先读一下这些文章: ICSE’12 paper on StackMine – Performance D…

C#元组类型System.ValueTuple

元组功能在 C# 7.0 及更高版本中可用&#xff0c;它提供了简洁的语法&#xff0c;用于将多个数据元素分组成一个轻型数据结构。元组功能需要 System.ValueTuple 类型和相关的泛型类型&#xff08;例如 System.ValueTuple<T1,T2>&#xff09;&#xff0c;这些类型在 .NET …

Cocoapods的安装和使用

一、Cocoapods的安装 第一步&#xff1a;打开终端 第二步&#xff1a;修改ruby镜像引用 gem source --remove https://rubygems.org/ gem sources -a http://ruby.taobao.org/ 完成后用命令行查看ruby镜像是否是taobao,用命令行&#xff1a; gem sources -l 返回信息为&#xf…

JAVA软件图片浏览下载_java模拟浏览器下载图片

/** * 抓取网上的图片 * param imgSrc * param filePath */ public static void downloadImgByNet(String imgSrc,String filePath,String fileName){ try{ URL url new URL(imgSrc); URLConnection conn url.openConnection(); //设置超时间为3秒 conn.setConnectTimeout(3*…

微信企业号开发之如何建立连接

http://www.07net01.com/2014/09/167991.html 连接将使你的企业号更具价值&#xff0c;你可以使用以下三种方式&#xff0c;连接你的企业号及企业应用&#xff1a; 1、企业应用调用企业号提供的接口&#xff0c;管理或查询企业号后台所管理的资源、或给成员发送消息等&#xff…

完全颠覆你世界观的10个科学实验!从此脑洞大开

全世界只有3.14 % 的人关注了爆炸吧知识这两天超模君逛知乎时&#xff0c;发现有人提问&#xff1a;“如何让孩子学会主动”&#xff1f;孩子学会主动是很重要的&#xff0c;特别是在学习方面&#xff0c;懂得主动学习无论是在小时候还是未来都很有优势。可能很多家长都有类似的…