首页 文章 精选 留言 我的

精选列表

搜索[速度],共10004篇文章
优秀的个人博客,低调大师

提高 SharePoint 页面访问速度之SQL优化

前面两篇文章我们和大家一起讨论到了SharePoint IIS的应用池回收,W3WP进程数和重置回收等方面的优化,今天来和大家讲讲后端SQL服务器的优化。 对于SQL的优化,今天主要介绍的就是两点,CPU的优化和内存的优化。 很多同学在装好SQL之后,其实并没有对内存优化进行设置,导致SQL的内存分配很不合理,针对于SharePoint,建议设置SQL的使用内存最少为 8192 MB,最多为 20480 MB 这个临界值。 如上设置,注意,这里的配置值和运行值一定要配置两次,并且要保证其一直,否则不会生效,如果不匹配,多点击几次即可。 默认情况下,这两个值的设置是不一样的,需要我们点击配置项,点击确定保存,再输入值,点击运行项目,再点击确定。多设置几次,两个地方反复点OK,多试几次。 OK,说完内存,现在我们来说下CPU,在一个SharePoint环境里面,或者私有云环境里面,正常情况下,SQL的CPU应该至少要跑在 40% ,伴随着硬盘会有频繁的读写IO。 如果CPU占用不高,磁盘IO读写也不高,那就是SQL拖了后腿,SQL一旦拖后腿了,前端web服务器再怎么优化和牛X,用户访问也还是会很慢的。 默认情况下,SQL和IIS一样,针对每个请求,也只会有一个人员来为你服务,但是其实SQL本来是可以用很多个人员来为你服务的,用来处理你的query,但是你如果不优化它,它就会偷懒,默认只激活一个服务员为你工作。 同样在SQL实例的处理器选项中,注意下面三个值。 这里建议是128线程起,最多可以开128个线程来并发为前端提供查询服务。 并且勾选 强化SQL优先级。 最后和内存配置项一样,记得在 配置值和运行值上都多设置几次,确保相同的数值生效。 在最大工作线程这个地方,默认是0,就是只开放1个线程来进行服务,也就是说随便你又多少个查询过来,只有一个服务人员接待,后面的查询全部请排队。 OK,在修改了SQL的内存和CPU配置项之后,大家可以尝试重启一下SQL Server服务,或者直接重启服务器,效果还是很明显的。今天的讨论就到这里,欢迎大家一起共同探讨,谢谢大家!

优秀的个人博客,低调大师

“GitHub 在 Safari 上的加载速度极其缓慢”

近日有开发者向 GitHub 反馈称,他在 Safari 浏览器上访问 GitHub 越来越缓慢,已接近“不可用”状态: 渲染进程 CPU 使用率高达 100%。 上下滚动时页面显示有空白,不流畅。 搜索与其他交互功能变得极其迟钝。 PR 评论非常难操作,即便标记「Viewed」也需耗费几秒钟以上。 系统为 M4 Max 16-core + 48GB RAM,性能非常强,但 GitHub 是唯一存在问题的网站。 Chrome 表现明显更好,但在处理非常大的 PR(成千行代码)时仍会卡顿。 https://github.com/orgs/community/discussions/170758 GitHub bots 表示反馈已提交供产品团队进一步评估。在这条反馈的评论区中,多位用户也表示遇到了相同问题,包括 PR 页面完全卡死,按钮点击无响应,标记标签等操作耗时显著。 GitHub 维护者询问了用户的 Safari 版本,用户反馈多数使用 Safari 18.6 (20621.3.11.11.3)(macOS Sequoia)。有开发者称可能是 GitHub 前端最近变更的 CSS 触发了 Safari 的性能缺陷。

优秀的个人博客,低调大师

XtraBackup 8.0.33-28 prepare 速度提升 20 倍!

