首页 文章 精选 留言 我的

精选列表

搜索[官方产品],共10012篇文章
优秀的个人博客,低调大师

《Spark 官方文档》在YARN上运行Spark

在YARN上运行Spark 对YARN (Hadoop NextGen)的支持是从Spark-0.6.0开始的,后续的版本也一直持续在改进。 在YARN上启动 首先确保 HADOOP_CONF_DIR 或者 YARN_CONF_DIR 变量指向一个包含Hadoop集群客户端配置文件的目录。这些配置用于读写HDFS和连接YARN资源管理器(ResourceManager)。这些配置应该发布到YARN集群上所有的节点,这样所有的YARN容器才能使用同样的配置。如果这些配置引用了Java系统属性或者其他不属于YARN管理的环境变量,那么这些属性和变量也应该在Spark应用的配置中设置(包括驱动器、执行器,以及其AM【运行于client模式时的YARN Application Master】) 在YARN上启动Spark应用有两种模式。在cluster模式下,Spark驱动器(driver)在YARNApplication Master中运行(运行于集群中),因此客户端可以在Spark应用启动之后关闭退出。而client模式下,Spark驱动器在客户端进程中,这时的YARNApplication Master只用于向YARN申请资源。 与独立部署(Spark standalone)或 在Mesos集群中不同,YARN的master地址不是在–master参数中指定的,而是在Hadoop配置文件中设置。因此,这种情况下,–master只需设置为yarn。 以下用cluster模式启动一个Spark应用: $ ./bin/spark-submit --class path.to.your.Class \ --master yarn \ --deploy-mode cluster \ [options] \ <app jar> [app options] 例如: $ ./bin/spark-submit --class org.apache.spark.examples.SparkPi \ --master yarn \ --deploy-mode cluster \ --driver-memory 4g \ --executor-memory 2g \ --executor-cores 1 \ --queue thequeue \ lib/spark-examples*.jar 10 以上例子中,启动了一个YARN客户端程序,使用默认的Application Master。而后SparkPi在Application Master中的子线程中运行。客户端会周期性的把Application Master的状态信息拉取下来,并更新到控制台。客户端会在你的应用程序结束后退出。参考“调试你的应用”,这一节说明了如何查看驱动器和执行器的日志。 要以client模式启动一个spark应用,只需在上面的例子中把cluster换成client。下面这个例子就是以client模式启动spark-shell: $ ./bin/spark-shell --master yarn --deploy-mode client 增加其他JAR包 在cluster模式下,驱动器不在客户端机器上运行,所以SparkContext.addJar添加客户端本地文件就不好使了。要使客户端上本地文件能够用SparkContext.addJar来添加,可以用–jars选项: $ ./bin/spark-submit --class my.main.Class \ --master yarn \ --deploy-mode cluster \ --jars my-other-jar.jar,my-other-other-jar.jar my-main-jar.jar app_arg1 app_arg2 准备 在YARN上运行Spark需要其二进制发布包构建的时候增加YARN支持。二进制发布包可以在这里下载:downloads page。 想要自己编译,参考这里:Building Spark 配置 大多数配置,对于YARN或其他集群模式下,都是一样的。详细请参考这里:configuration page。 以下是YARN上专有的配置项。 调试你的应用 在YARN术语集中,执行器和Application Master在容器(container)中运行。YARN在一个应用程序结束后,有两种处理容器日志的模式。如果开启了日志聚合(yarn.log-aggregation-enable),那么容器日志将被复制到HDFS,并删除本地日志。而后这些日志可以在集群任何节点上用yarn logs命令查看: yarn logs -applicationId <app ID> 以上命令,将会打印出指定应用的所有日志文件的内容。你也可以直接在HDFS上查看这些日志(HDFS shell或者HDFS API)。这些目录可以在你的YARN配置中指定(yarn.nodemanager.remote-app-log-dir和yarn.nodemanager-remote-app-log-dir-suffix)。这些日志同样还可以在Spark Web UI上Executors tab页查看。当然,你需要启动Spark history server和 MapReduce history server,再在 yarn-site.xml 中配置好yarn.log.server.url。Spark history server UI 将把你重定向到MapReduce history server 以查看这些聚合日志。 如果日志聚合没有开启,那么日志文件将在每台机器上的 YARN_APP_LOGS_DIR 目录保留,通常这个目录指向 /tmp/logs 或者 $HADOOP_HOME/log/userlogs(这取决于Hadoop版本和安全方式)。查看日志的话,需要到每台机器上查看这些目录。子目录是按 application ID 和 container ID来组织的。这些日志同样可以在 Spark Web UI 上 Executors tab 页查看,而且这时你不需要运行MapReduce history server。 如果需要检查各个容器的启动环境,可以先把 yarn.nodemanager.delete.debug-delay-sec 增大(如:36000),然后访问应用缓存目录yarn.nodemanager.local-dirs,这时容器的启动目录。这里包含了启动脚本、jar包以及容器启动所用的所有环境变量。这对调试 classpath 相关问题尤其有用。(注意,启用这个需要管理员权限,并重启所有的node managers,因此,对托管集群不适用) 要自定义Application Master或执行器的 log4j 配置,有如下方法: 通过spark-submit –files 上传一个自定义的 log4j.properties 文件。 在 spark.driver.extraJavaOptions(对Spark驱动器)或者 spark.executor.extraJavaOptions(对Spark执行器)增加 -Dlog4j.configuration=<location of configuration file>。注意,如果使用文件,那么 file: 协议头必须显式写上,且文件必须在所节点上都存在。 更新${SPARK_CONF_DIR}/log4j.properties 文件以及其他配置。注意,如果在多个地方都配置了log4j,那么上面其他两种方法的配置优先级比本方法要高。 注意,第一种方法中,执行器和Application Master共享同一个log4j配置,在有些环境下(AM和执行器在同一个节点上运行)可能会有问题(例如,AM和执行器日志都写入到同一个日志文件) 如果你需要引用YARN放置日志文件的路径,以便YARN可以正确地展示和聚合日志,请在log4j.properties文件中使用spark.yarn.app.container.log.dir。例如,log4j.appender.file_appender.File=${spark.yarn.app.container.log.dir}/spark.log 。对于流式应用,可以配置RollingFileAppender,并将文件路径设置为YARN日志目录,以避免磁盘打满,而且这些日志还可以利用YARN的日志工具访问和查看。 Spark属性 Property Name Default Meaning spark.yarn.am.memory 512m YARN Application Master在client模式下, 使用内存总量,与JVM内存设置格式相同(如:512m,2g)。 如果是cluster模式下,请设置 spark.driver.memory。 注意使用小写的后缀, 如:k、m、g、t、p,分别代表 kibi-, mebi, gibi-, tebi- 以及pebibytes。 spark.driver.cores 1 YARN cluster模式下,驱动器使用的CPU core个数。 在cluster模式下,驱动器(driver)和YARN AM(application master)使用相同的JVM,所以这个属性也可以用来控制YARN AM。 如果是client模式下,请使用spark.yarn.am.cores来控制YARN AM的CPU core个数。 spark.yarn.am.cores 1 client模式下,用来控制YARN AM的CPU core个数。 cluster模式下,请使用 spark.driver.cores。 spark.yarn.am.waitTime 100s 在cluster模式下,该属性表示YARN AM等待SparkContext初始化的时间。 在client模式下,该属性表示YARN AM等待驱动器连接的时间。 spark.yarn.submit.file .replication 默认的HDFS副本数(通常是3) HDFS文件副本数。包括Spark jar,app jar以及其他分布式缓存文件和存档。 spark.yarn.preserve .staging.files false 设为true以保存stage相关文件(stage相关的jar包和缓存)到作业结束,而不是立即删除。 spark.yarn.scheduler .heartbeat.interval-ms 3000 Spark AM发送给YARN资源管理器心跳的间隔(ms)。 这个值最多不能超过YARN配置的超时间隔的一半。(yarn.am.liveness-monitor.expiry-interval-ms) spark.yarn.scheduler .initial-allocation.interval 200ms Spark AM的初始带外心跳间隔(有待定的资源申请时)。 其值不应该大于 spark.yarn.scheduler.heartbeat.interval-ms。 该资源分配间隔会在每次带外心跳成功后但仍有待定资源申请时倍增, 直至达到 spark.yarn.scheduler.heartbeat.interval-ms 所设定的值。 spark.yarn.max.executor .failures 执行器个数*2且不小于3 Spark应用最大容忍执行器失败次数。 spark.yarn.historyServer .address (none) Spark history server地址,如:host.com:18080 。 这个地址不要包含协议头(http://)。 默认不设置,因为history server是可选的。 应用程序结束以后,YARN资源管理器web UI通过这个地址链接到Spark history server UI。 对于这属性,可以使用YARN属性变量,且这些变量是Spark在运行时组装的。 例如,如果Spark history server和YARN资源管理器(ResourceManager)部署在同一台机器上运行, 那么这个属性可以设置为 ${hadoopconf-yarn.resourcemanager.hostname}:18080 spark.yarn.dist.archives (none) 逗号分隔的文档列表,其指向的文档将被提取到每个执行器的工作目录下。 spark.yarn.dist.files (none) 逗号分隔的文件列表,其指向的文件将被复制到每个执行器的工作目录下。 spark.executor.instances 2 执行器个数。注意,这个属性和 spark.dynamicAllocation.enabled是不兼容的。 如果同时设置了spark.dynamicAllocation.enabled,那么动态分配将被关闭,并使用 spark.executor.instances 所设置的值。 spark.yarn.executor .memoryOverhead 执行器内存 * 0.10或者 384MB中较大者 每个执行器所分配的堆外内存(MB)总量。这些内存将被用于存储VM开销、字符串常量,以及其他原生开销等。这会使执行器所需内存增加(典型情况,增加6%~10%) spark.yarn.driver .memoryOverhead 驱动器内存 * 0.10或者 384MB中较大者 每个驱动器所分配的堆外内存(MB)总量。 这些内存将被用于存储VM开销、字符串常量,以及其他原生开销等。 这会使执行器所需内存增加(典型情况,增加6%~10%) spark.yarn.am .memoryOverhead Application Master 内存 * 0.10或者 384MB中较大者 与 spark.yarn.driver.memoryOverhead 相同,只是仅用于YARN AM client模式下。 spark.yarn.am.port (random) YARN AM所监听的端口。 在YARN client模式下,用于Spark驱动器(driver)和YARN AM通信。 而在YARN cluster模式下,这个端口将被用于动态执行器特性,这个特性会处理调度器后台杀死执行器的请求。 spark.yarn.queue default Spark应用提交到哪个yarn队列。 spark.yarn.jar (none) Spark jar文件位置,如果需要覆盖默认位置,请设定这个值。 默认的,Spark on YARN会使用本地的Spark jar包,但Spark jar包同样可以使用整个集群可读的HDFS文件位置。 这使YARN可以在各节点上缓存Spark jar包,而不需要每次运行一个应用的时候都要分发。 使用 hdfs:///some/path 来指定HDFS上jar包文件路径。 spark.yarn.access .namenodes (none) 逗号分隔的HDFS namenodes。 例如spark.yarn.access.namenodes=hdfs://nn1.com:8032,hdfs://nn2.com:8032。 Spark应用必须有这些机器的访问权限,并且需要配置好 kerberos(可以在同一个域或者信任的域)。 Spark需要每个namenode的安全token,以便访问集群中HDFS。 spark.yarn.appMasterEnv .[EnvironmentVariableName] (none) 增加EnvironmentVariableName所指定的环境变量到YARN AM的进程中。 用户可以指定多个环境变量。在cluster模式下,这个可以控制Spark驱动器的环境变量; 而在client模式下,只控制执行器启动器的环境变量。 spark.yarn .containerLauncherMaxThreads 25 YARN AM 启动执行器的容器最多包含多少线程数。 spark.yarn.am .extraJavaOptions (none) 在client模式下,传给YARN AM 的JVM参数。 在cluster模式下,请使用spark.driver.extraJavaOptions spark.yarn.am .extraLibraryPath (none) client模式下传给YARN AM额外依赖库。 spark.yarn.maxAppAttempts yarn .resourcemanager.am.max-attemptsin YARN 提交应用最大尝试次数。不应大于YARN全局配置的最大尝试次数。 spark.yarn.am .attemptFailuresValidityInterval (none) 定义AM失败跟踪校验间隔。 AM运行了至少要运行这么多时间后,其失败计数才被重置。 这个特性只有配置其值后才会生效,且只支持Hadoop-2.6+ spark.yarn.submit .waitAppCompletion true 在YARN cluster模式下,控制是否客户端等到Spark应用结束后再退出。 如果设为true,客户端进程将一直等待,并持续报告应用状态。 否则,客户端会在提交完成后退出。 spark.yarn.am .nodeLabelExpression (none) 一个YARN节点标签表达式(node label expression),以此来限制AM可以被调度到哪些节点上执行。 只有Hadoop 2.6+才能支持节点标签表达式,所以如果用其他版本运行,这个属性将被忽略。 spark.yarn.executor .nodeLabelExpression (none) 一个YARN节点标签表达式(node label expression),以此来限制执行器可以被调度到哪些节点上启动。 只有Hadoop 2.6+才能支持节点标签表达式,所以如果在其他版本上运行时,这个属性将被忽略。 spark.yarn.tags (none) 逗号分隔的字符串,传递YARN应用tags。 其值将出现在YARN Application Reports中,可以用来过滤和查询YARN 应用。 spark.yarn.keytab (none) 认证文件keytab的全路径。 这个文件将被复制到访问Secure Distributed Cache的YARN 应用节点上,并且周期性的刷新登陆的ticket和代理token(本地模式下也能work) spark.yarn.principal (none) 登陆KDC的认证,secure HDFS需要(local模式下也能用) spark.yarn.config .gatewayPath (none) 某些路径,可能在网关主机上能正常访问(Spark应用启动的地方),而在其他节点上的访问方式(路径)可能不同。 对于这样的路径,需要本属性配合 spark.yarn.config.replacementPath组合使用,对于支持异构配置的集群,必须配置好这两个值,Spark才能正确地启动远程进程。 replacement path 通常包含一些YARN导出的环境变量(因此,对Spark containers可见)。 例如,如果网关节点上Hadoop库安装在 /disk1/hadoop,并且其导出环境变量为 HADOOP_HOME, 就需要将spark.yarn.config.gatewayPath 设置为 /disk1/hadoop 并将 replacement path设为 $HADOOP_HOME, 这样才能在远程节点上以正确的环境变量启动进程。 spark.yarn.config .replacementPath (none) 见 spark.yarn.config.getewayPath spark.yarn.security .tokens.${service}.enabled true 在启用安全设置的情况下,控制是否对non-HDFS服务,获取代理token。 默认地,所有支持的服务,都启用;但你也可以在某些有冲突的情况下,对某些服务禁用。 目前支持的服务有:hive,hbase 重要提示 对CPU资源的请求是否满足,取决于调度器如何配置和使用。 cluster模式下,Spark执行器(executor)和驱动器(driver)的local目录都由YARN配置决定(yarn.nodemanager.local-dirs);如果用户指定了spark.local.dir,这时候将被忽略。在client模式下,Spark执行器(executor)的local目录由YARN决定,而驱动器(driver)的local目录由spark.local.dir决定,因为这时候,驱动器不在YARN上运行。 选项参数 –files和 –archives中井号(#)用法类似于Hadoop。例如,你可以指定 –files localtest.txt#appSees.txt,这将会把localtest.txt文件上传到HDFS上,并重命名为 appSees.txt,而你的程序应用用 appSees.txt来引用这个文件。 当你在cluster模式下使用本地文件时,使用选项–jar 才能让SparkContext.addJar正常工作,而不必使用 HDFS,HTTP,HTTPS或者FTP上的文件。 转载自 并发编程网 - ifeve.com

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

《Spark 官方文档》在Mesos上运行Spark

在Mesos上运行Spark Spark可以在由Apache Mesos管理的硬件集群中运行。 在Mesos集群中使用Spark的主要优势有: 可以在Spark以及其他框架(frameworks)之间动态划分资源。 可以同时部署多个Spark实例,且各个实例间的资源分配可以调整。 工作原理 在独立部署的Spark集群中,下图里的Cluster Manager代表Spark master。然而,在Mesos集群中,Mesos master将取代Spark master在下图中的地位。 如果一个Spark驱动程序(driver)提交一个作业(job)并开始分发调度作业相关的任务(task),将会由Mesos来决定每个任务分发到哪台机器上。Mesos在调度短期任务的时候,会根据提交任务的账号来动态分配资源,而不需要依赖于静态的资源划分。 按以下所示的步骤,来安装Mesos,以及向Mesos提交Spark作业。 安装Mesos Spark 1.6.0使用Mesos 0.21.0的时候,不需要任何特殊的Mesos补丁包。 如果你已经有一个Mesos集群,可以忽略Mesos安装这一步。 为Spark安装的Mesos和你为其他框架安装的Mesos没有什么不同。既可以从源代码安装,也可以从预编译好的包安装。 使用源代码安装 按以下步骤可以使用源代码安装Apache Mesos: 从镜像(mirror)下载一个Mesos发布版本 按Mesos的开始页(Getting Started)所示的步骤来编译和安装Mesos 注意:如果你不想把Mesos安装到系统默认路径下(比如,你没有管理员权限),可以通过configure脚本的–prefix参数来指定安装路径,例如,configure –prefix=/home/me/mesos。默认的安装路径是/usr/local。 使用第三方包安装 Apache Mesos项目本身只发布源码包,但你可以从一些第三方项目中找到Mesos的二进制发布包,二进制包在安装时相对更方便一些。 其中一个第三方项目是Mesosphere。按以下步骤可以安装Mesosphere提供的二进制发布包: 从下载页面(downloads page)下载Mesos安装包 按页面上所提供的安装指令即可安装和配置Mesos Mesosphere的安装文档中建议使用Zookeeper来设置Mesos master的容错备份,但其实Mesos并不依赖于Zookeeper,可以以单master方式运行。 验证 接下来,需要通过浏览Mesos master的Web UI(其端口为5050)来确认一下,是否页面上slave tab显示了所有集群中的slave机器。 Spark连接Mesos 要在Mesos上运行Spark,你需要在Mesos能访问到的地方部署Spark的二进制包,并且需要配置一下Spark驱动程序(driver)以便使其可以连接到Mesos。 当然,你也可以把Spark安装到Mesos slave机器上和Mesos相同的目录下,然后配置一下spark.mesos.executor.home(默认等于${SPAKR_HOME}),使其指向这个目录。 上传Spark包 Mesos在某个slave机器上首次运行Spark任务的时候,slave机器上需要一个运行Spark Mesos executor backend的二进制包,这个Spark包可以放在任何能够以Hadoop兼容URL访问到的地方,包括HTTP(http://,Amazon Simple Storage Service)、s3n(s3n://)、HDFS (hdfs://) 要使用预编译好的二进制包: 从这里(download page)下载Spark二进制包 将Spark二进制包上传到可访问的的存储:hdfs/http/s3 要存到HDFS上,可以使用Hadoop fs put 命令:hadoop fs -put spark-1.6.0.tar.gz /path/to/spark-1.6.0.tar.gz 或者,你也可以编译一个自定义Spark版本,可以使用Spark源码中tarball/checkout下的 make-distribution.sh脚本来打包: 下载并编译Spark(参考这里here) 创建一个二进制包:make-distribution.sh –tgz 将Spark二进制包上传到可访问的存储:hdfs/http/s3 Mesos Master URL Mesos Master URL有两种形式: 单master为 mesos://host:5050 基于Zookeeper的多master为 mesos://zk://host:2181 客户端模式 客户端模式下,客户端机器上将会启动一个Spark Mesos框架,并且会等待驱动(driver)的输出。 驱动需要spark-env.sh中的一些配置项,以便和Mesos交互操作: 在Spark-env.sh中设置一些环境变量: export MESOS_NATIVE_JAVA_LIBRARY=<path to libmesos.so>。一般情况下,这个路径是 <prefix>/lib/libmesos.so,其中prefix的默认值是/usr/local。见前面的Mesos安装所述。在Mac OS X系统中,libmesos.so的名字变为libmesos.dylib。 export SPARK_EXECUTOR_URI=<上文所述的上传spark-1.6.0.tar.gz对应的URL> 同样,spark.executor.uri 也需要设成<上文所述的上传spark-1.6.0.tar.gz对应的URL> 然后,你就可以向这个Mesos集群提交Spark应用了,当然,你需要把Mesos Master URL(mesos:// )传给SparkContext,例如: val conf = new SparkConf() .setMaster("mesos://HOST:5050") .setAppName("My app") .set("spark.executor.uri", "<path to spark-1.6.0.tar.gz uploaded above>"); val sc =newSparkContext(conf); (你也可以在conf/spark-defaults.conf文件中配置spark.executor.uri,然后通过spark-submit脚本来提交Spark应用) 如果是在Spark shell中,spark.executor.uri参数值是从SPARK_EXECUTOR_URI继承而来的,所以不需要额外再传一个系统属性。 ./bin/spark-shell --master mesos://host:5050 集群模式 Mesos同样也支持Spark以集群模式提交作业,这种模式下,驱动器将在集群中某一台机器上启动,其运行结果可以在Mesos Web UI上看到。 要使用集群模式,你首先需要利用 sbin/start-mesos-dispatcher.sh脚本启动 MesosClusterDispatcher,并且将Mesos Master URL(如:mesos://host:5050)传给该脚本。MesosClusterDispatcher启动后会以后台服务的形式运行在本机。 如果你想以Marathon框架运行MesosClusterDispatcher,那么就需要在前台运行MesosClusterDispatcher(如:bin/spark-class org.apache.spark.deploy.mesos.MesosClusterDispatcher) 客户机现在可以向Mesos集群提交任务了,如下示例,你可以用spark-submit脚本,并将master URL指定为MesosClusterDispatcher的URL(如:mesos://dispatcher:7077)。然后,你可以在Spark集群Web UI上查看驱动器程序的状态。 ./bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master mesos://207.184.161.138:7077 \ --deploy-mode cluster \ --supervise \ --executor-memory 20G \ --total-executor-cores 100\ http://path/to/examples.jar \ 1000 注意,spark-submit中所涉及的jar包或python文件必须传到Mesos可以以URI形式访问到的位置,Spark驱动是不会自动上传任何本地jar包或python文件的。 Mesos运行模式 Spark可以在Mesos的两种模式下运行:“粗粒度”模式(默认)和“细粒度”模式。 “粗粒度”模式下,Mesos在每台机器上只启动一个长期运行的Spark任务,而Spark任务则会作为其内部的“mini-tasks”来动态调度。这样做的好处是,启动延迟会比较低,但同时,也会增加一定的资源消耗,因为Mesos需要在整个生命周期内为这些长期运行的Spark任务保留其所需的资源。 粗粒度是Mesos的默认模式。你也可以显示地在SparkConf中设置spark.mesos.coarse属性为true来启用该模式: conf.set("spark.mesos.coarse","true") 另外,在粗粒度模式下,你可以控制Spark所使用资源的上限。默认情况下,Spark会申请集群中所有的CPU(当然是Mesos所能提供的),这其实并不合理,除非你每次只启动一个应用。你可以通过SparkConf设置个帽子(上限),如:conf.set(“spark.cores.max”, “10) 在细粒度模式下,每个Spark任务都作为独立的Mesos任务运行。这使得多个Spark实例(或者其他计算框架)可以比较细粒度地共享机器资源,每个应用所获得的机器资源也会随着应用的启动和关闭而增加或减少,但同时每个任务的启动也会有相应的延迟。这种模式可能不适用于一些低延迟的场景,如:交互式查询,响应web请求等。 要使用细粒度模式,可以在SparkConf中将 spark.mesos.coarse 属性设为false: conf.set("spark.mesos.coarse","false") 你还可以用spark.mesos.constraints属性来设置mesos资源分配约束条件。默认是没有约束的,也就是所有的资源分配都是可接受的。 conf.set("spark.mesos.constraints","tachyon:true;us-east-1:false") 例如,我们把spark.mesos.constraints设为tachyon:true;us-east-1:false,接下来,资源分配将会检查新分配的资源(机器)是否符合这两项约束,只有符合约束的机器才会启动新的Spark执行器(executor)。 Mesos对Docker的支持 Spark可以使用Mesos Docker集装箱,你需要在SparkConf中设置spark.mesos.executor.docker.image属性。 所使用的Docker镜像必须已经包含特定的Spark版本,或者也可以使用Mesos的惯用方法下载Spark。 支持Docker需要Mesos 0.20.1及以上版本。 和Hadoop一起运行 你可以将Spark和Mesos作为机器上独立服务,和已有的Hadoop集群部署在一起。要从Spark访问Hadoop数据,需要一个完整的hdfs:// URL(通常是 hdfs://<namenode>:9000/path,你可以在Hadoop Namenode Web UI上看到这个URL)。 另外,你也可以在Mesos上运行Hadoop MapReduce,以便达到Mesos和Hadoop之间更好的资源隔离和共享。这种场景下,Mesos就是一个全局唯一的调度器,同时为Hadoop和Spark分配CPU,而不再是利用Linux调度器来共享CPU资源。更详细的请参考Hadoop on Mesos。 但是不管是上面哪种场景,HDFS始终是独立于Hadoop MapReduce的,也不需要Mesos的调度。 Mesos中的动态资源分配 Mesos在粗粒度模式下,可以支持动态分配,Mesos会基于应用的统计信息调整执行器(executor)的个数。粗粒度模式下,由于Mesos被设计成在每个slave上只启动一个执行器,所以Mesos的粗粒度调度器本身只支持减少资源分配,而动态分配同时支持减少和增加执行器的个数。所以在粗粒度调度器减少执行器个数后,如果Spark表示需要更多执行器的时候,Mesos又会重新把执行器个数提升为原值。 由于Mesos目前还不支持对其他框架作业终止的通知,所以想要使用动态分配这个特性的用户,需要开启Mesos Shuffle Service,来清理shuffle产生的临时数据。可以使用sbin/start-mesos-shuffle-service.sh 和 sbin/stop-mesos-shuffle-service.sh来启动和停止Mesos Shuffle Service。 Shuffle Service需要在每个运行Spark执行器(executor)的节点上启动。最简单的实现方式就是在Mesos上使用Marathon启动Shuffle Service,并添加一个主机唯一的限制。 配置 Spark更详细的配置可参考这里:configuration page。以下为Spark on Mesos的相应配置: Spark Properties(Spark属性) 属性名 默认值 含义 spark.mesos.coarse false 如果设为true,则运行于Mesos集群粗粒度模式下(“coarse-grained” sharing mode),这种模式下,Spark需要运行一个长期Mesos任务。这样可以有效减少小型查询的延迟,但同时也会增加整个Spark作业生命周期内对集群资源的占用。 spark.mesos.extra.cores 0 每一个task的额外CPU资源请求。仅在粗粒度模式下生效。每个task所申请的CPU个数 = 集群提供的个数 + 该配置所设定的个数。注意,执行器锁申请的总CPU个数不会超过 spark.cores.max spark.mesos.mesosExecutor.cores 1.0 每个Mesos执行器的CPU个数(仅细粒度模式有效)。这不包括用于执行Spark tasks的CPU。换句话说,即使没有任何Spark任务在运行,每个Mesos执行器也会占用这么多个CPU。注意,该值可以是一个浮点数。 spark.mesos.executor.docker.image (none) 容纳Spark执行器的docker镜像名称。这个镜像中必须包含Spark以及兼容的Mesos库。镜像中的Spark安装路径可以由spark.mesos.executor.home指定;Mesos库的安装路径可以由 spark.executor.Env.MESOS_NATIVE_JAVA_LIBRARY指定。 spark.mesos.executor.docker.volumes (none) 设置挂载到docker镜像中的卷标(docker镜像由spark.mesos.executor.docker.image设置)。该属性值为逗号分隔的卷标路径映射列表,其格式同docker run -v所需参数,如下: [host_path:]container_path[:ro|:rw] spark.mesos.executor.docker.portmaps (none) 设置docker镜像的接入端口映射列表(docker镜像由spark.mesos.executor.docker.image设置)。格式为逗号分隔的端口映射列表,如下所示: host_port:container_port[:tcp|:udp] spark.mesos.executor.home driver sideSPARK_HOME 驱动器所在节点上的${SPARK_HOME} 设置Mesos执行节点上的Spark安装目录。默认情况下,会使用驱动器(driver)所在节点的${SPARK_HOME}路径。注意,如果设置了spark.executor.uri指定Spark二进制包的位置,那么本设置将无效。 spark.mesos.executor.memoryOverhead 执行器内存 * 0.10 或384MB中较大者 每个执行器(executor)分配的额外内存总量(MB)。其默认值为 384MB或者 spark.executor.memory * 10% 二者中较大者。 spark.mesos.uris (none) 驱动器(driver)或执行器(executor)启动时下载到沙箱中的URI列表。粗粒度和细粒度模式均适用。 spark.mesos.principal (none) 设置Spark框架在Mesos集群上的认证身份。 spark.mesos.secret (none) 设置Spark框架在Mesos集群上的认证密码。 spark.mesos.role * 设置Spark框架在Mesos集群上的认证角色。角色是Mesos用于保留和分配资源的权重因子。 spark.mesos.constraints (none) 基于资源特性的资源分配约束条件。默认,所有分配的资源都是可以接受的。更详细的资源特性请参考这里:Mesos Attributes & Resources 数值型约束:使用”less than equal”语义,例如,约束中设置的值必须小于或等于分配资源的实际值。 范围型约束:使用“contains”语义,例如,约束中设置的必须包含于资源分配的实际值范围内。 集合型约束:使用“subset of”语义,例如,约束条件中设置的值必须是资源分配实际值的一个子集。 文本型约束:使用“equality”语义,例如,约束条件中的值必须精确等价月资源分配中的值。 如果资源的所有特性都没有对应的约束条件中,则该资源是可接受的(即不需要检查) 排错和调试 调试时需要关注的地方: Mesos master(端口:5050) Slave节点应该全部显示在slaves tab页上 Spark应用应该显示在frameworks tab页上 Spark任务应该显示在framework detail中 检查失败任务沙箱的标准输出和标准错误 Mesos日志 默认,master和slave的日志都保存在/var/log/mesos目录下 常见陷阱: Spark程序集不可访问 Slave机器必须能够通过你指定的http://, hdfs:// 或者 s3n:// 等URL访问并下载Spark的二进制包 防火墙阻断网络通信 检查是否有连接失败消息 临时关闭防火墙以便调试,后续再专门放开几个端口 转载自并发编程网 - ifeve.com

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

SparkSql官方文档中文翻译(java版本)

1 概述(Overview) 2 DataFrames 2.1 入口:SQLContext(Starting Point: SQLContext) 2.2 创建DataFrames(Creating DataFrames) 2.3 DataFrame操作(DataFrame Operations) 2.4 运行SQL查询程序(Running SQL Queries Programmatically) 2.5 DataFrames与RDDs的相互转换(Interoperating with RDDs) 2.5.1 使用反射获取Schema(Inferring the Schema Using Reflection) 2.5.2 通过编程接口指定Schema(Programmatically Specifying the Schema) 3 数据源(Data Source) 3.1 一般Load/Save方法 3.1.1 手动指定选项(Manually Specifying Options) 3.1.2 存储模式(Save Modes) 3.1.3 持久化到表(Saving to Persistent Tables) 3.2 Parquet文件 3.2.1 读取Parquet文件(Loading Data Programmatically) 3.2.2 解析分区信息(Partition Discovery) 3.2.3 Schema合并(Schema Merging) 3.2.4 Hive metastore Parquet表转换(Hive metastore Parquet table conversion) 3.2.4.1 Hive/Parquet Schema反射(Hive/Parquet Schema Reconciliation) 3.2.4.2 元数据刷新(Metadata Refreshing) 3.2.5 配置(Configuration) 3.3 JSON数据集 3.4 Hive表 3.4.1 访问不同版本的Hive Metastore(Interacting with Different Versions of Hive Metastore) 3.5 JDBC To Other Databases 3.6 故障排除(Troubleshooting) 4 性能调优 4.1 缓存数据至内存(Caching Data In Memory) 4.2 调优参数(Other Configuration Options) 5 分布式SQL引擎 5.1 运行Thrift JDBC/ODBC服务 5.2 运行Spark SQL CLI 6 Migration Guide 6.1 与Hive的兼容(Compatibility with Apache Hive 6.1.1 在Hive warehouse中部署Spark SQL 6.1.2 Spark SQL支持的Hive特性 6.1.3 不支持的Hive功能 7 Reference 7.1 Data Types 7.2 NaN 语义 1 概述(Overview) Spark SQL是Spark的一个组件,用于结构化数据的计算。Spark SQL提供了一个称为DataFrames的编程抽象,DataFrames可以充当分布式SQL查询引擎。 2 DataFrames DataFrame是一个分布式的数据集合,该数据集合以命名列的方式进行整合。DataFrame可以理解为关系数据库中的一张表,也可以理解为R/Python中的一个data frame。DataFrames可以通过多种数据构造,例如:结构化的数据文件、hive中的表、外部数据库、Spark计算过程中生成的RDD等。DataFrame的API支持4种语言:Scala、Java、Python、R。 2.1 入口:SQLContext(Starting Point: SQLContext) Spark SQL程序的主入口是SQLContext类或它的子类。创建一个基本的SQLContext,你只需要SparkContext,创建代码示例如下: Scala val sc: SparkContext // An existing SparkContext. val sqlContext = new org.apache.spark.sql.SQLContext(sc) Java JavaSparkContext sc = ...; // An existing JavaSparkContext. SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc); 除了基本的SQLContext,也可以创建HiveContext。SQLContext和HiveContext区别与联系为: SQLContext现在只支持SQL语法解析器(SQL-92语法) HiveContext现在支持SQL语法解析器和HiveSQL语法解析器,默认为HiveSQL语法解析器,用户可以通过配置切换成SQL语法解析器,来运行HiveSQL不支持的语法。 使用HiveContext可以使用Hive的UDF,读写Hive表数据等Hive操作。SQLContext不可以对Hive进行操作。 Spark SQL未来的版本会不断丰富SQLContext的功能,做到SQLContext和HiveContext的功能容和,最终可能两者会统一成一个Context HiveContext包装了Hive的依赖包,把HiveContext单独拿出来,可以在部署基本的Spark的时候就不需要Hive的依赖包,需要使用HiveContext时再把Hive的各种依赖包加进来。 SQL的解析器可以通过配置spark.sql.dialect参数进行配置。在SQLContext中只能使用Spark SQL提供的”sql“解析器。在HiveContext中默认解析器为”hiveql“,也支持”sql“解析器。 2.2 创建DataFrames(Creating DataFrames) 使用SQLContext,spark应用程序(Application)可以通过RDD、Hive表、JSON格式数据等数据源创建DataFrames。下面是基于JSON文件创建DataFrame的示例: Scala val sc: SparkContext // An existing SparkContext. val sqlContext = new org.apache.spark.sql.SQLContext(sc) val df = sqlContext.read.json("examples/src/main/resources/people.json") // Displays the content of the DataFrame to stdout df.show() Java JavaSparkContext sc = ...; // An existing JavaSparkContext. SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc); DataFrame df = sqlContext.read().json("examples/src/main/resources/people.json"); // Displays the content of the DataFrame to stdout df.show(); 2.3 DataFrame操作(DataFrame Operations) DataFrames支持Scala、Java和Python的操作接口。下面是Scala和Java的几个操作示例: Scala val sc: SparkContext // An existing SparkContext. val sqlContext = new org.apache.spark.sql.SQLContext(sc) // Create the DataFrame val df = sqlContext.read.json("examples/src/main/resources/people.json") // Show the content of the DataFrame df.show() // age name // null Michael // 30 Andy // 19 Justin // Print the schema in a tree format df.printSchema() // root // |-- age: long (nullable = true) // |-- name: string (nullable = true) // Select only the "name" column df.select("name").show() // name // Michael // Andy // Justin // Select everybody, but increment the age by 1 df.select(df("name"), df("age") + 1).show() // name (age + 1) // Michael null // Andy 31 // Justin 20 // Select people older than 21 df.filter(df("age") > 21).show() // age name // 30 Andy // Count people by age df.groupBy("age").count().show() // age count // null 1 // 19 1 // 30 1 Java JavaSparkContext sc // An existing SparkContext. SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc) // Create the DataFrame DataFrame df = sqlContext.read().json("examples/src/main/resources/people.json"); // Show the content of the DataFrame df.show(); // age name // null Michael // 30 Andy // 19 Justin // Print the schema in a tree format df.printSchema(); // root // |-- age: long (nullable = true) // |-- name: string (nullable = true) // Select only the "name" column df.select("name").show(); // name // Michael // Andy // Justin // Select everybody, but increment the age by 1 df.select(df.col("name"), df.col("age").plus(1)).show(); // name (age + 1) // Michael null // Andy 31 // Justin 20 // Select people older than 21 df.filter(df.col("age").gt(21)).show(); // age name // 30 Andy // Count people by age df.groupBy("age").count().show(); // age count // null 1 // 19 1 // 30 1 详细的DataFrame API请参考API Documentation。 除了简单列引用和表达式,DataFrames还有丰富的library,功能包括string操作、date操作、常见数学操作等。详细内容请参考DataFrame Function Reference。 2.4 运行SQL查询程序(Running SQL Queries Programmatically) Spark Application可以使用SQLContext的sql()方法执行SQL查询操作,sql()方法返回的查询结果为DataFrame格式。代码如下: Scala val sqlContext = ... // An existing SQLContext val df = sqlContext.sql("SELECT * FROM table") Java SQLContext sqlContext = ... // An existing SQLContext DataFrame df = sqlContext.sql("SELECT * FROM table") 2.5 DataFrames与RDDs的相互转换(Interoperating with RDDs) Spark SQL支持两种RDDs转换为DataFrames的方式: 使用反射获取RDD内的Schema 当已知类的Schema的时候,使用这种基于反射的方法会让代码更加简洁而且效果也很好。 通过编程接口指定Schema 通过Spark SQL的接口创建RDD的Schema,这种方式会让代码比较冗长。 这种方法的好处是,在运行时才知道数据的列以及列的类型的情况下,可以动态生成Schema 2.5.1 使用反射获取Schema(Inferring the Schema Using Reflection) Spark SQL支持将JavaBean的RDD自动转换成DataFrame。通过反射获取Bean的基本信息,依据Bean的信息定义Schema。当前Spark SQL版本(Spark 1.5.2)不支持嵌套的JavaBeans和复杂数据类型(如:List、Array)。创建一个实现Serializable接口包含所有属性getters和setters的类来创建一个JavaBean。通过调用createDataFrame并提供JavaBean的Class object,指定一个Schema给一个RDD。示例如下: public static class Person implements Serializable { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } // sc is an existing JavaSparkContext. SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc); // Load a text file and convert each line to a JavaBean. JavaRDD<Person> people = sc.textFile("examples/src/main/resources/people.txt").map( new Function<String, Person>() { public Person call(String line) throws Exception { String[] parts = line.split(","); Person person = new Person(); person.setName(parts[0]); person.setAge(Integer.parseInt(parts[1].trim())); return person; } }); // Apply a schema to an RDD of JavaBeans and register it as a table. DataFrame schemaPeople = sqlContext.createDataFrame(people, Person.class); schemaPeople.registerTempTable("people"); // SQL can be run over RDDs that have been registered as tables. DataFrame teenagers = sqlContext.sql("SELECT name FROM people WHERE age >= 13 AND age <= 19") // The results of SQL queries are DataFrames and support all the normal RDD operations. // The columns of a row in the result can be accessed by ordinal. List<String> teenagerNames = teenagers.javaRDD().map(new Function<Row, String>() { public String call(Row row) { return "Name: " + row.getString(0); } }).collect(); 2.5.2 通过编程接口指定Schema(Programmatically Specifying the Schema) 当JavaBean不能被预先定义的时候,编程创建DataFrame分为三步: 从原来的RDD创建一个Row格式的RDD 创建与RDD中Rows结构匹配的StructType,通过该StructType创建表示RDD的Schema 通过SQLContext提供的createDataFrame方法创建DataFrame,方法参数为RDD的Schema 示例如下: import org.apache.spark.api.java.function.Function; // Import factory methods provided by DataTypes. import org.apache.spark.sql.types.DataTypes; // Import StructType and StructField import org.apache.spark.sql.types.StructType; import org.apache.spark.sql.types.StructField; // Import Row. import org.apache.spark.sql.Row; // Import RowFactory. import org.apache.spark.sql.RowFactory; // sc is an existing JavaSparkContext. SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc); // Load a text file and convert each line to a JavaBean. JavaRDD<String> people = sc.textFile("examples/src/main/resources/people.txt"); // The schema is encoded in a string String schemaString = "name age"; // Generate the schema based on the string of schema List<StructField> fields = new ArrayList<StructField>(); for (String fieldName: schemaString.split(" ")) { fields.add(DataTypes.createStructField(fieldName, DataTypes.StringType, true)); } StructType schema = DataTypes.createStructType(fields); // Convert records of the RDD (people) to Rows. JavaRDD<Row> rowRDD = people.map( new Function<String, Row>() { public Row call(String record) throws Exception { String[] fields = record.split(","); return RowFactory.create(fields[0], fields[1].trim()); } }); // Apply the schema to the RDD. DataFrame peopleDataFrame = sqlContext.createDataFrame(rowRDD, schema); // Register the DataFrame as a table. peopleDataFrame.registerTempTable("people"); // SQL can be run over RDDs that have been registered as tables. DataFrame results = sqlContext.sql("SELECT name FROM people"); // The results of SQL queries are DataFrames and support all the normal RDD operations. // The columns of a row in the result can be accessed by ordinal. List<String> names = results.javaRDD().map(new Function<Row, String>() { public String call(Row row) { return "Name: " + row.getString(0); } }).collect(); 3 数据源(Data Source) Spark SQL的DataFrame接口支持多种数据源的操作。一个DataFrame可以进行RDDs方式的操作,也可以被注册为临时表。把DataFrame注册为临时表之后,就可以对该DataFrame执行SQL查询。Data Sources这部分首先描述了对Spark的数据源执行加载和保存的常用方法,然后对内置数据源进行深入介绍。 3.1 一般Load/Save方法 Spark SQL的默认数据源为Parquet格式。数据源为Parquet文件时,Spark SQL可以方便的执行所有的操作。修改配置项spark.sql.sources.default,可修改默认数据源格式。读取Parquet文件示例如下: Scala val df = sqlContext.read.load("examples/src/main/resources/users.parquet") df.select("name", "favorite_color").write.save("namesAndFavColors.parquet") Java DataFrame df = sqlContext.read().load("examples/src/main/resources/users.parquet"); df.select("name", "favorite_color").write().save("namesAndFavColors.parquet"); 3.1.1 手动指定选项(Manually Specifying Options) 当数据源格式不是parquet格式文件时,需要手动指定数据源的格式。数据源格式需要指定全名(例如:org.apache.spark.sql.parquet),如果数据源格式为内置格式,则只需要指定简称(json,parquet,jdbc)。通过指定的数据源格式名,可以对DataFrames进行类型转换操作。示例如下: Scala val df = sqlContext.read.format("json").load("examples/src/main/resources/people.json") df.select("name", "age").write.format("parquet").save("namesAndAges.parquet") Java DataFrame df = sqlContext.read().format("json").load("examples/src/main/resources/people.json"); df.select("name", "age").write().format("parquet").save("namesAndAges.parquet"); 3.1.2 存储模式(Save Modes) 可以采用SaveMode执行存储操作,SaveMode定义了对数据的处理模式。需要注意的是,这些保存模式不使用任何锁定,不是原子操作。此外,当使用Overwrite方式执行时,在输出新数据之前原数据就已经被删除。SaveMode详细介绍如下表: 3.1.3 持久化到表(Saving to Persistent Tables) 当使用HiveContext时,可以通过saveAsTable方法将DataFrames存储到表中。与registerTempTable方法不同的是,saveAsTable将DataFrame中的内容持久化到表中,并在HiveMetastore中存储元数据。存储一个DataFrame,可以使用SQLContext的table方法。table先创建一个表,方法参数为要创建的表的表名,然后将DataFrame持久化到这个表中。 默认的saveAsTable方法将创建一个“managed table”,表示数据的位置可以通过metastore获得。当存储数据的表被删除时,managed table也将自动删除。 3.2 Parquet文件 Parquet是一种支持多种数据处理系统的柱状的数据格式,Parquet文件中保留了原始数据的模式。Spark SQL提供了Parquet文件的读写功能。 3.2.1 读取Parquet文件(Loading Data Programmatically) 读取Parquet文件示例如下: Scala // sqlContext from the previous example is used in this example. // This is used to implicitly convert an RDD to a DataFrame. import sqlContext.implicits._ val people: RDD[Person] = ... // An RDD of case class objects, from the previous example. // The RDD is implicitly converted to a DataFrame by implicits, allowing it to be stored using Parquet. people.write.parquet("people.parquet") // Read in the parquet file created above. Parquet files are self-describing so the schema is preserved. // The result of loading a Parquet file is also a DataFrame. val parquetFile = sqlContext.read.parquet("people.parquet") //Parquet files can also be registered as tables and then used in SQL statements. parquetFile.registerTempTable("parquetFile") val teenagers = sqlContext.sql("SELECT name FROM parquetFile WHERE age >= 13 AND age <= 19") teenagers.map(t => "Name: " + t(0)).collect().foreach(println) Java // sqlContext from the previous example is used in this example. DataFrame schemaPeople = ... // The DataFrame from the previous example. // DataFrames can be saved as Parquet files, maintaining the schema information. schemaPeople.write().parquet("people.parquet"); // Read in the Parquet file created above. Parquet files are self-describing so the schema is preserved. // The result of loading a parquet file is also a DataFrame. DataFrame parquetFile = sqlContext.read().parquet("people.parquet"); // Parquet files can also be registered as tables and then used in SQL statements. parquetFile.registerTempTable("parquetFile"); DataFrame teenagers = sqlContext.sql("SELECT name FROM parquetFile WHERE age >= 13 AND age <= 19"); List<String> teenagerNames = teenagers.javaRDD().map(new Function<Row, String>() { public String call(Row row) { return "Name: " + row.getString(0); } }).collect(); 3.2.2 解析分区信息(Partition Discovery) 对表进行分区是对数据进行优化的方式之一。在分区的表内,数据通过分区列将数据存储在不同的目录下。Parquet数据源现在能够自动发现并解析分区信息。例如,对人口数据进行分区存储,分区列为gender和country,使用下面的目录结构: path └── to └── table ├── gender=male │ ├── ... │ │ │ ├── country=US │ │ └── data.parquet │ ├── country=CN │ │ └── data.parquet │ └── ... └── gender=female ├── ... │ ├── country=US │ └── data.parquet ├── country=CN │ └── data.parquet └── ... 通过传递path/to/table给 SQLContext.read.parquet或SQLContext.read.load,Spark SQL将自动解析分区信息。返回的DataFrame的Schema如下: root |-- name: string (nullable = true) |-- age: long (nullable = true) |-- gender: string (nullable = true) |-- country: string (nullable = true) 需要注意的是,数据的分区列的数据类型是自动解析的。当前,支持数值类型和字符串类型。自动解析分区类型的参数为:spark.sql.sources.partitionColumnTypeInference.enabled,默认值为true。如果想关闭该功能,直接将该参数设置为disabled。此时,分区列数据格式将被默认设置为string类型,不再进行类型解析。 3.2.3 Schema合并(Schema Merging) 像ProtocolBuffer、Avro和Thrift那样,Parquet也支持Schema evolution(Schema演变)。用户可以先定义一个简单的Schema,然后逐渐的向Schema中增加列描述。通过这种方式,用户可以获取多个有不同Schema但相互兼容的Parquet文件。现在Parquet数据源能自动检测这种情况,并合并这些文件的schemas。 因为Schema合并是一个高消耗的操作,在大多数情况下并不需要,所以Spark SQL从1.5.0开始默认关闭了该功能。可以通过下面两种方式开启该功能: 当数据源为Parquet文件时,将数据源选项mergeSchema设置为true 设置全局SQL选项spark.sql.parquet.mergeSchema为true 示例如下: Scala // sqlContext from the previous example is used in this example. // This is used to implicitly convert an RDD to a DataFrame. import sqlContext.implicits._ // Create a simple DataFrame, stored into a partition directory val df1 = sc.makeRDD(1 to 5).map(i => (i, i * 2)).toDF("single", "double") df1.write.parquet("data/test_table/key=1") // Create another DataFrame in a new partition directory, // adding a new column and dropping an existing column val df2 = sc.makeRDD(6 to 10).map(i => (i, i * 3)).toDF("single", "triple") df2.write.parquet("data/test_table/key=2") // Read the partitioned table val df3 = sqlContext.read.option("mergeSchema", "true").parquet("data/test_table") df3.printSchema() // The final schema consists of all 3 columns in the Parquet files together // with the partitioning column appeared in the partition directory paths. // root // |-- single: int (nullable = true) // |-- double: int (nullable = true) // |-- triple: int (nullable = true) // |-- key : int (nullable = true) 3.2.4 Hive metastore Parquet表转换(Hive metastore Parquet table conversion) 当向Hive metastore中读写Parquet表时,Spark SQL将使用Spark SQL自带的Parquet SerDe(SerDe:Serialize/Deserilize的简称,目的是用于序列化和反序列化),而不是用Hive的SerDe,Spark SQL自带的SerDe拥有更好的性能。这个优化的配置参数为spark.sql.hive.convertMetastoreParquet,默认值为开启。 3.2.4.1 Hive/Parquet Schema反射(Hive/Parquet Schema Reconciliation) 从表Schema处理的角度对比Hive和Parquet,有两个区别: Hive区分大小写,Parquet不区分大小写 hive允许所有的列为空,而Parquet不允许所有的列全为空 由于这两个区别,当将Hive metastore Parquet表转换为Spark SQL Parquet表时,需要将Hive metastore schema和Parquet schema进行一致化。一致化规则如下: 这两个schema中的同名字段必须具有相同的数据类型。一致化后的字段必须为Parquet的字段类型。这个规则同时也解决了空值的问题。 一致化后的schema只包含Hive metastore中出现的字段。 忽略只出现在Parquet schema中的字段 只在Hive metastore schema中出现的字段设为nullable字段,并加到一致化后的schema中 3.2.4.2 元数据刷新(Metadata Refreshing) Spark SQL缓存了Parquet元数据以达到良好的性能。当Hive metastore Parquet表转换为enabled时,表修改后缓存的元数据并不能刷新。所以,当表被Hive或其它工具修改时,则必须手动刷新元数据,以保证元数据的一致性。示例如下: Scala // sqlContext is an existing HiveContext sqlContext.refreshTable("my_table") Java // sqlContext is an existing HiveContext sqlContext.refreshTable("my_table") 3.2.5 配置(Configuration) 配置Parquet可以使用SQLContext的setConf方法或使用SQL执行SET key=value命令。详细参数说明如下: 3.3 JSON数据集 Spark SQL能自动解析JSON数据集的Schema,读取JSON数据集为DataFrame格式。读取JSON数据集方法为SQLContext.read().json()。该方法将String格式的RDD或JSON文件转换为DataFrame。 需要注意的是,这里的JSON文件不是常规的JSON格式。JSON文件每一行必须包含一个独立的、自满足有效的JSON对象。如果用多行描述一个JSON对象,会导致读取出错。读取JSON数据集示例如下: Scala // sc is an existing SparkContext. val sqlContext = new org.apache.spark.sql.SQLContext(sc) // A JSON dataset is pointed to by path. // The path can be either a single text file or a directory storing text files. val path = "examples/src/main/resources/people.json" val people = sqlContext.read.json(path) // The inferred schema can be visualized using the printSchema() method. people.printSchema() // root // |-- age: integer (nullable = true) // |-- name: string (nullable = true) // Register this DataFrame as a table. people.registerTempTable("people") // SQL statements can be run by using the sql methods provided by sqlContext. val teenagers = sqlContext.sql("SELECT name FROM people WHERE age >= 13 AND age <= 19") // Alternatively, a DataFrame can be created for a JSON dataset represented by // an RDD[String] storing one JSON object per string. val anotherPeopleRDD = sc.parallelize( """{"name":"Yin","address":{"city":"Columbus","state":"Ohio"}}""" :: Nil) val anotherPeople = sqlContext.read.json(anotherPeopleRDD) Java // sc is an existing JavaSparkContext. SQLContext sqlContext = new org.apache.spark.sql.SQLContext(sc); // A JSON dataset is pointed to by path. // The path can be either a single text file or a directory storing text files. DataFrame people = sqlContext.read().json("examples/src/main/resources/people.json"); // The inferred schema can be visualized using the printSchema() method. people.printSchema(); // root // |-- age: integer (nullable = true) // |-- name: string (nullable = true) // Register this DataFrame as a table. people.registerTempTable("people"); // SQL statements can be run by using the sql methods provided by sqlContext. DataFrame teenagers = sqlContext.sql("SELECT name FROM people WHERE age >= 13 AND age <= 19"); // Alternatively, a DataFrame can be created for a JSON dataset represented by // an RDD[String] storing one JSON object per string. List<String> jsonData = Arrays.asList( "{\"name\":\"Yin\",\"address\":{\"city\":\"Columbus\",\"state\":\"Ohio\"}}"); JavaRDD<String> anotherPeopleRDD = sc.parallelize(jsonData); DataFrame anotherPeople = sqlContext.read().json(anotherPeopleRDD); 3.4 Hive表 Spark SQL支持对Hive的读写操作。需要注意的是,Hive所依赖的包,没有包含在Spark assembly包中。增加Hive时,需要在Spark的build中添加 -Phive 和 -Phivethriftserver配置。这两个配置将build一个新的assembly包,这个assembly包含了Hive的依赖包。注意,必须上这个心的assembly包到所有的worker节点上。因为worker节点在访问Hive中数据时,会调用Hive的 serialization and deserialization libraries(SerDes),此时将用到Hive的依赖包。 Hive的配置文件为conf/目录下的hive-site.xml文件。在YARN上执行查询命令之前,lib_managed/jars目录下的datanucleus包和conf/目录下的hive-site.xml必须可以被driverhe和所有的executors所访问。确保被访问,最方便的方式就是在spark-submit命令中通过--jars选项和--file选项指定。 操作Hive时,必须创建一个HiveContext对象,HiveContext继承了SQLContext,并增加了对MetaStore和HiveQL的支持。除了sql方法,HiveContext还提供了一个hql方法,hql方法可以执行HiveQL语法的查询语句。示例如下: Scala // sc is an existing SparkContext. val sqlContext = new org.apache.spark.sql.hive.HiveContext(sc) sqlContext.sql("CREATE TABLE IF NOT EXISTS src (key INT, value STRING)") sqlContext.sql("LOAD DATA LOCAL INPATH 'examples/src/main/resources/kv1.txt' INTO TABLE src") // Queries are expressed in HiveQL sqlContext.sql("FROM src SELECT key, value").collect().foreach(println) Java // sc is an existing JavaSparkContext. HiveContext sqlContext = new org.apache.spark.sql.hive.HiveContext(sc.sc); sqlContext.sql("CREATE TABLE IF NOT EXISTS src (key INT, value STRING)"); sqlContext.sql("LOAD DATA LOCAL INPATH 'examples/src/main/resources/kv1.txt' INTO TABLE src"); // Queries are expressed in HiveQL. Row[] results = sqlContext.sql("FROM src SELECT key, value").collect(); 3.4.1 访问不同版本的Hive Metastore(Interacting with Different Versions of Hive Metastore) Spark SQL经常需要访问Hive metastore,Spark SQL可以通过Hive metastore获取Hive表的元数据。从Spark 1.4.0开始,Spark SQL只需简单的配置,就支持各版本Hive metastore的访问。注意,涉及到metastore时Spar SQL忽略了Hive的版本。Spark SQL内部将Hive反编译至Hive 1.2.1版本,Spark SQL的内部操作(serdes, UDFs, UDAFs, etc)都调用Hive 1.2.1版本的class。版本配置项见下面表格: 3.5 JDBC To Other Databases Spark SQL支持使用JDBC访问其他数据库。当时用JDBC访问其它数据库时,最好使用JdbcRDD。使用JdbcRDD时,Spark SQL操作返回的DataFrame会很方便,也会很方便的添加其他数据源数据。JDBC数据源因为不需要用户提供ClassTag,所以很适合使用Java或Python进行操作。使用JDBC访问数据源,需要在spark classpath添加JDBC driver配置。例如,从Spark Shell连接postgres的配置为: SPARK_CLASSPATH=postgresql-9.3-1102-jdbc41.jar bin/spark-shell 远程数据库的表,可用DataFrame或Spark SQL临时表的方式调用数据源API。支持的参数有: 代码示例如下: Scala val jdbcDF = sqlContext.read.format("jdbc").options( Map("url" -> "jdbc:postgresql:dbserver", "dbtable" -> "schema.tablename")).load() Java Map<String, String> options = new HashMap<String, String>(); options.put("url", "jdbc:postgresql:dbserver"); options.put("dbtable", "schema.tablename"); DataFrame jdbcDF = sqlContext.read().format("jdbc"). options(options).load(); 3.6 故障排除(Troubleshooting) 在客户端session和所有的executors上,JDBC driver必须对启动类加载器(primordial class loader)设置为visible。因为当创建一个connection时,Java的DriverManager类会执行安全验证,安全验证将忽略所有对启动类加载器为非visible的driver。一个很方便的解决方法是,修改所有worker节点上的compute_classpath.sh脚本,将driver JARs添加至脚本。 有些数据库(例:H2)将所有的名字转换为大写,所以在这些数据库中,Spark SQL也需要将名字全部大写。 4 性能调优 4.1 缓存数据至内存(Caching Data In Memory) Spark SQL可以通过调用sqlContext.cacheTable("tableName") 或者dataFrame.cache(),将表用一种柱状格式( an in­memory columnar format)缓存至内存中。然后Spark SQL在执行查询任务时,只需扫描必需的列,从而以减少扫描数据量、提高性能。通过缓存数据,Spark SQL还可以自动调节压缩,从而达到最小化内存使用率和降低GC压力的目的。调用sqlContext.uncacheTable("tableName")可将缓存的数据移出内存。 可通过两种配置方式开启缓存数据功能: 使用SQLContext的setConf方法 执行SQL命令 SET key=value 4.2 调优参数(Other Configuration Options) 可以通过配置下表中的参数调节Spark SQL的性能。在后续的Spark版本中将逐渐增强自动调优功能,下表中的参数在后续的版本中或许将不再需要配置。 5 分布式SQL引擎 使用Spark SQL的JDBC/ODBC或者CLI,可以将Spark SQL作为一个分布式查询引擎。终端用户或应用不需要编写额外的代码,可以直接使用Spark SQL执行SQL查询。 5.1 运行Thrift JDBC/ODBC服务 这里运行的Thrift JDBC/ODBC服务与Hive 1.2.1中的HiveServer2一致。可以在Spark目录下执行如下命令来启动JDBC/ODBC服务: ./sbin/start-thriftserver.sh 这个命令接收所有bin/spark-submit命令行参数,添加一个--hiveconf参数来指定Hive的属性。详细的参数说明请执行命令./sbin/start-thriftserver.sh --help。服务默认监听端口为localhost:10000。有两种方式修改默认监听端口: 修改环境变量: export HIVE_SERVER2_THRIFT_PORT=<listening-port> export HIVE_SERVER2_THRIFT_BIND_HOST=<listening-host> ./sbin/start-thriftserver.sh \ --master <master-uri> \ ... 修改系统属性 ./sbin/start-thriftserver.sh \ --hiveconf hive.server2.thrift.port=<listening-port> \ --hiveconf hive.server2.thrift.bind.host=<listening-host> \ --master <master-uri> ... 使用beeline来测试Thrift JDBC/ODBC服务: ./bin/beeline 连接到Thrift JDBC/ODBC服务 beeline> !connect jdbc:hive2://localhost:10000 在非安全模式下,只需要输入机器上的一个用户名即可,无需密码。在安全模式下,beeline会要求输入用户名和密码。安全模式下的详细要求,请阅读beeline documentation的说明。 配置Hive需要替换conf/目录下的hive-site.xml。 Thrift JDBC服务也支持通过HTTP传输发送thrift RPC messages。开启HTTP模式需要将下面的配参数配置到系统属性或conf/:下的hive-site.xml中 hive.server2.transport.mode - Set this to value: http hive.server2.thrift.http.port - HTTP port number fo listen on; default is 10001 hive.server2.http.endpoint - HTTP endpoint; default is cliservice 测试http模式,可以使用beeline链接JDBC/ODBC服务: beeline> !connect jdbc:hive2://<host>:<port>/<database>?hive.server2.transport.mode=http;hive.server2.thrift.http.path=<http_endpoint> 5.2 运行Spark SQL CLI Spark SQL CLI可以很方便的在本地运行Hive元数据服务以及从命令行执行查询任务。需要注意的是,Spark SQL CLI不能与Thrift JDBC服务交互。在Spark目录下执行如下命令启动Spark SQL CLI: ./bin/spark-sql 配置Hive需要替换conf/下的hive-site.xml。执行./bin/spark-sql --help可查看详细的参数说明 。 6 Migration Guide 6.1 与Hive的兼容(Compatibility with Apache Hive) Spark SQL与Hive Metastore、SerDes、UDFs相兼容。Spark SQL兼容Hive Metastore从0.12到1.2.1的所有版本。Spark SQL也与Hive SerDes和UDFs相兼容,当前SerDes和UDFs是基于Hive 1.2.1。 6.1.1 在Hive warehouse中部署Spark SQL Spark SQL Thrift JDBC服务与Hive相兼容,在已存在的Hive上部署Spark SQL Thrift服务不需要对已存在的Hive Metastore做任何修改,也不需要对数据做任何改动。 6.1.2 Spark SQL支持的Hive特性 Spark SQL支持多部分的Hive特性,例如: Hive查询语句,包括: SELECT GROUP BY ORDER BY CLUSTER BY SORT BY 所有Hive运算符,包括 比较操作符(=, ⇔, ==, <>, <, >, >=, <=, etc) 算术运算符(+, -, *, /, %, etc) 逻辑运算符(AND, &&, OR, ||, etc) 复杂类型构造器 数学函数(sign,ln,cos,etc) 字符串函数(instr,length,printf,etc) 用户自定义函数(UDF) 用户自定义聚合函数(UDAF) 用户自定义序列化格式器(SerDes) 窗口函数 Joins JOIN {LEFT|RIGHT|FULL} OUTER JOIN LEFT SEMI JOIN CROSS JOIN Unions 子查询 SELECT col FROM ( SELECT a + b AS col from t1) t2 Sampling Explain 表分区,包括动态分区插入 视图 所有的Hive DDL函数,包括: CREATE TABLE CREATE TABLE AS SELECT ALTER TABLE 大部分的Hive数据类型,包括: TINYINT SMALLINT INT BIGINT BOOLEAN FLOAT DOUBLE STRING BINARY TIMESTAMP DATE ARRAY<> MAP<> STRUCT<> 6.1.3 不支持的Hive功能 下面是当前不支持的Hive特性,其中大部分特性在实际的Hive使用中很少用到。 Major Hive Features Tables with buckets:bucket是在一个Hive表分区内进行hash分区。Spark SQL当前不支持。 Esoteric Hive Features UNION type Unique join Column statistics collecting:当期Spark SQL不智齿列信息统计,只支持填充Hive Metastore的sizeInBytes列。 Hive Input/Output Formats File format for CLI: 这个功能用于在CLI显示返回结果,Spark SQL只支持TextOutputFormat Hadoop archive Hive优化部分Hive优化还没有添加到Spark中。没有添加的Hive优化(比如索引)对Spark SQL这种in-memory计算模型来说不是特别重要。下列Hive优化将在后续Spark SQL版本中慢慢添加。 块级别位图索引和虚拟列(用于建立索引) 自动检测joins和groupbys的reducer数量:当前Spark SQL中需要使用“SET spark.sql.shuffle.partitions=[num_tasks];”控制post-shuffle的并行度,不能自动检测。 仅元数据查询:对于可以通过仅使用元数据就能完成的查询,当前Spark SQL还是需要启动任务来计算结果。 数据倾斜标记:当前Spark SQL不遵循Hive中的数据倾斜标记 jion中STREAMTABLE提示:当前Spark SQL不遵循STREAMTABLE提示 查询结果为多个小文件时合并小文件:如果查询结果包含多个小文件,Hive能合并小文件为几个大文件,避免HDFS metadata溢出。当前Spark SQL不支持这个功能。 7 Reference 7.1 Data Types Spark SQL和DataFrames支持的数据格式如下: 数值类型 ByteType: 代表1字节有符号整数. 数值范围: -128 到 127. ShortType: 代表2字节有符号整数. 数值范围: -32768 到 32767. IntegerType: 代表4字节有符号整数. 数值范围: -2147483648 t到 2147483647. LongType: 代表8字节有符号整数. 数值范围: -9223372036854775808 到 9223372036854775807. FloatType: 代表4字节单精度浮点数。 DoubleType: 代表8字节双精度浮点数。 DecimalType: 表示任意精度的有符号十进制数。内部使用java.math.BigDecimal.A实现。 BigDecimal由一个任意精度的整数非标度值和一个32位的整数组成。 String类型 StringType: 表示字符串值。 Binary类型 BinaryType: 代表字节序列值。 Boolean类型 BooleanType: 代表布尔值。 Datetime类型 TimestampType: 代表包含的年、月、日、时、分和秒的时间值 DateType: 代表包含的年、月、日的日期值 复杂类型 ArrayType(elementType, containsNull): 代表包含一系列类型为elementType的元素。如果在一个将ArrayType值的元素可以为空值,containsNull指示是否允许为空。 MapType(keyType, valueType, valueContainsNull): 代表一系列键值对的集合。key不允许为空,valueContainsNull指示value是否允许为空 StructType(fields): 代表带有一个StructFields(列)描述结构数据。 StructField(name, dataType, nullable): 表示StructType中的一个字段。name表示列名、dataType表示数据类型、nullable指示是否允许为空。 Spark SQL所有的数据类型在org.apache.spark.sql.types包内。不同语言访问或创建数据类型方法不一样: Scala代码中添加import org.apache.spark.sql.types._,再进行数据类型访问或创建操作。 Java可以使用org.apache.spark.sql.types.DataTypes中的工厂方法,如下表: 7.2 NaN 语义 当处理float或double类型时,如果类型不符合标准的浮点语义,则使用专门的处理方式NaN。需要注意的是: NaN = NaN 返回 true 可以对NaN值进行聚合操作 在join操作中,key为NaN时,NaN值与普通的数值处理逻辑相同 NaN值大于所有的数值型数据,在升序排序中排在最后 转自:http://www.cnblogs.com/BYRans/

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

ThinkSNS+产品技术概要

一、PC端(web端)服务端框架:Laravel 5.7+前端框架:jQuery+Bootstrap3管理后台: html + jquery + bootstrap + vue前端开发语言:HTML/CSS/JavaScript(ES5)开发环境:PHP7.1.3+ / Nginx 1.10+ / Mysql 5.7+运行环境:IE10+/Chrome/Firefox/Safari等支持ES5语法和Flex布局的浏览器额外内容:Lodash+Axios+easemob+Dexie开发软件:VSCode / Atom / Sublime Text / WebStorm / PHPStrom等,无特殊要求。 二、SPA端(手机H5)开发框架:Vue2.6(及其套件)/Axios开发语言:HTML5/Less/JavaScript(ES6)开发环境:VS Code/ES Lint/nodejs8+/vue-dev tools 额外内容:Lodash + Axios + easemob + Dexie开发软件:推荐VScode 三、Android APP端开发语言:JAVA,部分接入kotlin框架:整体结构:MVP + Dagger2技术说明 :Retrofit+Okhttp+Dagger2+Rx+GreenDao+Glide支持lambda表达式开发软件:Android Studio 3.1(IDE)编辑器,推荐使用最新版; 支持系统及机型:所有Android手机,Android 4.3 及以上系统。 四、Ios 端 开发语言:Swift 4.2、Objective-C开发软件:XCode(IDE)版本10.2 ;Cocoapods 1.5.3支持系统及机型:支持iPhone5s手机, iOS 9.0 以上系统。设计模式:MVC主要应用三方SDK:Alamofire、Realm、Kingfisher、SnapKit、Hyphenate、AMap、MarkdownView 五、服务器环境PHP:PHP 7.1.3 +扩展要求: OpenSSL PHP 拓展PDO PHP 拓展Mbstring PHP 拓展Tokenizer PHP 拓展XML PHP 拓展Ctype PHP 拓展JSON PHP 拓展BCMath PHP 拓展Composer:推荐使用最新版数据库:mysql 5.6+ 推荐 5.7+系统:Nginx 1.10 + 推荐1.12+Centos 6+ 推荐 7.0+

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

Windows 7 产品新特性

(1)更低需求,更优性能表现 经济危机来袭之时,企业愈加依重信息化平台上运转的生产和经营管理软件。平台的性能提高,是否只能依靠在硬件上的巨额投入?企业以前所购置的低端电脑是否便意味着无谓的浪费? Windows 7是微软最新一代操作系统软件,性能更为突出,对系统配置的要求却大大降低,更稳定可靠的基础架构减少了系统崩溃和运行速度慢的情况,最经济的投入即可令一些在Windows Vista时代不堪其负的电脑重新开始支持您的业务运转。 (2)软件硬件,实现良好兼容 企业内所使用的各类计算机专业硬件、网络设备与数字办公外设和即插即拔设备,种类多样且不断推陈出新,至2010年预计将会增加到4,000,000种。到目前为止,Windows 7广泛兼容Windows Vista所支持的各类硬件与外设。此外,用户还可以通过Windows 更新或设备制造商的网站获取驱动。另外,到目前为止,绝大部分可以在Windows Vista上运行的软件,在Windows 7上同样正常运行。 Windows 7更提供了强大的“Windows Program Compatibility Troubleshooter”,基本上帮助解决了从Windows 95,Windows 98/Me, Windows 2000, Windows NT4.0,Windows XP, Windows Server 2003, Windows Vista在内的各类应用程序的兼容性问题。 职场 Windows 休闲 本文转自 tao61 博客,原文链接: http://blog.51cto.com/tao61/147500 如需转载请自行联系原作者

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

【 Release Notes】CodePipeline 产品更新

2017年12月22日 CodePipeline全面支持子账号登录以及权限控制,具体操作请参阅帮助文档 https://help.aliyun.com/document_detail/63612.html 新增 Go 语言构建环境,Go语言版本是 v1.9.2。示例代码相关请参阅 https://code.aliyun.com/CodePipeline/go-demo Nodejs 构建环境Nodejs升级到 v8.9.3, yarn同步升级到 v1.3.2。 2017年12月8日 CodePipeline API和SDK全面上线,支持查看项目列表,执行项目,删除项目等。详细使用说明请阅读帮助文档开发指南部分(https://help.aliyun.com/document_detail/62887.html)。 CodePipeline增加

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

产品设计思维:电商产品设计全攻略》一一导读

前 言 为什么要写这本书互联网进入我国也就二十多年,从全国各行业的发展来看,它仍然是一个新兴领域,从互联网到移动互联网,从移动互联网到物联网,万物互联互通,其发展的势头令世人惊叹。最近几年,我国政府更是将“互联网+”等基于互联网的变革提升到了国家战略的地位。作为一个与互联网共生的人,我感到异常荣幸与兴奋,互联网不仅深深地影响了国家、行业的发展格局,同时也对我个人的成长产生了重大的影响。如果让我选出20世纪最伟大的发明,我认为当之无愧的是“互联网”,其影响力将会波及整个21世纪甚至更久远的未来。2011年德国汉诺威博览会上提出了“第四次工业革命”的概念,互联网的价值与影响力由此被提升到了一个战略级高度,我国政府也在工作报告中提出了“互联网+”的战略,我国的绝大部分企业都在基于互联网络进行转型,要么适应互联网时代的变化,要么被互联网革

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

微信推出官方龙虾插件:微信 ClawBot

腾讯宣布正式推出“微信ClawBot”插件,实现龙虾直连。根据介绍,连接后,用户就能通过微信聊天的方式,快速调用自己的“龙虾”高效互动 。 目前,该插件正逐步向用户放量。 具体操作路径为:打开手机微信,点击“我>设置>插件>微信ClawBot”,根据页面提示启用或授权该插件。iOS/Android用户需将微信更新至最新版本,当前鸿蒙版微信暂不支持该功能。

资源下载

更多资源
Mario

Mario

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

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

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文件系统,支持十年生命周期更新。

用户登录
用户注册