本文转载自Spark快速入门指南 – Spark安装与基础使用

Apache Spark 是一个新兴的大数据处理通用引擎,提供了分布式的内存抽象。Spark 正如其名,最大的特点就是快(Lightning-fast),可比 Hadoop MapReduce 的处理速度快 100 倍。此外,Spark 提供了简单易用的 API,几行代码就能实现 WordCount。本教程主要参考官网快速入门教程,介绍了 Spark 的安装,Spark shell 、RDD、Spark SQL、Spark Streaming 等的基本使用。

本教程的具体运行环境如下:

  • CentOS 6.4
  • Spark 1.6
  • Hadoop 2.6.0
  • Java JDK 1.7
  • Scala 2.10.5

准备工作

运行 Spark 需要 Java JDK 1.7,CentOS 6.x 系统默认只安装了 Java JRE,还需要安装 Java JDK,并配置好 JAVA_HOME 变量。此外,Spark 会用到 HDFS 与 YARN,因此请先安装 Hadoop,具体请浏览Hadoop安装教程,在此就不再复述。

安装 Spark

待 Hadoop 安装好之后,我们再开始安装 Spark。

官网下载地址:http://spark.apache.org/downloads.html

本教程选择的是 Spark 1.6.0 版本,选择 package type 为 “Pre-build with user-provided Hadoop [can use with most Hadoop distributions]”,再点击给出的下载连接 http://www.apache.org/dyn/closer.lua/spark/spark-1.6.0/spark-1.6.0-bin-without-hadoop.tgz 就可以下载了,如下图所示:

从官网下载 Spark

Package type

  • Source code: Spark 源码,需要编译才能使用,另外 Scala 2.11 需要使用源码编译才可使用
  • Pre-build with user-provided Hadoop: “Hadoop free” 版,可应用到任意 Hadoop 版本
  • Pre-build for Hadoop 2.6 and later: 基于 Hadoop 2.6 的预先编译版,需要与本机安装的 Hadoop 版本对应。可选的还有 Hadoop 2.4 and later、Hadoop 2.3、Hadoop 1.x,以及 CDH 4。

为方便,本教程选择的是 Pre-build with user-provided Hadoop,简单配置后可应用到任意 Hadoop 版本。

下载后,执行如下命令进行安装:

  1. sudo tar -zxf ~/下载/spark-1.6.0-bin-without-hadoop.tgz -C /usr/local/
  2. cd /usr/local
  3. sudo mv ./spark-1.6.0-bin-without-hadoop/ ./spark
  4. sudo chown -R hadoop:hadoop ./spark # 此处的 hadoop 为你的用户名
Shell 命令

安装后,需要在 ./conf/spark-env.sh 中修改 Spark 的 Classpath,执行如下命令拷贝一个配置文件:

  1. cd /usr/local/spark
  2. cp ./conf/spark-env.sh.template ./conf/spark-env.sh
Shell 命令

编辑 ./conf/spark-env.sh(vim ./conf/spark-env.sh) ,在最后面加上如下一行:

export SPARK_DIST_CLASSPATH=$(/usr/local/hadoop/bin/hadoop classpath)

保存后,Spark 就可以启动、运行了。

运行 Spark 示例

注意,必须安装 Hadoop 才能使用 Spark,但如果使用 Spark 过程中没用到 HDFS,不启动 Hadoop 也是可以的。此外,接下来教程中出现的命令、目录,若无说明,则一般以 Spark 的安装目录(/usr/local/spark)为当前路径,请注意区分。

在 ./examples/src/main 目录下有一些 Spark 的示例程序,有 Scala、Java、Python、R 等语言的版本。我们可以先运行一个示例程序 SparkPi(即计算 π 的近似值),执行如下命令:

  1. cd /usr/local/spark
  2. ./bin/run-example SparkPi
Shell 命令