在这篇博文中,我们将描述 Percona XtraBackup 8.0.33-28 的改进,这显著减少了备份准备所需的时间,以便进行恢复操作。 Percona XtraBackup 中的这一改进显着缩短了新节点加入 Percona XtraDB 集群(PXC) 所需的时间。 Percona XtraDB Cluster 使用 Percona XtraBackup 在节点之间执行 SST(状态快照传输)。当一个新节点加入集群时,会从 DONOR 到 JOINER 执行 SST。 JOINER 使用 PXB 从 DONOR 流式传输数据目录。 JOINER 必须在使用它之前准备备份。 观察到,当 DONOR 拥有大量表空间(一百万个)时,JOINER 一侧的 XtraBackup 无法完成数据准备阶段(xtrabackup -prepare)。 Prepare 阶段 Percona XtraBackup 复制 InnoDB 数据文件。数据在服务器并发修改数据文件时内部不一致,因为服务器并发地修改数据文件。 Percona XtraBackup 对文件执行崩溃恢复,以再次创建一致的可用数据库。 这称为 Prepare 操作(xtrabackup -prepare)。 XtraBackup Prepare 操作分两个阶段进行: Redo Log 应用 Undo Log 应用 Redo Log 应用阶段 将 Redo Log 文件修改的更改应用于页面。 此阶段没有行或事务的概念。Redo 应用阶段不会使数据库与事务一致。服务器可以刷新或写入未提交事务的更改到 Redo Log 中。 XtraBackup 仍应用记录在 Redo Log 中的修改,并且 Redo Log 应用阶段不会撤消这些更改。为此,我们必须使用 Undo Log。 Undo Log 应用阶段 Undo Log 应用阶段(也称为回滚阶段),将读取 Undo Log 页面中的更改以撤消事务。然后它们再次应用于页面(例如,再次写入旧值),并写入磁盘。在此阶段之后,备份过程中所有未提交的事务都会被回滚。 Undo Log 记录有两种类型:INSERT Undo Log 记录和 UPDATE Undo Log 记录。 删除记录标记被视为 UPDATE UNDO Log 记录的子类型。 格式如下所示: 当服务器写入这些记录时,它不会与每个记录一起写入索引/表信息。它只将“table_id”写入作为 UNDO LOG 记录的一部分。 table_id 用于获取表架构。 从 Undo Log 记录中获取表架构和关键字段用于创建索引搜索元组(Key)。 此搜索元组(Key)用于查找要执行撤消操作的记录。 所以,给定一个 table_id,你如何获取表架构/定义? 在服务器上初始化“数据字典”(DD)引擎和 DD 缓存后,存储引擎可以请求表定义。例如,InnoDB 根据也称为“se_private_id”的 table_id 请求表定义。 与服务器不同,Percona XtraBackup 无法访问“数据字典”(DD)。初始化 DD 引擎和缓存会增加复杂性和其他服务器依赖项。XtraBackup 不会简单地像服务器一样访问表对象。 为何 Percona XtraBackup 受到数以千计的企业信赖? Percona XtraBackup 初始化 InnoDB 引擎,并需要所有目的(回滚、导出等)的“InnoDB 表对象”,也称为 dict_table_t。XtraBackup 依靠序列化字典信息(SDI)。 这是表的 JSON 表示形式。 对于 InnoDB 表空间,该信息存储在表空间内。从 8.0 开始,IBD 文件是“自描述的”;例如,表架构在 IBD 文件中可用。 让我们看一个示例表。 CREATE TABLE test.t1(a INT PRIMARY KEY, b INT); CREATE TABLE 语句在 test 目录中创建一个名为 t1.ibd 的文件。例如,mysql datadir/test/t1.ibd。 因此 t1.ibd 包含有关表结构(列、它们的类型、索引数量、索引中的列、外键等)的信息作为 SDI。 使用名为“ibd2sdi”的工具从 IBD 文件中提取 SDI。 ibd2sdi data/test/t1.ibd > t1.sdi 如您所见,表名在“dd_object:name”字段中,列信息存储在“dd_object:columns”数组中。 以往的设计(8.0.33-28 之前) XtraBackup 从每个 IBD 读取 SDI 并将 每个 IBD 中的所有表加载到缓存中作为不可驱逐的。本质上,通过将表加载为不可驱逐来禁用 LRU 缓存。 每个表保留在内存中,直到 XtraBackup 退出。 这种方法的问题: 加载不需要回滚的表。 从读取表的 SDI 页面进行不必要的 IO 操作。 加载不必要的表会增加准备所需的时间。 占用内存可能导致 OOM。 如果备份目录包含大量 表/IBD 文件,则会导致 XtraBackup Prepare 操作崩溃。 加入 PXC 集群的节点需要更多内存并花费很长时间加入集群。 为什么 XtraBackup 会将表加载为“不可驱逐”?我们可以只是将它们加载为可驱逐来解决问题吗?假设一个表被驱逐,必须再次加载它。XtraBackup 将如何知道包含被驱逐表的表空间(IBD)?它必须再次扫描每个 IBD 才能找到被驱逐的表。 新的设计(8.0.33-28 开始) 为了将表加载为可驱逐的,必须建立 table_id 和包含表的表空间 space_id 之间的关系。它是通过扫描数据字典表 mysql.indexes 和 mysql.index_partitions 的 B 树页面完成的。 建立此 table_id→space_id 关系后,它将在事务回滚期间使用。在这种新设计中,只有在它们上面有事务回滚时,才会加载用户表。 新设计如下: 当达到缓存大小限制或由后台主线程时,缓存中的表将被逐出。 新设计的好处(xtrabackup -prepare): 使用更少的内存 使用更少的 IO 更快的准备 即使有大量表也能成功完成 节点更快地完成 SST 过程并快速加入 PXC 集群 节点需要更少的内存才能加入 PXC 集群 压测 在其他大小的备份目录上对 xtrabackup -prepare 进行基准测试,如 10K、50K、100K 和 250K 表。性能改进如下: 结论 正如您所见,从 Percona XtraBackup 8.0.33-28 开始,具有字典缓存的 xtrabackup -prepare 更快、更高效。 改进将取决于备份目录中的表空间文件(IBD)数量。 新节点加入 PXC 集群所需的时间也大大减少,因为 SST 过程将更快完成。 更多技术文章,请访问:https://opensource.actionsky.com/ 关于 SQLE 爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。 SQLE 获取 类型 地址 版本库 https://github.com/actiontech/sqle 文档 https://actiontech.github.io/sqle-docs/ 发布信息 https://github.com/actiontech/sqle/releases 数据审核插件开发文档 https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse

优秀的个人博客,低调大师

XtarBackup 8.0.33-28 prepare 速度提升 20 倍!

在这篇博文中,我们将描述 Percona XtraBackup 8.0.33-28 的改进,这显著减少了备份准备所需的时间,以便进行恢复操作。 Percona XtraBackup 中的这一改进显着缩短了新节点加入 Percona XtraDB 集群(PXC) 所需的时间。 Percona XtraDB Cluster 使用 Percona XtraBackup 在节点之间执行 SST(状态快照传输)。当一个新节点加入集群时,会从 DONOR 到 JOINER 执行 SST。 JOINER 使用 PXB 从 DONOR 流式传输数据目录。 JOINER 必须在使用它之前准备备份。 观察到,当 DONOR 拥有大量表空间(一百万个)时,JOINER 一侧的 XtraBackup 无法完成数据准备阶段(xtrabackup -prepare)。 Prepare 阶段 Percona XtraBackup 复制 InnoDB 数据文件。数据在服务器并发修改数据文件时内部不一致,因为服务器并发地修改数据文件。 Percona XtraBackup 对文件执行崩溃恢复,以再次创建一致的可用数据库。 这称为 Prepare 操作(xtrabackup -prepare)。 XtraBackup Prepare 操作分两个阶段进行: Redo Log 应用 Undo Log 应用 Redo Log 应用阶段 将 Redo Log 文件修改的更改应用于页面。 此阶段没有行或事务的概念。Redo 应用阶段不会使数据库与事务一致。服务器可以刷新或写入未提交事务的更改到 Redo Log 中。 XtraBackup 仍应用记录在 Redo Log 中的修改,并且 Redo Log 应用阶段不会撤消这些更改。为此,我们必须使用 Undo Log。 Undo Log 应用阶段 Undo Log 应用阶段(也称为回滚阶段),将读取 Undo Log 页面中的更改以撤消事务。然后它们再次应用于页面(例如,再次写入旧值),并写入磁盘。在此阶段之后,备份过程中所有未提交的事务都会被回滚。 Undo Log 记录有两种类型:INSERT Undo Log 记录和 UPDATE Undo Log 记录。 删除记录标记被视为 UPDATE UNDO Log 记录的子类型。 格式如下所示: 当服务器写入这些记录时,它不会与每个记录一起写入索引/表信息。它只将“table_id”写入作为 UNDO LOG 记录的一部分。 table_id 用于获取表架构。 从 Undo Log 记录中获取表架构和关键字段用于创建索引搜索元组(Key)。 此搜索元组(Key)用于查找要执行撤消操作的记录。 所以,给定一个 table_id,你如何获取表架构/定义? 在服务器上初始化“数据字典”(DD)引擎和 DD 缓存后,存储引擎可以请求表定义。例如,InnoDB 根据也称为“se_private_id”的 table_id 请求表定义。 与服务器不同,Percona XtraBackup 无法访问“数据字典”(DD)。初始化 DD 引擎和缓存会增加复杂性和其他服务器依赖项。XtraBackup 不会简单地像服务器一样访问表对象。 为何 Percona XtraBackup 受到数以千计的企业信赖? Percona XtraBackup 初始化 InnoDB 引擎,并需要所有目的(回滚、导出等)的“InnoDB 表对象”,也称为 dict_table_t。XtraBackup 依靠序列化字典信息(SDI)。 这是表的 JSON 表示形式。 对于 InnoDB 表空间,该信息存储在表空间内。从 8.0 开始,IBD 文件是“自描述的”;例如,表架构在 IBD 文件中可用。 让我们看一个示例表。 CREATE TABLE test.t1(a INT PRIMARY KEY, b INT); CREATE TABLE 语句在 test 目录中创建一个名为 t1.ibd 的文件。例如,mysql datadir/test/t1.ibd。 因此 t1.ibd 包含有关表结构(列、它们的类型、索引数量、索引中的列、外键等)的信息作为 SDI。 使用名为“ibd2sdi”的工具从 IBD 文件中提取 SDI。 ibd2sdi data/test/t1.ibd > t1.sdi 如您所见,表名在“dd_object:name”字段中,列信息存储在“dd_object:columns”数组中。 以往的设计(8.0.33-28 之前) XtraBackup 从每个 IBD 读取 SDI 并将 每个 IBD 中的所有表加载到缓存中作为不可驱逐的。本质上,通过将表加载为不可驱逐来禁用 LRU 缓存。 每个表保留在内存中,直到 XtraBackup 退出。 这种方法的问题: 加载不需要回滚的表。 从读取表的 SDI 页面进行不必要的 IO 操作。 加载不必要的表会增加准备所需的时间。 占用内存可能导致 OOM。 如果备份目录包含大量 表/IBD 文件,则会导致 XtraBackup Prepare 操作崩溃。 加入 PXC 集群的节点需要更多内存并花费很长时间加入集群。 为什么 XtraBackup 会将表加载为“不可驱逐”?我们可以只是将它们加载为可驱逐来解决问题吗?假设一个表被驱逐,必须再次加载它。XtraBackup 将如何知道包含被驱逐表的表空间(IBD)?它必须再次扫描每个 IBD 才能找到被驱逐的表。 新的设计(8.0.33-28 开始) 为了将表加载为可驱逐的,必须建立 table_id 和包含表的表空间 space_id 之间的关系。它是通过扫描数据字典表 mysql.indexes 和 mysql.index_partitions 的 B 树页面完成的。 建立此 table_id→space_id 关系后,它将在事务回滚期间使用。在这种新设计中,只有在它们上面有事务回滚时,才会加载用户表。 新设计如下: 当达到缓存大小限制或由后台主线程时,缓存中的表将被逐出。 新设计的好处(xtrabackup -prepare): 使用更少的内存 使用更少的 IO 更快的准备 即使有大量表也能成功完成 节点更快地完成 SST 过程并快速加入 PXC 集群 节点需要更少的内存才能加入 PXC 集群 压测 在其他大小的备份目录上对 xtrabackup -prepare 进行基准测试,如 10K、50K、100K 和 250K 表。性能改进如下: 结论 正如您所见,从 Percona XtraBackup 8.0.33-28 开始,具有字典缓存的 xtrabackup -prepare 更快、更高效。 改进将取决于备份目录中的表空间文件(IBD)数量。 新节点加入 PXC 集群所需的时间也大大减少,因为 SST 过程将更快完成。 更多技术文章,请访问:https://opensource.actionsky.com/ 关于 SQLE 爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。 SQLE 获取 类型 地址 版本库 https://github.com/actiontech/sqle 文档 https://actiontech.github.io/sqle-docs/ 发布信息 https://github.com/actiontech/sqle/releases 数据审核插件开发文档 https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse

优秀的个人博客,低调大师

NestJS v10 发布,速度提升 20 倍

NestJS 是一个 TypeScript Node.js 框架,帮助你建立企业级高效和可扩展的 Node.js 应用程序。 近日 NestJS v10 正式发布。这个版本带来了大量的错误修复、改进和新功能。 SWC SWC(Speedy Web Compiler)是一个基于 Rust 的可扩展平台,将 SWC 与 Nest CLI 一起使用可以大大加快你的开发过程。SWC 大约比默认的 TypeScript 编译器快 20 倍。 在 NestJS v10 中,你可以通过简单地将-b swc标志传递给nest start命令来使用 SWC,如下所示: 在测试中重写模块 NestJS 10 引入了一个新功能,允许你在测试中重写模块。当你想一次性模拟整个模块而不是单独模拟每个时,这个功能特别有用。 Test.createTestingModule({ ...}) .overrideModule(LoggerModule) .useModule(LoggerTestingModule) .compile(); Redis 通配符订阅 在 NestJS v10 中,增加了对 Redis 通配符订阅的支持。这个功能允许你订阅所有符合给定模式的消息。只要你在你的微服务配置中把wildcards配置属性设置为true,如下所示: const app = await NestFactory.createMicroservice<MicroserviceOptions>( AppModule, { transport: Transport.REDIS, options: { host: 'localhost', port: 6379, wildcards: true, // 👈 THIS IS NEW }, }); CacheModule CacheModule 已经从 @nestjs/common 包中删除,现在可以将其作为一个独立的包 @nestjs/cache-manager 来使用。这一改变是为了避免在 @nestjs/common 包中出现不必要的依赖。 放弃 Node.js v12 的支持 从 NestJS 10 开始,将不再支持 Node.js v12,NestJS 10 需要 Node.js v16 或更高版本。 CLI 插件 NestJS CLI 插件现在需要 TypeScript >= v4.8,旧版本的 TypeScript 将不再被支持。 更多详情可查看:https://github.com/nestjs/nest/releases/tag/v10.0.0

优秀的个人博客,低调大师

LinkedList插入速度比ArrayList快?你确定吗?

持续坚持原创输出,点击蓝字关注我吧 作者:小傅哥博客:https://bugstack.cn ❝ 沉淀、分享、成长,让自己和他人都能有所收获!😜 ❞ 目录 一、前言 二、面试题 三、数据结构 四、源码分析 1. 初始化 2. 插入 3. 删除 4. 遍历 五、总结 一、前言 你以为考你个数据结构是要造火箭? 🚕汽车75马力就够奔跑了,那你怎么还想要2.0涡轮+9AT呢?大桥两边的护栏你每次走的时候都会去摸吗?那怎么没有护栏的大桥你不敢上呢? 很多时候,你额外的能力才是自身价值的体现,不要以为你的能力就只是做个业务开发每天CRUD,并不是产品让你写CRUD,而是因为你的能力只能产品功能设计成CRUD。 就像数据结构、算法逻辑、源码技能,它都是可以为你的业务开发赋能的,也是写出更好、更易扩展程序的根基,所以学好这份知识非常有必要。 本文涉及了较多的代码和实践验证图稿,欢迎关注公众号:bugstack虫洞栈,回复下载得到一个链接打开后,找到ID:19🤫获取! 二、面试题 谢飞机,ArrayList资料看了吧?嗯,那行问问你哈🦀 「问」:ArrayList和LinkedList,都用在什么场景呢? 「答」:啊,这我知道了。ArrayList是基于数组实现、LinkedList是基于双向链表实现,所以基于数据结构的不同,遍历和查找多的情况下用ArrayList、插入和删除频繁的情况下用LinkedList。 「问」:嗯,那LinkedList的插入效率一定比ArrayList好吗? 「答」:对,好! 送你个飞机✈,回去等消息吧! 其实,飞机回答的也不是不对,只是不全面。出门后不甘心买瓶肥宅水又回来,跟面试官聊了2个点,要到了两张图,如下; 小傅哥 bugstack.cn & ArrayList头插、尾插、中间 小傅哥 bugstack.cn & LinkedList头插、尾插、中间 如图,分别是;10万、100万、1000万,数据在两种集合下不同位置的插入效果,「所以:」,不能说LinkedList插入就快,ArrayList插入就慢,还需要看具体的操作情况。 接下来我们带着数据结构和源码,具体分析下。 三、数据结构 Linked + List = 链表 + 列表 = LinkedList = 链表列表 小傅哥 bugstack.cn & LinkedList数据结构 LinkedList,是基于链表实现,由双向链条next、prev,把数据节点穿插起来。所以,在插入数据时,是不需要像我们上一章节介绍的ArrayList那样,扩容数组。 但,又不能说所有的插入都是高效,比如中间区域插入,他还需要遍历元素找到插入位置。具体的细节,我们在下文的源码分析中进行讲解,也帮谢飞机扫除疑惑。 四、源码分析 1. 初始化 与ArrayList不同,LinkedList初始化不需要创建数组,因为它是一个链表结构。而且也没有传给构造函数初始化多少个空间的入参,例如这样是不可以的,如下; 「但是」,构造函数一样提供了和ArrayList一些相同的方式,来初始化入参,如下这四种方式; @Testpublicvoidtest_init(){//初始化方式;普通方式LinkedList<String>list01=newLinkedList<String>();list01.add("a");list01.add("b");list01.add("c");System.out.println(list01);//初始化方式;Arrays.asListLinkedList<String>list02=newLinkedList<String>(Arrays.asList("a","b","c"));System.out.println(list02);//初始化方式;内部类LinkedList<String>list03=newLinkedList<String>()\\{{add("a");add("b");add("c");}\\};System.out.println(list03);//初始化方式;Collections.nCopiesLinkedList<Integer>list04=newLinkedList<Integer>(Collections.nCopies(10,0));System.out.println(list04);}//测试结果[a,b,c][a,b,c][a,b,c][0,0,0,0,0,0,0,0,0,0]Processfinishedwithexitcode0 这些方式都可以初始化操作,按需选择即可。 2. 插入 LinkedList的插入方法比较多,List中接口中默认提供的是add,也可以指定位置插入。但在LinkedList中还提供了头插addFirst和尾插addLast。 关于插入这部分就会讲到为什么;有的时候LinkedList插入更耗时、有的时候ArrayList插入更好。 2.1 头插 先来看一张数据结构对比图,回顾下ArrayList的插入也和LinkedList插入做下对比,如下; 小傅哥 bugstack.cn & 插入对比 看上图我们可以分析出几点; ArrayList 头插时,需要把数组元素通过 Arrays.copyOf的方式把数组元素移位,如果容量不足还需要扩容。 LinkedList 头插时,则不需要考虑扩容以及移位问题,直接把元素定位到首位,接点链条链接上即可。 2.1.1 源码 这里我们再对照下LinkedList头插的源码,如下; privatevoidlinkFirst(Ee){finalNode<E>f=first;finalNode<E>newNode=newNode<>(null,e,f);first=newNode;if(f==null)last=newNode;elsef.prev=newNode;size++;modCount++;} first,首节点会一直被记录,这样就非常方便头插。 插入时候会创建新的节点元素, new Node<>(null, e, f),紧接着把新的头元素赋值给first。 之后判断f节点是否存在,不存在则把头插节点作为最后一个节点、存在则用f节点的上一个链条prev链接。 最后记录size大小、和元素数量modCount。 modCount用在遍历时做校验,modCount != expectedModCount 2.1.2 验证 「ArrayList、LinkeList,头插源码验证」 @Testpublicvoidtest_ArrayList_addFirst(){ArrayList<Integer>list=newArrayList<Integer>();longstartTime=System.currentTimeMillis();for(inti=0;i<10000000;i++){list.add(0,i);}System.out.println("耗时:"+(System.currentTimeMillis()-startTime));}@Testpublicvoidtest_LinkedList_addFirst(){LinkedList<Integer>list=newLinkedList<Integer>();longstartTime=System.currentTimeMillis();for(inti=0;i<10000000;i++){list.addFirst(i);}System.out.println("耗时:"+(System.currentTimeMillis()-startTime));} 「比对结果:」 这里我们分别验证,10万、100万、1000万的数据量,在头插时的一个耗时情况。 如我们数据结构对比图中一样,ArrayList需要做大量的位移和复制操作,而LinkedList的优势就体现出来了,耗时只是实例化一个对象。 2.2 尾插 先来看一张数据结构对比图,回顾下ArrayList的插入也和LinkedList插入做下对比,如下; 小傅哥 bugstack.cn & 插入对比 看上图我们可以分析出几点; ArrayList 尾插时,是不需要数据位移的,比较耗时的是数据的扩容时,需要拷贝迁移。 LinkedList 尾插时,与头插相比耗时点会在对象的实例化上。 2.2.1 源码 这里我们再对照下LinkedList尾插的源码,如下; voidlinkLast(Ee){finalNode<E>l=last;finalNode<E>newNode=newNode<>(l,e,null);last=newNode;if(l==null)first=newNode;elsel.next=newNode;size++;modCount++;} 与头插代码相比几乎没有什么区别,只是first换成last 耗时点只是在创建节点上, Node<E> 2.2.2 验证 「ArrayList、LinkeList,尾插源码验证」 @Testpublicvoidtest_ArrayList_addLast(){ArrayList<Integer>list=newArrayList<Integer>();longstartTime=System.currentTimeMillis();for(inti=0;i<10000000;i++){list.add(i);}System.out.println("耗时:"+(System.currentTimeMillis()-startTime));}@Testpublicvoidtest_LinkedList_addLast(){LinkedList<Integer>list=newLinkedList<Integer>();longstartTime=System.currentTimeMillis();for(inti=0;i<1000000;i++){list.addLast(i);}System.out.println("耗时:"+(System.currentTimeMillis()-startTime));} 「比对结果:」 这里我们分别验证,10万、100万、1000万的数据量,在尾插时的一个耗时情况。 如我们数据结构对比图中一样,ArrayList 不需要做位移拷贝也就不那么耗时了,而LinkedList则需要创建大量的对象。 所以这里ArrayList尾插的效果更好一些。 2.3 中间插 先来看一张数据结构对比图,回顾下ArrayList的插入也和LinkedList插入做下对比,如下; 看上图我们可以分析出几点; ArrayList 中间插入,首先我们知道他的定位时间复杂度是O(1),比较耗时的点在于数据迁移和容量不足的时候扩容。 LinkedList 中间插入,链表的数据实际插入时候并不会怎么耗时,但是它定位的元素的时间复杂度是O(n),所以这部分以及元素的实例化比较耗时。 2.3.1 源码 这里看下LinkedList指定位置插入的源码; 「使用add(位置、元素)方法插入:」 publicvoidadd(intindex,Eelement){checkPositionIndex(index);if(index==size)linkLast(element);elselinkBefore(element,node(index));} 「位置定位node(index):」 Node<E>node(intindex){//assertisElementIndex(index);if(index<(size>>1)){Node<E>x=first;for(inti=0;i<index;i++)x=x.next;returnx;}else{Node<E>x=last;for(inti=size-1;i>index;i--)x=x.prev;returnx;}} size >> 1,这部分的代码判断元素位置在左半区间,还是右半区间,在进行循环查找。 「执行插入:」 voidlinkBefore(Ee,Node<E>succ){//assertsucc!=null;finalNode<E>pred=succ.prev;finalNode<E>newNode=newNode<>(pred,e,succ);succ.prev=newNode;if(pred==null)first=newNode;elsepred.next=newNode;size++;modCount++;} 找到指定位置插入的过程就比较简单了,与头插、尾插,相差不大。 整个过程可以看到,插入中比较耗时的点会在遍历寻找插入位置上。 2.3.2 验证 「ArrayList、LinkeList,中间插入源码验证」 @Testpublicvoidtest_ArrayList_addCenter(){ArrayList<Integer>list=newArrayList<Integer>();longstartTime=System.currentTimeMillis();for(inti=0;i<10000000;i++){list.add(list.size()>>1,i);}System.out.println("耗时:"+(System.currentTimeMillis()-startTime));}@Testpublicvoidtest_LinkedList_addCenter(){LinkedList<Integer>list=newLinkedList<Integer>();longstartTime=System.currentTimeMillis();for(inti=0;i<1000000;i++){list.add(list.size()>>1,i);}System.out.println("耗时:"+(System.currentTimeMillis()-startTime));} 「比对结果:」 这里我们分别验证,10万、100万、1000万的数据量,在中间插时的一个耗时情况。 可以看到Linkedlist在中间插入时,遍历寻找位置还是非常耗时了。所以不同的情况下,需要选择不同的List集合做业务。 3. 删除 讲了这么多插入的操作后,删除的知识点就很好理解了。与ArrayList不同,删除不需要拷贝元素,LinkedList是找到元素位置,把元素前后链连接上。基本如下图; 确定出要删除的元素x,把前后的链接进行替换。 如果是删除首尾元素,操作起来会更加容易,这也就是为什么说插入和删除快。但中间位置删除,需要遍历找到对应位置。 3.1 删除操作方法 序号 方法 描述 1 list.remove(); 与removeFirst()一致 2 list.remove(1); 删除Idx=1的位置元素节点,需要遍历定位 3 list.remove("a"); 删除元素="a"的节点,需要遍历定位 4 list.removeFirst(); 删除首位节点 5 list.removeLast(); 删除结尾节点 6 list.removeAll(Arrays.asList("a", "b")); 按照集合批量删除,底层是Iterator删除 「源码:」 @Testpublicvoidtest_remove(){LinkedList<String>list=newLinkedList<String>();list.add("a");list.add("b");list.add("c");list.remove();list.remove(1);list.remove("a");list.removeFirst();list.removeLast();list.removeAll(Arrays.asList("a","b"));} 3.2 源码 删除操作的源码都差不多,分为删除首尾节点与其他节点时候,对节点的解链操作。这里我们举例一个删除其他位置的源码进行学习,如下; 「list.remove("a");」 publicbooleanremove(Objecto){if(o==null){for(Node<E>x=first;x!=null;x=x.next){if(x.item==null){unlink(x);returntrue;}}}else{for(Node<E>x=first;x!=null;x=x.next){if(o.equals(x.item)){unlink(x);returntrue;}}}returnfalse;} 这一部分是元素定位,和 unlink(x)解链。循环查找对应的元素,这部分没有什么难点。 「unlink(x)解链」 Eunlink(Node<E>x){//assertx!=null;finalEelement=x.item;finalNode<E>next=x.next;finalNode<E>prev=x.prev;if(prev==null){first=next;}else{prev.next=next;x.prev=null;}if(next==null){last=prev;}else{next.prev=prev;x.next=null;}x.item=null;size--;modCount++;returnelement;} 这部分源码主要有以下几个知识点; 获取待删除节点的信息;元素item、元素下一个节点next、元素上一个节点prev。 如果上个节点为空则把待删除元素的下一个节点赋值给首节点,否则把待删除节点的下一个节点,赋值给待删除节点的上一个节点的子节点。 同样待删除节点的下一个节点next,也执行2步骤同样操作。 最后是把删除节点设置为null,并扣减size和modeCount数量。 4. 遍历 接下来说下遍历,ArrayList与LinkedList的遍历都是通用的,基本包括5种方式。 这里我们先初始化出待遍历的集合1千万数据; intxx=0;@Beforepublicvoidinit(){for(inti=0;i<10000000;i++){list.add(i);}} 4.1 普通for循环 @Testpublicvoidtest_LinkedList_for0(){longstartTime=System.currentTimeMillis();for(inti=0;i<list.size();i++){xx+=list.get(i);}System.out.println("耗时:"+(System.currentTimeMillis()-startTime));} 4.2 增强for循环 @Testpublicvoidtest_LinkedList_for1(){longstartTime=System.currentTimeMillis();for(Integeritr:list){xx+=itr;}System.out.println("耗时:"+(System.currentTimeMillis()-startTime));} 4.3 Iterator遍历 @Testpublicvoidtest_LinkedList_Iterator(){longstartTime=System.currentTimeMillis();Iterator<Integer>iterator=list.iterator();while(iterator.hasNext()){Integernext=iterator.next();xx+=next;}System.out.println("耗时:"+(System.currentTimeMillis()-startTime))} 4.4 forEach循环 @Testpublicvoidtest_LinkedList_forEach(){longstartTime=System.currentTimeMillis();list.forEach(integer->{xx+=integer;});System.out.println("耗时:"+(System.currentTimeMillis()-startTime));} 4.5 stream(流) @Testpublicvoidtest_LinkedList_stream(){longstartTime=System.currentTimeMillis();list.stream().forEach(integer->{xx+=integer;});System.out.println("耗时:"+(System.currentTimeMillis()-startTime));} 「那么」,以上这5种遍历方式谁最慢呢?按照我们的源码学习分析下吧,欢迎留下你的答案在评论区! 五、总结 ArrayList与LinkedList都有自己的使用场景,如果你不能很好的确定,那么就使用ArrayList。但如果你能确定你会在集合的首位有大量的插入、删除以及获取操作,那么可以使用LinkedList,因为它都有相应的方法; addFirst、 addLast、 removeFirst、 removeLast、 getFirst、 getLast,这些操作的时间复杂度都是O(1),非常高效。 LinkedList的链表结构不一定会比ArrayList节省空间,首先它所占用的内存不是连续的,其次他还需要大量的实例化对象创造节点。虽然不一定节省空间,但链表结构也是非常优秀的数据结构,它能在你的程序设计中起着非常优秀的作用,例如可视化的链路追踪图,就是需要链表结构,并需要每个节点自旋一次,用于串联业务。 程序的精髓往往就是数据结构的设计,这能为你的程序开发提供出非常高的效率改变。可能目前你还不能用到,但万一有一天你需要去造🚀火箭了呢? bugstack虫洞栈 沉淀、分享、成长,让自己和他人都能有所收获! 作者小傅哥多年从事一线互联网Java开发,从19年开始编写工作和学习历程的技术汇总,旨在为大家提供一个较清晰详细的核心技能学习文档。如果本文能为您提供帮助,请给予支持(关注、点赞、分享)! 感谢支持小傅哥原创,欢迎点击在看和转发 本文分享自微信公众号 - bugstack虫洞栈(bugstack)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

Dubbo 远程代码执行漏洞通告,速度升级

云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 0x01 漏洞背景 2020年06月23日, 360CERT监测发现 Apache Dubbo 官方 发布了 Apache Dubbo 远程代码执行的风险通告,该漏洞编号为 CVE-2020-1948,漏洞等级:高危。 Apache Dubbo 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。 Apache Dubbo Provider 存在反序列化漏洞,攻击者可以通过RPC请求发送无法识别的服务名称或方法名称以及一些恶意参数有效载荷,当恶意参数被反序列化时,可以造成远程代码执行。该漏洞的相关技术细节已公开。 对此,360CERT建议广大用户及时安装最新补丁,做好资产自查以及预防工作,以免遭受黑客攻击。 0x02 风险等级 360CERT对该漏洞的评定结果如下 0x03 漏洞详情 Apache Dubbo Provider 存在反序列化漏洞,攻击者可以通过RPC请求发送无法识别的服务名称或方法名称以及一些恶意参数有效载荷,当恶意参数被反序列化时,可以造成远程代码执行。 0x04 影响版本 Dubbo 2.7.0 – 2.7.6Dubbo 2.6.0 – 2.6.7Dubbo 2.5.x (官方不再维护) 0x05 修复建议 通用修补建议:建议广大用户及时升级到2.7.7或更高版本,下载地址为:https://github.com/apache/dubbo/releases/tag/dubbo-2.7.7 0x06 相关空间测绘数据 360安全大脑-Quake网络空间测绘系统通过对全网资产测绘,发现Dubbo在国内均有广泛使用,具体分布如下图所示。 0x07 时间线 2020-06-22 Apache Dubbo 官方发布通告2020-06-23 360CERT发布预警 【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/zhibo 立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK 原文发布时间:2020-07-05本文作者:安全客本文来自:“互联网架构师”,了解相关信息可以关注“互联网架构师”

优秀的个人博客,低调大师

PostgreSQL 数据库内外查询速度比较

数据库内使用 Rust 编写存储过程,使用pgxr程序库; 数据库外使用 Go 语言,使用pgx连接数据库进行查询; 逻辑都是查询某个表的字段列表,循环执行10000次; 测试结果如下: Rust 存储过程: test_sql_speed: 26.810285862s Go 连接数据库查询: 32.746561715s Go 语言只建立一次连接。 看来复用连接的话开销很小的嘛,一次只需要花费 0.5 毫秒左右。 然后,又测试了最简单的 SQL 查询:SELECT 1,同样也是 10000 次; 这次,Rust 存储过程: test_sql_speed: 67.651917ms Go 连接数据库查询: 1.261617769s 数据库内查询那是相当快的,这样算来每次处理连接的耗时大概在 0.1 毫秒左右。 源代码如下: Rust #[no_mangle] pub extern "C" fn test_sql_speed(_fcinfo: FunctionCallInfo) -> Datum { let sys_time = SystemTime::now(); for _ in 1..10000 { let _i = query_for_int("select 1"); } let difference = SystemTime::now().duration_since(sys_time) .expect("SystemTime::duration_since failed"); eprintln!("test_sql_speed: {:?}", difference); PG_RETURN_I32(1) } Go func main() { db := openDbConnection() start := time.Now() i := 0 for i = 1; i <= 10000; i++ { db.Query(`SELECT 1`) } t := time.Now() elapsed := t.Sub(start) fmt.Printf("%v\n", elapsed) } 后来发现用于查询表字段的方法效率不行,是从 information_schema 这个 ANSI 标准目录里去查的,后来看了一些资料,改成从 pg_catalog 这个原生目录去查,结果性能有了大幅提升。 Rust 里查询一万次只用了 1 秒,Go 里查询一万次用了 3 秒。

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。