当R语言遇上Docker

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹(Conan), 程序员R,Nodejs,Java
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-docker

r-docker

前言

R语言作为数据分析的工具,已经广泛被大家所接受并使用。但要把R语言项目工程化,部署到生产环境,提供在线用户使用却是难度很大的。主要原因就是R本身是单线程的,不支持并行处理。

当R遇到上了Docker会发生什么呢?本文将做详细的解释。

目录

  1. 当R遇到上了Docker
  2. 用Docker来管理R的程序

1. 当R遇到上了Docker

前言中提到,R运行时环境是单线程的,不支持并行处理,所以我们很难把R直接应用到生产环境中。当R遇到上了Docker,就出现了一个可以解决上面问题的方案。

通过Docker的容器化技术,把R的应用Docker化。每当用户发出请求,程序可以自动地在线启动一个Docker化的容器,来装载R的任务,部署,运行,计算,并返回结果。

r-docker2

从极端的情况考虑,如果要面对100万次并发的请求,我们需要启动100万个Docker的容器,每次容器单独执行自己的任务。但这种情况是要避免的,因为R本身来说,是做数据任务的,并不善于处理web是请求。如果可以把用户的大批量请求,转换成少量的数据计算的任务,那么这个设计就完美地解决了R由于并发而不能被工程化的问题。

r-docker3

比如,针对大量用户的重复性计算,把R的计算结果保存在缓存池中。

2. 用Docker来管理R的程序

设计方案定好,接下来就是就是动手实践了。

操作过程分成4步:

  • 1. 要有Docker的环境
  • 2. 找到第三方成熟的R语言的Docker镜像
  • 3. 把我们的R程序装进去
  • 4. 打包,运行,上传

1. Docker的环境。

安装Docker环境,就不在本文中介绍了,Docker环境的安装,请参考文章在Ubuntu中安装Docker

2. 找到第三方成熟的R语言的Docker镜像。

在docker hub中,搜索关键字 r, 共有535条结果。我们直接选用,排在第一位的r-base做为Docker容器的基础就行了。

docker-r

从仓库中,下载r-base镜像。


# 下载r-base镜像,大概300mb要下一会儿
~ sudo docker pull r-base
Using default tag: latest
latest: Pulling from library/r-base
9cd73496e13f: Pull complete 
f10af350cd29: Pull complete 
eea7b33eea97: Pull complete 
c91475e50472: Pull complete 
1e5e5f6785b4: Pull complete 
8c4091261ff6: Pull complete 
Digest: sha256:5f06e5a89cc64cbc513d02a8c650ea8bcbf0499795add57d18793069795c6f8d
Status: Downloaded newer image for r-base:latest

# 查看本地镜像列表
~ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
bsspirit/fensme     latest              8496b10e857a        2 hours ago         182.8 MB
ubuntu              latest              f8d79ba03c00        2 weeks ago         126.4 MB
r-base              latest              e2abe45e47d7        3 weeks ago         959.9 MB

3. 把我们的R程序装进去。

把R程序放进去之前,我们要先通过命令交互的方法,看看r-base容器中,是什么样子的。

运行r-base容器,会直接打开一个R的命令行窗口。


~ sudo docker run -ti --rm r-base

R version 3.3.1 (2016-06-21) -- "Bug in Your Hair"
Copyright (C) 2016 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> 

我们通过执行R语言程序,了解一下Docker环境的信息。


# R程序启动路径
> getwd()
[1] "/"

# 当前路径中的目录
> dir()
 [1] "bin"   "boot"  "dev"   "etc"   "home"  "lib"   "lib64" "media" "mnt"  
[10] "opt"   "proc"  "root"  "run"   "sbin"  "srv"   "sys"   "tmp"   "usr"  
[19] "var"  

# 用户身份
> system('whoami')
root

# 系统信息
> sessionInfo()
R version 3.3.1 (2016-06-21)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux stretch/sid

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base    

# R语言版本
> R.Version()
$platform
[1] "x86_64-pc-linux-gnu"

$arch
[1] "x86_64"

$os
[1] "linux-gnu"

$system
[1] "x86_64, linux-gnu"

$status
[1] ""

$major
[1] "3"

$minor
[1] "3.1"

$year
[1] "2016"

$month
[1] "06"

$day
[1] "21"

$`svn rev`
[1] "70800"

$language
[1] "R"

$version.string
[1] "R version 3.3.1 (2016-06-21)"

