首页 文章 精选 留言 我的

精选列表

搜索[安全加速 SCDN],共10000篇文章
优秀的个人博客,低调大师

Apache Kyuubi 在爱奇艺的时间:加速 Hive SQL 迁移 Spark

Hive 作为爱奇艺数仓的基础,Hive SQL 是爱奇艺大数据平台目前主要的数处理工具,各个业务积累大量的 Hive ETL 任务。Spark 相对于 MapReduce 有着更为灵活的的计算模型,这使得 Spark 相对于 Hive (on MapReduce) 有更好的性能。 经过测试对比,我们发现迁移 Hive SQL 到 Spark 将会带来很大的性能提升和资源节省。 Apache Kyuubi (Incubating) 项目提供一个分布式多租户的 Spark Thrift Server,相对于 Spark 原生的 Spark Thrift Server 有更好的架构优势和更多优秀的特性,具体对比可参考:Kyuubi v.s. Spark Thrift JDBC/ODBC Server (STS)。 HiveSQL 迁移Spark 1.1双跑对比 大数据平台中已有大量稳定运行的 Hive SQL 任务,为了在迁移的过程中提高用户迁移意愿,降低与用户的沟通成本,我们需要保证迁移后 Spark SQL 的稳定性以及数据准确性,并尽量减少用户操作。 我们在大数据平台中新增了 Hive SQL 迁移服务,提供一键批量双跑测试和一键迁移功能。在迁移前, 我们会对业务的 Hive SQL 任务进行批量双跑测试。改写业务 SQL 将输出替换成临时库表,并分别通过 Hive SQL 和 Spark SQL 执行。 执行完成后,对 Hive SQL 和 Spark SQL 的执行结果进行校验,确保迁移后数据一致。对每行数据进行concat后计算crc32并求和得到 checksum 值,通过对比两个结果表的 checksum 值和 count 数,来确定数据是否一致。 select sum(cast(CRC32(concat(*)) as decimal(19,0))) as checksum, count(*) as count from mock_db.mock_table 通过双跑测试,我们能够提前发现 Hive SQL 与 Spark SQL 的一些兼容性问题,以及配置不合理导致任 务失败的问题。及时优化平台配置,指导用户优化 SQL 并为任务提供合适的配置。 1.2 兼容性适配 Hive SQL 迁移到 Spark 的过程中,我们遇到了一些语法兼容性的问题,例如: Spark 删除不存在分区报错,而 Hive 中允许删除不存在分区 Spark 执行set mapreduce.job.reduces=-1报错 数字类型与字符串比较,结果与 Hive 不一致 ..... 为了加快迁移的进度,减少用户参与,我们需要兼容部分 Hive 语法。 在 Kyuubi 中提供 kyuubi-extension-spark 模块,维护 Spark SQL的 Extensions,用于优化Spark SQL的执行计划,社区已经提供了很多优化,详细文档:Auxiliary SQL extension for Spark SQL 。我们基于此模块,为不兼容的语法修改其执行计划,使得与 Hive 保持一致的语义。 例如,在 Hive 中由于默认的hive.exec.drop.ignorenonexistent=true配置,在删除不存在的表或分区时不会报错,但是迁移到 Spark 运行后,出现大量删除不存在分区的错误。我们在Kyuubi中实现了 DropIgnoreNonexistent 优化,改写AlterTableDropPartitionCommand/DropTableCommand等命令的执行计划,将ifExists属性设置为true,从而在删除不存在分区时不报错。 Kyuubi提供了只解释SQL执行计划的运行模式,通过 kyuubi.operation.plan.only.mode 配置,可以以 PARSE/ANALYZE/OPTIMIZE/PHYSICAL/EXECUTION的一些模式解释 SQL 的执行计划而不执行它,这样我们可以快速扫描出有语法兼容问题的一些 SQL。 1.3 小文件优化 Hive SQL 迁移 Spark 运行不可避免地会出现小文件的问题。我们使用 Kyuubi 的 Spark Extensions 结合 Spark AQE 可以有效地控制小文件问题。 Kyuubi Spark Extensions 中提供了RepartitionBeforeWrite的优化,在写入前插入repartition操作,再结合 AQE 合并小分区,从而实现控制小文件。 对于写入动态分区的情况,Kyuubi 中 Repartition 操作指定了动态分区字段,这样可以减小动态分区导致的小文件。如果动态分区数据分布不均匀,可能导致部分分区数据倾斜,所以对于动态分区写入 Kyuubi 在 Repartition 时,同时加入了一个随机数字段来避免数据倾斜。不过这样由于扩展了分区字段 的基数,也可能会导致小文件问题。 在spark-defaults.conf中添加相关的配置: spark.sql.extensions org.apache.kyuubi.sql.xyuubiSparksQ1Extension # Kyuubi # spark.sql.optimizer.insertmepartitionneforewrite.enabled true # AQE spark.sql.adaptive.enabled true spark.sql.adaptive.advisoryPartitionSizexnaytes 1024m spark. sql .adaptive. coal esceParti ti on s .mi nmarti ti onmum 1 对于 Spark3.2,Kyuubi 通过在写入前插入 Rebalance 算子,更好地解决小文件的问题。 Kyuubi 服务增强 2.1 标签化配置 对于不同用户和业务的 SQL,由于数据量和业务处理逻辑存在差异,可能需要对不同的任务进行单独的 配置优化。我们在数据开发平台上提供了用户配置参数的能力,允许用户对 SQL 任务添加配置。 对于同一用户或者业务会存在一些具有相同的特效的一些 SQL,我们提供标签化配置,定义一些标签绑定特有的配置,并在任务提交时带上相关的标签。 例如,我们定义的部分标签如下: Adhoc:用于即席查询平台任务,数据量小,要求快速响应。配置 USER 共享级别的引擎,较大 Driver 内存,以及 Spark 任务抢占策略等。 Batch:用于数据开发平台任务,定时调度运行,稳定要求较高。配置 CONNECTION 级别独立引 擎,使得任务完全资源隔离,并添加小文件、AQE 等优化配置。 User/Business/Custom:允许定义用户、业务或其他自定义标签,绑定特有的一些配置,如:队列、资源、兼容性适配相关配置等,降低用户使用门槛。 Kyuubi 中已经支持了对用户添加默认配置,例如在配置文件中添加 \_\_\_bob\_\_\_.spark.executor.memory=8g 配置,为 bob 用户的任务默认指定 8G 的 executor 内存,具体使用参考:User Default 。 同时,在Kyuubi 的kyuubi-server-plugin中,提供了SessionConfAdvisor接口,用于为 Session 注入配置。可以将标签配置保存在数据库中,并实现SessionConfAdvisor接口,根据 Session 配置 的标签从数据库中获取对应的配置。 2.2 SQL 审计 Kyuubi 服务中定义了一些事件,可用于 SQL 审计操作。 Kyuubi Server 中定义了如下事件: KyuubiServerInfoEvent:Kyuubi Server 启动、停止事件信息 KyuubiSessionEvent:Session 开启、关闭事件,以及连接相关信息 KyuubiOperationEvent:Kyuubi Operation 执行事件,包括了 SQL 执行相关信息 目前 Kyuubi 仅实现了 JSON 写入本地文件的方式采集事件,相关配置: 将事件写入 JSON 文件后,可以借助日志收集插件采集到 Kakfa 中并落地到 ElasticSearch 中,方便后续 对 SQL 执行事件进行审计分析。 我们在 Kyuubi Server 中通过实现自定义的EventHandler,处理 Kyuubi Server 的事件,直接将事件写入到 ElasticSearch 中。分析失败 SQL 执行事件的错误信息,完善 Spark SQL 运维知识库,并添加正则匹配分析规则,匹配执行事件的错误信息给出对应的解决方案,方便用户自行排障。 文中文档可参考: Kyuubi v.s. Spark Thrift JDBC/ODBC Server (STS)——https://kyuubi.apache.org/docs/latest/overview/kyuubi_vs_thriftserver.html Auxiliary SQL extension for Spark SQL—— https://kyuubi.apache.org/docs/latest/sql/rules.html# DropIgnoreNonexistent——https://github.com/apache/incubator-kyuubi/blob/master/extensions/spark/kyuubi-extension-spark-3-1/src/main/scala/org/apache/kyuubi/sql/DropIgnoreNonexistent.scala User Defaults—— https://kyuubi.apache.org/docs/latest/deployment/settings.html#user-defaults

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