执行时会输出非常多的运行信息,输出结果不容易找到,可以通过 grep 命令进行过滤(命令中的 2>&1 可以将所有的信息都输出到 stdout 中,否则由于输出日志的性质,还是会输出到屏幕中):

  1. ./bin/run-example SparkPi 2>&1 | grep "Pi is roughly"
Shell 命令

过滤后的运行结果如下图所示,可以得到 π 的 5 位小数近似值 :

从官网下载 Spark

Python 版本的 SparkPi 则需要通过 spark-submit 运行:

  1. ./bin/spark-submit examples/src/main/python/pi.py
Shell 命令

通过 Spark Shell 进行交互分析

Spark shell 提供了简单的方式来学习 API,也提供了交互的方式来分析数据。Spark Shell 支持 Scala 和 Python,本教程选择使用 Scala 来进行介绍。

Scala

Scala 是一门现代的多范式编程语言,志在以简练、优雅及类型安全的方式来表达常用编程模式。它平滑地集成了面向对象和函数语言的特性。Scala 运行于 Java 平台(JVM,Java 虚拟机),并兼容现有的 Java 程序。

Scala 是 Spark 的主要编程语言,如果仅仅是写 Spark 应用,并非一定要用 Scala,用 Java、Python 都是可以的。使用 Scala 的优势是开发效率更高,代码更精简,并且可以通过 Spark Shell 进行交互式实时查询,方便排查问题。

执行如下命令启动 Spark Shell:

  1. ./bin/spark-shell
Shell 命令

启动成功后如图所示,会有 “scala >” 的命令提示符。

成功启动Spark Shell

基础操作

Spark 的主要抽象是分布式的元素集合(distributed collection of items),称为RDD(Resilient Distributed Dataset,弹性分布式数据集),它可被分发到集群各个节点上,进行并行操作。RDDs 可以通过 Hadoop InputFormats 创建(如 HDFS),或者从其他 RDDs 转化而来。

我们从 ./README 文件新建一个 RDD,代码如下(本文出现的 Spark 交互式命令代码中,与位于同一行的注释内容为该命令的说明,命令之后的注释内容表示交互式输出结果):

  1. val textFile = sc.textFile("file:///usr/local/spark/README.md")
  2. // textFile: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[1] at textFile at <console>:27
scala

代码中通过 “file://” 前缀指定读取本地文件。Spark shell 默认是读取 HDFS 中的文件,需要先上传文件到 HDFS 中,否则会有“org.apache.hadoop.mapred.InvalidInputException: Input path does not exist: hdfs://localhost:9000/user/hadoop/README.md”的错误。

上述命令的输出结果如下图所示:

新建RDD

RDDs 支持两种类型的操作

  • actions: 在数据集上运行计算后返回值
  • transformations: 转换, 从现有数据集创建一个新的数据集

下面我们就来演示 count() 和 first() 操作:

  1. textFile.count() // RDD 中的 item 数量,对于文本文件,就是总行数
  2. // res0: Long = 95
  3. textFile.first() // RDD 中的第一个 item,对于文本文件,就是第一行内容
  4. // res1: String = # Apache Spark
scala

接着演示 transformation,通过 filter transformation 来返回一个新的 RDD,代码如下:

  1. val linesWithSpark = textFile.filter(line => line.contains("Spark")) // 筛选出包含 Spark 的行
  2. linesWithSpark.count() // 统计行数
  3. // res4: Long = 17
scala

可以看到一共有 17 行内容包含 Spark,这与通过 Linux 命令 cat ./README.md | grep "Spark" -c 得到的结果一致,说明是正确的。action 和 transformation 可以用链式操作的方式结合使用,使代码更为简洁:

  1. textFile.filter(line => line.contains("Spark")).count() // 统计包含 Spark 的行数
  2. // res4: Long = 17
scala

RDD的更多操作