$nickname
[1] "Bug in Your Hair"

通过上面的几条命令,r-base容器的系统环境已经掌握。接下来,我们可以写一个R的算法,让这个程序在r-base的容器中运行。退出容器。

新建项目目录


~ mkdir ret && cd ret
~ pwd
/home/conan/ret

我们用a.r写一个计算万科(WANK)000002.SZ股票收益率的程序。数据从yahoo财经进行采集,R语言用于收益率计算,计算结果通过在控制台打印。

wanke

新建R语言算法文件,a.r。


~ vi a.r

install.packages(c('quantmod','PerformanceAnalytics'))
library(quantmod)
library(PerformanceAnalytics)
VANKE<-getSymbols("000002.SZ",auto.assign = FALSE, from = '2010-10-10')
close<-VANKE$'000002.SZ.Close'
ret<-CalculateReturns(close, method = "discrete")
cumret<-cumprod((ret+1)[-1])-1
VANKE_ret<-merge(close,ret,cumret)
names(VANKE_ret)<-c('close','ret','cumret')
print(tail(VANKE_ret))

我们先在本机中运行这段代码。


> 安装类库
> install.packages(c('quantmod','PerformanceAnalytics'))
> # 装载类库
> library(quantmod)
> library(PerformanceAnalytics)
> 
> # 获得VANKE每K线数据
> VANKE<-getSymbols("000002.SZ",auto.assign = FALSE, from = '2010-10-10')
>
> # 收盘价
> close<-VANKE$'000002.SZ.Close'
> 
> # 每日收益率 = (T日收盘价 - (T-1日收盘价))/T-1日收盘价
> ret<-CalculateReturns(close, method = "discrete")
> 
> # 每日累计收盘率 = (T日收益率+1)*(T+1日收益率+1)*...*(T+N日收益率+1)-1
> cumret<-cumprod((ret+1)[-1])-1
> 
> # 合并数据集
> VANKE_ret<-merge(close,ret,cumret)
> names(VANKE_ret)<-c('close','ret','cumret')
> 
> # 查看VANKE最近几日收益率
> print(tail(VANKE_ret))
           close          ret   cumret
2016-08-18 25.58 -0.010444874 1.893665
2016-08-19 24.59 -0.038702111 1.781674
2016-08-22 24.70  0.004473363 1.794118
2016-08-23 24.70  0.000000000 1.794118
2016-08-24 23.99 -0.028744939 1.713801
2016-08-25 23.54 -0.018757816 1.662896

接下来,编写Dockerfile通过加载外部文件的方法。


~ vi Dockerfile

FROM r-base
COPY . /usr/local/src/myscripts
WORKDIR /usr/local/src/myscripts
CMD ["Rscript", "a.r"]

4. 打包,运行,上传。

打包,生成Docker的镜像文件a.r。


~ sudo docker build -t a.r .
[sudo] password for conan: 
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM r-base
 ---> e2abe45e47d7
Step 2 : COPY . /usr/local/src/myscripts
 ---> e6ef215d3683
Removing intermediate container aaabfdfe92ab
Step 3 : WORKDIR /usr/local/src/myscripts
 ---> Running in e3f2c65b947a
 ---> c667baee06bf
Removing intermediate container e3f2c65b947a
Step 4 : CMD Rscript a.r
 ---> Running in dc040bbdd3b9
 ---> 9a48d6dc02fe
Removing intermediate container dc040bbdd3b9
Successfully built 9a48d6dc02fe

启动r-base容器,运行a.r的脚本。


~  sudo docker run a.r

看着大段的日志从眼前飞过,计算出了万科的收益率的结果。

docker-r2

最后一步,不忘上传到docker hub,仓库地址为:https://hub.docker.com/r/bsspirit/ret/

上传镜像的操作命令:


~ sudo docker tag 9a48d6dc02fe bsspirit/ret
~ sudo docker push bsspirit/ret

如果你有Docker的环境,你可以直接用下面的命令,进行容器下载和运行。


~ sudo docker run bsspirit/ret

R和Docker的相遇,给R提供了并行计算施展的空间。Docker和R的相遇,也让Docker能够切入数据处理领域,有了更广阔的应用场景。感谢R和Docker给程序员的世界,带来了新的机会!!

转载请注明出处:
http://blog.fens.me/r-docker

打赏作者

This entry was posted in R语言实践, 虚拟化实践, 金融

  • 每篇文章都有对应的图片,真好。是有什么工具推荐么