Spring Boot中使用@Async实现异步调用,加速任务的执行!

什么是“异步调用”?“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。 同步调用 下面通过一个简单示例来直观的理解什么是同步调用: 定义Task类,创建三个处理函数分别模拟三个执行任务的操作,操作消耗时间随机取(10秒内) @Slf4j @Component public class AsyncTasks { public static Random random = new Random(); public void doTaskOne() throws Exception { log.info("开始做任务一"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); log.info("完成任务一,耗时:" + (end - start) + "毫秒"); } public void doTaskTwo() throws Exception { log.info("开始做任务二"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); log.info("完成任务二,耗时:" + (end - start) + "毫秒"); } public void doTaskThree() throws Exception { log.info("开始做任务三"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); log.info("完成任务三,耗时:" + (end - start) + "毫秒"); } } 在单元测试用例中,注入Task对象,并在测试用例中执行doTaskOne、doTaskTwo、doTaskThree三个函数。 @Slf4j @SpringBootTest public class Chapter75ApplicationTests { @Autowired private AsyncTasks asyncTasks; @Test public void test() throws Exception { asyncTasks.doTaskOne(); asyncTasks.doTaskTwo(); asyncTasks.doTaskThree(); } } 执行单元测试,可以看到类似如下输出: 2021-09-11 23:19:12.922 INFO 92539 --- [ main] com.didispace.chapter75.AsyncTasks : 开始做任务一 2021-09-11 23:19:17.788 INFO 92539 --- [ main] com.didispace.chapter75.AsyncTasks : 完成任务一,耗时:4865毫秒 2021-09-11 23:19:17.788 INFO 92539 --- [ main] com.didispace.chapter75.AsyncTasks : 开始做任务二 2021-09-11 23:19:24.851 INFO 92539 --- [ main] com.didispace.chapter75.AsyncTasks : 完成任务二,耗时:7063毫秒 2021-09-11 23:19:24.851 INFO 92539 --- [ main] com.didispace.chapter75.AsyncTasks : 开始做任务三 2021-09-11 23:19:26.928 INFO 92539 --- [ main] com.didispace.chapter75.AsyncTasks : 完成任务三,耗时:2076毫秒 任务一、任务二、任务三顺序的执行完了,换言之doTaskOne、doTaskTwo、doTaskThree三个函数顺序的执行完成。 异步调用 上述的同步调用虽然顺利的执行完了三个任务,但是可以看到执行时间比较长,若这三个任务本身之间不存在依赖关系,可以并发执行的话,同步调用在执行效率方面就比较差,可以考虑通过异步调用的方式来并发执行。 在Spring Boot中,我们只需要通过使用@Async注解就能简单的将原来的同步函数变为异步函数,Task类改在为如下模式: @Slf4j @Component public class AsyncTasks { public static Random random = new Random(); @Async public void doTaskOne() throws Exception { log.info("开始做任务一"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); log.info("完成任务一,耗时:" + (end - start) + "毫秒"); } @Async public void doTaskTwo() throws Exception { log.info("开始做任务二"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); log.info("完成任务二,耗时:" + (end - start) + "毫秒"); } @Async public void doTaskThree() throws Exception { log.info("开始做任务三"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); log.info("完成任务三,耗时:" + (end - start) + "毫秒"); } } 为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync,如下所示: @EnableAsync @SpringBootApplication public class Chapter75Application { public static void main(String[] args) { SpringApplication.run(Chapter75Application.class, args); } } 此时可以反复执行单元测试,您可能会遇到各种不同的结果,比如: 没有任何任务相关的输出 有部分任务相关的输出 乱序的任务相关的输出 原因是目前doTaskOne、doTaskTwo、doTaskThree三个函数的时候已经是异步执行了。主程序在异步调用之后,主程序并不会理会这三个函数是否执行完成了,由于没有其他需要执行的内容,所以程序就自动结束了,导致了不完整或是没有输出任务相关内容的情况。 注:@Async所修饰的函数不要定义为static类型,这样异步调用不会生效 异步回调 为了让doTaskOne、doTaskTwo、doTaskThree能正常结束,假设我们需要统计一下三个任务并发执行共耗时多少,这就需要等到上述三个函数都完成调动之后记录时间,并计算结果。 那么我们如何判断上述三个异步调用是否已经执行完成呢?我们需要使用CompletableFuture<T>来返回异步调用的结果,就像如下方式改造doTaskOne函数: @Async public CompletableFuture<String> doTaskOne() throws Exception { log.info("开始做任务一"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); log.info("完成任务一,耗时:" + (end - start) + "毫秒"); return CompletableFuture.completedFuture("任务一完成"); } 按照如上方式改造一下其他两个异步函数之后,下面我们改造一下测试用例,让测试在等待完成三个异步调用之后来做一些其他事情。 @Test public void test() throws Exception { long start = System.currentTimeMillis(); CompletableFuture<String> task1 = asyncTasks.doTaskOne(); CompletableFuture<String> task2 = asyncTasks.doTaskTwo(); CompletableFuture<String> task3 = asyncTasks.doTaskThree(); CompletableFuture.allOf(task1, task2, task3).join(); long end = System.currentTimeMillis(); log.info("任务全部完成,总耗时:" + (end - start) + "毫秒"); } 看看我们做了哪些改变: 在测试用例一开始记录开始时间 在调用三个异步函数的时候,返回CompletableFuture<String>类型的结果对象 通过CompletableFuture.allOf(task1, task2, task3).join()实现三个异步任务都结束之前的阻塞效果 三个任务都完成之后,根据结束时间 - 开始时间,计算出三个任务并发执行的总耗时。 执行一下上述的单元测试,可以看到如下结果: 2021-09-11 23:33:38.842 INFO 95891 --- [ task-3] com.didispace.chapter75.AsyncTasks : 开始做任务三 2021-09-11 23:33:38.842 INFO 95891 --- [ task-2] com.didispace.chapter75.AsyncTasks : 开始做任务二 2021-09-11 23:33:38.842 INFO 95891 --- [ task-1] com.didispace.chapter75.AsyncTasks : 开始做任务一 2021-09-11 23:33:45.155 INFO 95891 --- [ task-2] com.didispace.chapter75.AsyncTasks : 完成任务二,耗时:6312毫秒 2021-09-11 23:33:47.308 INFO 95891 --- [ task-3] com.didispace.chapter75.AsyncTasks : 完成任务三,耗时:8465毫秒 2021-09-11 23:33:47.403 INFO 95891 --- [ task-1] com.didispace.chapter75.AsyncTasks : 完成任务一,耗时:8560毫秒 2021-09-11 23:33:47.404 INFO 95891 --- [ main] c.d.chapter75.Chapter75ApplicationTests : 任务全部完成,总耗时:8590毫秒 可以看到,通过异步调用,让任务一、二、三并发执行,有效的减少了程序的总运行时间。本系列教程《Spring Boot 2.x基础教程》点击直达!,欢迎收藏与转发!如果学习过程中如遇困难?可以加入我们的 Spring技术交流群,参与交流与讨论,更好的学习与进步! 代码示例 本文的完整工程可以查看下面仓库中2.x目录下的chapter7-5工程: Github:https://github.com/dyc87112/SpringBoot-Learning/ Gitee:https://gitee.com/didispace/SpringBoot-Learning/ 如果您觉得本文不错,欢迎Star支持,您的关注是我坚持的动力! 欢迎关注我的公众号:程序猿DD,分享外面看不到的干货!

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