RDD 的 actions 和 transformations 可用在更复杂的计算中,例如通过如下代码可以找到包含单词最多的那一行内容共有几个单词:

  1. textFile.map(line => line.split(" ").size).reduce((a, b) => if (a > b) a else b)
  2. // res5: Int = 14
scala

代码首先将每一行内容 map 为一个整数,这将创建一个新的 RDD,并在这个 RDD 中执行 reduce 操作,找到最大的数。map()、reduce() 中的参数是 Scala 的函数字面量(function literals,也称为闭包 closures),并且可以使用语言特征或 Scala/Java 的库。例如,通过使用 Math.max() 函数(需要导入 Java 的 Math 库),可以使上述代码更容易理解:

  1. import java.lang.Math
  2. textFile.map(line => line.split(" ").size).reduce((a, b) => Math.max(a, b))
  3. // res6: Int = 14
scala

Hadoop MapReduce 是常见的数据流模式,在 Spark 中同样可以实现(下面这个例子也就是 WordCount):

  1. val wordCounts = textFile.flatMap(line => line.split(" ")).map(word => (word, 1)).reduceByKey((a, b) => a + b) // 实现单词统计
  2. // wordCounts: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[4] at reduceByKey at <console>:29
  3. wordCounts.collect() // 输出单词统计结果
  4. // res7: Array[(String, Int)] = Array((package,1), (For,2), (Programs,1), (processing.,1), (Because,1), (The,1)...)
scala

缓存

Spark 支持在集群范围内将数据集缓存至每一个节点的内存中,可避免数据传输,当数据需要重复访问时这个特征非常有用,例如查询体积小的“热”数据集,或是运行如 PageRank 的迭代算法。调用 cache(),就可以将数据集进行缓存:

  1. linesWithSpark.cache()
scala

Spark SQL 和 DataFrames

Spark SQL 是 Spark 内嵌的模块,用于结构化数据。在 Spark 程序中可以使用 SQL 查询语句或 DataFrame API。DataFrames 和 SQL 提供了通用的方式来连接多种数据源,支持 Hive、Avro、Parquet、ORC、JSON、和 JDBC,并且可以在多种数据源之间执行 join 操作。

下面仍在 Spark shell 中演示一下 Spark SQL 的基本操作,该部分内容主要参考了 Spark SQL、DataFrames 和 Datasets 指南。

Spark SQL 的功能是通过 SQLContext 类来使用的,而创建 SQLContext 是通过 SparkContext 创建的。在 Spark shell 启动时,输出日志的最后有这么几条信息

16/01/16 13:25:41 INFO repl.SparkILoop: Created spark context..
Spark context available as sc.
16/01/16 13:25:41 INFO repl.SparkILoop: Created sql context..
SQL context available as sqlContext.

这些信息表明 SparkContent 和 SQLContext 都已经初始化好了,可通过对应的 sc、sqlContext 变量直接进行访问。

使用 SQLContext 可以从现有的 RDD 或数据源创建 DataFrames。作为示例,我们通过 Spark 提供的 JSON 格式的数据源文件 ./examples/src/main/resources/people.json 来进行演示,该数据源内容如下:

  1. {"name":"Michael"}
  2. {"name":"Andy", "age":30}
  3. {"name":"Justin", "age":19}
json

执行如下命令导入数据源,并输出内容:

  1. val df = sqlContext.read.json("file:///usr/local/spark/examples/src/main/resources/people.json")
  2. // df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
  3. df.show() // 输出数据源内容
  4. // +----+-------+
  5. // | age| name|
  6. // +----+-------+
  7. // |null|Michael|
  8. // | 30| Andy|
  9. // | 19| Justin|
  10. // +----+-------+
scala

接着,我们来演示 DataFrames 处理结构化数据的一些基本操作:

  1. df.select("name").show() // 只显示 "name" 列
  2. // +-------+
  3. // | name|
  4. // +-------+
  5. // |Michael|
  6. // | Andy|
  7. // | Justin|
  8. // +-------+
  9. df.select(df("name"), df("age") + 1).show() // 将 "age" 加 1
  10. // +-------+---------+
  11. // | name|(age + 1)|
  12. // +-------+---------+
  13. // |Michael| null|
  14. // | Andy| 31|
  15. // | Justin| 20|
  16. // +-------+---------+
  17. df.filter(df("age") > 21).show() # 条件语句
  18. // +---+----+
  19. // |age|name|
  20. // +---+----+
  21. // | 30|Andy|
  22. // +---+----+
  23. df.groupBy("age").count().show() // groupBy 操作
  24. // +----+-----+
  25. // | age|count|
  26. // +----+-----+
  27. // |null| 1|
  28. // | 19| 1|
  29. // | 30| 1|
  30. // +----+-----+
scala

当然,我们也可以使用 SQL 语句来进行操作:

  1. df.registerTempTable("people") // 将 DataFrame 注册为临时表 people
  2. val result = sqlContext.sql("SELECT name, age FROM people WHERE age >= 13 AND age <= 19") // 执行 SQL 查询
  3. result.show() // 输出结果
  4. // +------+---+
  5. // | name|age|
  6. // +------+---+
  7. // |Justin| 19|
  8. // +------+---+
scala

更多的功能可以查看完整的 DataFrames API ,此外 DataFrames 也包含了丰富的 DataFrames Function 可用于字符串处理、日期计算、数学计算等。

Spark Streaming

流计算除了使用 Storm 框架,使用 Spark Streaming 也是一个很好的选择。基于 Spark Streaming,可以方便地构建可拓展、高容错的流计算应用程序。Spark Streaming 使用 Spark API 进行流计算,这意味着在 Spark 上进行流处理与批处理的方式一样。因此,你可以复用批处理的代码,使用 Spark Streaming 构建强大的交互式应用程序,而不仅仅是用于分析数据。

下面以一个简单的 Spark Streaming 示例(基于流的单词统计)来演示一下 Spark Streaming:本地服务器通过 TCP 接收文本数据,实时输出单词统计结果。该部分内容主要参考了 Spark Streaming 编程指南。

运行该示例需要 Netcat(在网络上通过 TCP 或 UDP 读写数据),CentOS 6.x 系统中默认没有安装,经过测试,如果通过 yum 直接安装,运行时会有 “nc: Protocol not available” 的错误,需要下载较低版本的 nc 才能正常使用。我们选择 Netcat 0.6.1 版本,在终端中运行如下命令进行安装:

  1. wget http://downloads.sourceforge.net/project/netcat/netcat/0.6.1/netcat-0.6.1-1.i386.rpm -O ~/netcat-0.6.1-1.i386.rpm # 下载
  2. sudo rpm -iUv ~/netcat-0.6.1-1.i386.rpm # 安装
Shell 命令

安装好 NetCat 之后,使用如下命令建立本地数据服务,监听 TCP 端口 9999:

  1. # 记为终端 1
  2. nc -l -p 9999
Shell 命令

启动后,该端口就被占用了,需要开启另一个终端运行示例程序,执行如下命令:

  1. # 需要另外开启一个终端,记为终端 2,然后运行如下命令
  2. /usr/local/spark/bin/run-example streaming.NetworkWordCount localhost 9999
Shell 命令

接着在终端 1 中输入文本,在终端 2 中就可以实时看到单词统计结果了。

Spark Streaming 的内容较多,本教程就简单介绍到这,更详细的内容可查看官网教程。最后需要关掉终端 2,并按 ctrl+c 退出 终端 1 的Netcat。

独立应用程序(Self-Contained Applications)

接着我们通过一个简单的应用程序 SimpleApp 来演示如何通过 Spark API 编写一个独立应用程序。使用 Scala 编写的程序需要使用 sbt 进行编译打包,相应的,Java 程序使用 Maven 编译打包,而 Python 程序通过 spark-submit 直接提交。