Chrome 浏览器改进书签文件夹,加速工作流程

Google 正在为 Chrome 浏览器文件夹中保存的书签开发一个新的功能,并已率先上线 Chrome Canary,Chrome 用户可以使用这个新功能在新标签组中打开一个文件夹的所有书签,在这个功能的辅助下,那些具有特定工作流程或特定使用习惯的用户可以更加快速方便的开启所需要的网页。 在目前稳定版本的 Chrome 浏览器中,当用户右键点击书签文件夹时,会显示三个打开选项(如图所示),这些选项分别是在当前窗口、在新窗口以及在隐身窗口中打开文件夹中的所有书签。 而在目前的 Chrome Canary 以及未来的 Chrome 94 版本中,Google 会为一个新的右键菜单选项 —— 在标签组中打开全部书签。 标签组是 Chrome 浏览器中一个相对较新的功能,可以让用户对开启的标签页进行分组管理。每个标签组都能设置一个名称和一个与之相关的图标,从而可以将工作、娱乐等页面进行区分,不会杂乱地排列在标签栏中。 其他基于 Chromium 的浏览器目前也都支持标签组这一功能,Chrome 反而是最晚引入该功能的浏览器,而 Chrome 的标签组功能也显得比较简单。 目前在这方面做的最好的浏览器应该就是 Vivaldi,在近期 4.1 版本的更新中,Vivaldi 新增了手风琴式的标签页风格,可选的标签页风格增加到了 3 种。除此以外,4.1 版本还加入了 Command Chains 功能,用户可以利用这个功能所提供的 200 多项浏览器操作创建一个自定义的指令,通过一个命令即可执行一系列的操作,包括但不限于开启标签页。对 Vivaldi 感兴趣的用户可以查看我们前几天出的这篇文章,了解更多详情。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册