应用程序代码

在终端中执行如下命令创建一个文件夹 sparkapp 作为应用程序根目录:

  1. cd ~ # 进入用户主文件夹
  2. mkdir ./sparkapp # 创建应用程序根目录
  3. mkdir -p ./sparkapp/src/main/scala # 创建所需的文件夹结构
Shell 命令

在 ./sparkapp/src/main/scala 下建立一个名为 SimpleApp.scala 的文件(vim ./sparkapp/src/main/scala/SimpleApp.scala),添加代码如下:

  1. /* SimpleApp.scala */
  2. import org.apache.spark.SparkContext
  3. import org.apache.spark.SparkContext._
  4. import org.apache.spark.SparkConf
  5. object SimpleApp {
  6. def main(args: Array[String]) {
  7. val logFile = "file:///usr/local/spark/README.md" // Should be some file on your system
  8. val conf = new SparkConf().setAppName("Simple Application")
  9. val sc = new SparkContext(conf)
  10. val logData = sc.textFile(logFile, 2).cache()
  11. val numAs = logData.filter(line => line.contains("a")).count()
  12. val numBs = logData.filter(line => line.contains("b")).count()
  13. println("Lines with a: %s, Lines with b: %s".format(numAs, numBs))
  14. }
  15. }
scala

该程序计算 /usr/local/spark/README 文件中包含 “a” 的行数 和包含 “b” 的行数。代码第8行的 /usr/local/spark 为 Spark 的安装目录,如果不是该目录请自行修改。不同于 Spark shell,独立应用程序需要通过 val sc = new SparkContext(conf) 初始化 SparkContext,SparkContext 的参数 SparkConf 包含了应用程序的信息。

该程序依赖 Spark API,因此我们需要通过 sbt 进行编译打包。在 ./sparkapp 中新建文件 simple.sbt(vim ./sparkapp/simple.sbt),添加内容如下,声明该独立应用程序的信息以及与 Spark 的依赖关系:

name := "Simple Project"version := "1.0"scalaVersion := "2.10.5"libraryDependencies += "org.apache.spark" %% "spark-core" % "1.6.0"

文件 simple.sbt 需要指明 Spark 和 Scala 的版本。启动 Spark shell 的过程中,当输出到 Spark 的符号图形时,可以看到相关的版本信息。

查看 Spark 和 Scala 的版本信息

安装 sbt

Spark 中没有自带 sbt,需要手动安装 sbt,我们选择安装在 /usr/local/sbt 中:

  1. sudo mkdir /usr/local/sbt
  2. sudo chown -R hadoop /usr/local/sbt # 此处的 hadoop 为你的用户名
  3. cd /usr/local/sbt
Shell 命令

经笔者测试,按官网教程安装 sbt 0.13.9 后,使用时可能存在网络问题,无法下载依赖包,导致 sbt 无法正常使用,需要进行一定的修改。为方便,请使用笔者修改后的版本,下载地址:http://pan.baidu.com/s/1eRyFddw。

下载后,执行如下命令拷贝至 /usr/local/sbt 中:

  1. cp ~/下载/sbt-launch.jar .
Shell 命令

接着在 /usr/local/sbt 中创建 sbt 脚本(vim ./sbt),添加如下内容:

  1. #!/bin/bash
  2. SBT_OPTS="-Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256M"
  3. java $SBT_OPTS -jar `dirname $0`/sbt-launch.jar "$@"
Shell 命令

保存后,为 ./sbt 脚本增加可执行权限:

  1. chmod u+x ./sbt
Shell 命令

最后检验 sbt 是否可用(首次运行会处于 “Getting org.scala-sbt sbt 0.13.9 …” 的下载状态,请耐心等待。笔者等待了 7 分钟才出现第一条下载提示):

  1. ./sbt sbt-version
Shell 命令

下载过程中可能会类似 “Server access Error: java.security.ProviderException: java.security.KeyException url=https://jcenter.bintray.com/org/scala-sbt/precompiled-2_9_3/0.13.9/precompiled-2_9_3-0.13.9.jar” 的错误,可以忽略。可再执行一次 ./sbt sbt-version,只要能得到如下图的版本信息就没问题:

验证 sbt 是否可用

如果由于网络问题无法下载依赖,导致 sbt 无法正确运行的话,可以下载笔者提供的离线依赖包 sbt-0.13.9-repo.tar.gz 到本地中(依赖包的本地位置为 ~/.sbt 和 ~/.ivy2,检查依赖关系时,首先检查本地,本地未找到,再从网络中下载),下载地址:http://pan.baidu.com/s/1sjTQ8yD。下载后,执行如下命令解压依赖包:

  1. tar -zxf ~/下载/sbt-0.13.9-local-repo.tar.gz ~
Shell 命令

通过这个方式,一般可以解决依赖包缺失的问题(读者提供的依赖包仅适合于 Spark 1.6 版本,不同版本依赖关系不一样)。

如果对 sbt 存在的网络问题以及如何解决感兴趣,请点击下方查看。

点击查看:解决 sbt 无法下载依赖包的问题

使用 sbt 打包 Scala 程序

为保证 sbt 能正常运行,先执行如下命令检查整个应用程序的文件结构:

  1. cd ~/sparkapp
  2. find .
Shell 命令

文件结构应如下图所示:

SimpleApp的文件结构

接着,我们就可以通过如下代码将整个应用程序打包成 JAR(首次运行同样需要下载依赖包,如果这边遇到网络问题无法成功,也请下载上述安装 sbt 提到的离线依赖包 sbt-0.13.9-repo.tar.gz ):

  1. /usr/local/sbt/sbt package
Shell 命令

打包成功的话,会输出如下图内容:

SimpleApp的文件结构

生成的 jar 包的位置为 ~/sparkapp/target/scala-2.10/simple-project_2.10-1.0.jar。

通过 spark-submit 运行程序

最后,我们就可以将生成的 jar 包通过 spark-submit 提交到 Spark 中运行了,命令如下:

  1. /usr/local/spark/bin/spark-submit --class "SimpleApp" ~/sparkapp/target/scala-2.10/simple-project_2.10-1.0.jar
  2. # 输出信息太多,可以通过如下命令过滤直接查看结果
  3. /usr/local/spark/bin/spark-submit --class "SimpleApp" ~/sparkapp/target/scala-2.10/simple-project_2.10-1.0.jar 2>&1 | grep "Lines with a:"
Shell 命令

最终得到的结果如下:

Lines with a: 58, Lines with b: 26

自此,你就完成了你的第一个 Spark 应用程序了。

Spark快速入门指南 – Spark安装与基础使用相关推荐

  1. Spark快速入门指南

    - Spark是什么? Spark is a MapReduce-like cluster computing framework designed to support  low-latency i ...

  2. 【51单片机快速入门指南】1:基础知识和工程创建

    目录 简介 命名规则 51单片机的数据类型 总表 扩展数据类型 stdint.h 存储器类型关键字 烧录工具 工程的创建 创建项目 添加C文件 配置工程 存储模式配置 输出配置 代码优化配置 编译 烧 ...

  3. 【51单片机快速入门指南】6.4:DHT11、DHT22单总线温湿度传感器

    目录 硬知识 DHT11 DHT22 通信协议 读取步骤 数据解读 DHT11 DHT22 示例程序 DHT11_22.c DHT11_22.h 测试程序 main.c 实验现象 DHT11 DHT2 ...

  4. 【51单片机快速入门指南】4.6:I2C 与 PCF8563实时时钟日历芯片

    目录 硬知识 概述 特性 功能描述 报警功能模式 定时器模式 CLKOUT输出 复位低电压检测器和时钟监视器 低电压检测器和时钟监视器 寄存器结构 寄存器概述 BCD编码格式寄存器概述 Control ...

  5. 【51单片机快速入门指南】6.3:DS18B20 单总线数字温度计的多路读取

    目录 硬知识 DS18B20介绍 时序 初始化时序 写时序 读时序 命令 ROM 操作命令 ROM 搜索举例 存贮器操作命令 示例程序 DS18B20.c DS18B20.h 测试程序 定时器中断服务 ...

  6. 【51单片机快速入门指南】6.1:LCD1602的八线、四线控制及自定义符号,完美兼容Proteus仿真

    目录 硬知识 显示特性 接口定义 操作时序 写操作时序 读操作时序 寄存器 忙标志位BF 地址计数器(AC) 显示数据寄存器(DDRAM) CGROM CGRAM 指令 清屏指令 光标归位指令 进入模 ...

  7. 【51单片机快速入门指南】5.3:SPI控制晶联讯JLX12864G_08602 LCD屏幕

    目录 示例程序 JLX12864G_08602.c JLX12864G_08602.h JLX12864G_08602_Font.c JLX12864G_08602_Font.h 测试程序 main. ...

  8. 【51单片机快速入门指南】5.1:SPI与DS1302时钟芯片

    目录 硬知识 DS1302 简介 DS1302 使用 控制寄存器 日历/时钟寄存器 DS1302 的读写时序 电路设计 示例程序 DS1302.c DS1302.h 测试程序 main.c 实验现象 ...

  9. 【51单片机快速入门指南】4.5:I2C 与 TCA6416实现双向 IO 扩展

    目录 硬知识 IO 扩展芯片 TCA6416A TAC6416A 的寄存器 IO 输入寄存器 IO 输出寄存器 IO 反相寄存器 IO 方向寄存器 TCA6416A 的操作 TCA6416A 写数据 ...

最新文章

  1. Gridview][UpdateCommand的写法要点]
  2. Javascript获取select下拉框选中的的值以及索引
  3. 收图一张: android 架构图
  4. 更新 Ubuntu 系统,避免报错「校验和不符」
  5. python 字符串去重从小到大排列_110道题整理(1-60)
  6. mysql 5.1 互为主从,mysql数据库互为主从配置方法分享
  7. 自动初始化 git Bash脚本
  8. 双时隙的工作原理_双作用叶片泵工作原理是怎样的?作为8年工程师都没了解这么深...
  9. linux shell 特殊符号的表示
  10. python爬虫定时爬取_如何用框架给python爬虫定时?
  11. Ubuntu 16 安装JDK1.8
  12. Java 模块化技术演进和对现有应用微服务化的意义
  13. Python连载7-time包的其他函数
  14. 虚拟文件系统VSF的作用
  15. RFM 客户价值分析
  16. Spring学习之浅析refresh()执行逻辑
  17. HTML5网页中的链接
  18. 特岗计算机考试面试,你应该知道的特岗教师面试注意事项!快来收藏吧!
  19. 在Windows下安装Vim编辑器
  20. net项目使用花生壳,Cpolar进行内网穿透

热门文章

  1. 棋牌游戏服务器架构: 详细设计(三) 数据库设计
  2. cin、cin.get()、cin.getline()、getline()、gets()等函数的用法
  3. android 获取程序,Android获取桌面应用程序
  4. 东北农业大计算机排名,黑龙江高校排名更新,东北林大排名第3,东油排名第8...
  5. swagger内部类_API管理工具Swagger介绍及Springfox原理分析
  6. niosii spi 外部_基于Nios_II的DMA传输总结
  7. c mysql5.7_CentOS7下MySQL5.7的三种安装方式详解
  8. 实体 联系 模型mysql_数据库系统概念读书笔记――实体-联系模型_MySQL
  9. linux 命令分类,常用linux 命令分类整理(篇一)
  10. mysql 导出 没有函数_没有MYSQL FILE函数的CSV导出