您正在查看: 后台开发 分类下的文章

php页面不能被解析成网页,而是直接显示了页面代码

Overview

之前安装过很多次的phpMyAdmin,但最近一次安装时,出现了一个之前从来没遇到的问题:访问phpMyAdmin时,主页的php页面会被不能被解析成网页,而是直接显示了页面代码。

问题描述

文字描述已经比较清楚了,就不截图了。如果想看截图,参考 phpmyadmin showing php script [duplicate]

对比之前的安装流程,发现这次安装Apache2时,php还没装(这个一般装Ubuntu系统时都会自动装上,这次居然没装,所以才会碰到这么少见的错误),所以php是在Apache2后面安装的。这样的问题在于,当Apache2安装时,没有检测到系统有php,所以就以为用户安装Apache2不是为了运行php网站(尽管Apache2最常见的应用就是做php网站容器,但实际上可以用作多种语言网站的容器,比如perlCGI程序,但需要手动配置添加专门的模块,使Apache2支持perlCGI程序,不然你通过Apache2访问你的perl页面,也会被直接显示为代码,而不是页面,参见配置Apache2服务器以CGI方式运行Perl程序),也就没有安装配置支持php的模块。

解决方案

  • 先安装php,再安装Apache2,这样Apache2安装时,会检测到php,然后自动安装配置好支持php网站的模块。

  • 如果不幸顺序反了(后面又发现,好像跟顺序无关,还是有可能报这个错误 =。=),那使用下面的命令手动给Apache2安装支持php的模块

    先用下面的命令看看你装的php版本:

    php --version
    

    出现下面的信息:

    PHP 7.0.32-0ubuntu0.16.04.1 (cli) ( NTS )
    Copyright (c) 1997-2017 The PHP Group
    Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
        with Zend OPcache v7.0.32-0ubuntu0.16.04.1, Copyright (c) 1999-2017, by Zend    Technologies
    

    如果你装的是php 7.0,那通过下面的命令

    sudo apt-get install libapache2-mod-php7.0
    

    然后重启Apache2

    sudo service apache2 restart
    

    就可以了。

参考文献

FastDFS分布式文件系统在服务器集群上的安装部署

Overview

到目前为止,我们手里已经有了10台服务器了。之前一直说要把这些服务器搭建一个分布式文件系统,现在条件终于成熟了。这些服务器预装的系统大多数是Ubuntu16.04LTS发行版的Linux,少部分是Ubuntu14.04LTS。这次我们选择5台服务器,1feagen(118.138.241.39)服务器作为tracker4台服务器(Bastion3(118.138.240.146),Bastion4(118.138.233.74),Bastion6(118.138.233.26),POSSUM(118.138.233.27))作为storage。这里会记录下FastDFS分布式文件系统在Ubuntu16.04上的安装部署过程的细节。

5台服务器都要安装,只是配置文件稍有不同。

1.必备软件

  • FastDFS
    这个去GitHub上面下载源码:FastDFS
  • libfastcommon
    这个仍然要去GitHub上面下载源码:libfastcommon

这两个Zip包用wget或者在本地下载上传至服务器均可。

2.libfastcommon的安装

首先解压libfastcommon-master.zip包:

unzip libfastcommon-master.zip

进入这个文件夹:

cd libfastcommon-master/

依次输入如下命令:

sudo ./make.sh
sudo ./make.sh install

输入第二条命令之后,会有如下显示:

mkdir -p /usr/lib64
mkdir -p /usr/lib
install -m 755 libfastcommon.so /usr/lib64
install -m 755 libfastcommon.so /usr/lib
mkdir -p /usr/include/fastcommon
install -m 644 common_define.h hash.h chain.h logger.h base64.h shared_func.h pthread_func.h ini_file_reader.h _os_define.h sockopt.h sched_thread.h http_func.h md5.h local_ip_func.h avl_tree.h ioevent.h ioevent_loop.h fast_task_queue.h fast_timer.h process_ctrl.h fast_mblock.h connection_pool.h fast_mpool.h fast_allocator.h fast_buffer.h skiplist.h multi_skiplist.h flat_skiplist.h skiplist_common.h system_info.h fast_blocked_queue.h php7_ext_wrapper.h id_generator.h char_converter.h char_convert_loader.h /usr/include/fastcommon

可以看到libfastcommon.so安装到了/usr/lib64.
下面,我们需要为两个文件创建软链接,指向FastDFS主程序的lib目录:

sudo ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
sudo ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so
sudo ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
sudo ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so

3.FastDFS的安装

解压fastdfs-master.zip文件:

unzip fastdfs-master.zip

进入FastDFS源码根目录:

cd fastdfs-master

依次输入下面两条命令:

sudo ./make.sh
sudo ./make.sh install

安装完成之后,所有的可执行文件都被放在了/usr/bin/目录下面,可以用下面的命令查看:

ls /usr/bin/fdfs*

显示共有14个文件:

/usr/bin/fdfs_appender_test   
/usr/bin/fdfs_download_file  
/usr/bin/fdfs_test1
/usr/bin/fdfs_appender_test1  
/usr/bin/fdfs_file_info      
/usr/bin/fdfs_trackerd
/usr/bin/fdfs_append_file     
/usr/bin/fdfs_monitor        
/usr/bin/fdfs_upload_appender
/usr/bin/fdfs_crc32           
/usr/bin/fdfs_storaged       
/usr/bin/fdfs_upload_file
/usr/bin/fdfs_delete_file     
/usr/bin/fdfs_test

4. 配置FastDFS

配置文件在目录/etc/fdfs下,查看一下:

ls /etc/fdfs

显示如下:

client.conf.sample  storage.conf.sample  storage_ids.conf.sample  tracker.conf.sample

4.1 创建跟踪器和存储节点的配置文件

cd /etc/fdfs
sudo cp tracker.conf.sample tracker.conf
sudo cp storage.conf.sample storage.conf

4.2 修改tracker配置文件

feagen(118.138.241.39)服务器中修改tracker配置文件如下:

sudo vim /etc/fdfs/tracker.conf

可以看到如下显示:

# the base path to store data and log files
base_path=/home/yuqing/fastdfs

这行改成如下内容:

base_path=/feagen/fastdfs/tracker

这种配置文件,注意等号两边不能有空格。且上面的目录必须是真实存在的。
启动tracker

sudo fdfs_trackerd /etc/fdfs/tracker.conf start

查看监听端口:

sudo netstat -unltp|grep fdfs

如果显示如下,则证明tracker启动成功:

tcp        0      0 0.0.0.0:22122           0.0.0.0:*               LISTEN      6951/fdfs_trackerd

4.3 修改storage配置文件

Bastion3(118.138.240.146)服务器中,修改storage配置文件如下:

sudo vim /etc/fdfs/storage.conf

可以看到如下显示:

group_name=group1
base_path=/home/yuqing/fastdfs
store_path0=/home/yuqing/fastdfs
tracker_server=192.168.209.121:22122

修改为:

group_name=group1
base_path=/bastion3_cache/fastdfs/storage
store_path0=/bastion3_cache/fastdfs/storage
tracker_server=118.138.241.39:22122

Bastion4(118.138.233.74)服务器中,修改storage配置文件如下:

sudo vim /etc/fdfs/storage.conf

可以看到如下显示:

group_name=group1
base_path=/home/yuqing/fastdfs
store_path0=/home/yuqing/fastdfs
tracker_server=192.168.209.121:22122

修改为:

group_name=group1
base_path=/bastion4_cache/fastdfs/storage
store_path0=/bastion4_cache/fastdfs/storage
tracker_server=118.138.241.39:22122

Bastion6(118.138.233.26)服务器中,修改storage配置文件如下:

sudo vim /etc/fdfs/storage.conf

可以看到如下显示:

group_name=group1
base_path=/home/yuqing/fastdfs
store_path0=/home/yuqing/fastdfs
tracker_server=192.168.209.121:22122

修改为:

group_name=group1
base_path=/bastion6_cache/fastdfs/storage
store_path0=/bastion6_cache/fastdfs/storage
tracker_server=118.138.241.39:22122

POSSUM(118.138.233.27)服务器中,修改storage配置文件如下:

sudo vim /etc/fdfs/storage.conf

可以看到如下显示:

group_name=group1
base_path=/home/yuqing/fastdfs
store_path0=/home/yuqing/fastdfs
tracker_server=192.168.209.121:22122

修改为:

group_name=group1
base_path=/possum/fastdfs/storage
store_path0=/possum/fastdfs/storage
tracker_server=118.138.241.39:22122

启动storage服务:

sudo fdfs_storaged /etc/fdfs/storage.conf start

显示如下,即代表成功启动:

process fdfs_storaged already running, pid: 28250

查看监听端口:

sudo netstat -unltp|grep fdfs

如果显示如下,则证明storage启动成功:

tcp        0      0 0.0.0.0:23000           0.0.0.0:*               LISTEN      28250/fdfs_storaged

如果没有显示,则有可能是storage启动失败。

那么我们以Bastion6服务器为例,查看启动日志:

tail /bastion6_cache/fastdfs/storage/logs/storaged.log

如果显示如下,代表启动失败:

[2018-05-13 19:56:31] ERROR - file: storage_ip_changed_dealer.c, line: 186, connect to tracker server 118.138.2
40.146:22122 fail, errno: 110, error info: Connection timed out

连接超时;
如果显示如下,代表启动成功:

[2018-05-14 12:59:40] INFO - file: tracker_client_thread.c, line: 310, successfully connect to tracker server 118.138.240.146:22122, as a tracker client, my ip is 118.138.233.26
[2018-05-14 13:00:10] INFO - file: tracker_client_thread.c, line: 1263, tracker server 118.138.240.146:22122, set tracker leader: 118.138.240.146:22122
[2018-05-14 13:03:06] INFO - file: storage_sync.c, line: 2733, successfully connect to storage server 118.138.233.74:23000, continuous fail count: 16
[2018-05-14 13:03:41] INFO - file: storage_sync.c, line: 2733, successfully connect to storage server 118.138.233.74:23000

连接成功。

超时解读:
之前跟Chris讨论的时候,刚开始以为这几天服务器都是Monash云服务器中心的,属于内网,所以相互之间的端口是不用开的,实验之后才知道不开端口是不行的。后来联系Jerico开开3个端口之后,才连接成功。这3个端口分别是22122888823000

  • 22122:代表tracker服务端口;
  • 8888:代表HTTP协议端口,网页上传下载文件需要这个端口;
  • 23000:代表storage服务端口。

至此,storage存储节点安装成功。

4.4 查看所有存储节点信息

所有存储节点都启动之后,在任意一台storage上面用下面命令,查看集群状态信息:

sudo /usr/bin/fdfs_monitor /etc/fdfs/storage.conf

显示如下:

[2018-05-24 01:27:18] DEBUG - base_path=/bastion6_cache/fastdfs/storage, connect_timeout=10, network_timeout=60, tracker_server_count=1, anti_steal_token=0, anti_steal_secret_key length=0, use_connection_pool=0, g_connection_pool_max_idle_time=3600s, use_storage_id=0, storage server id count: 0

server_count=1, server_index=0

tracker server is 118.138.241.39:22122

group count: 1

Group 1:
group name = group1
disk total space = 100665 MB
disk free space = 72339 MB
trunk free space = 0 MB
storage server count = 4
active server count = 4
storage server port = 23000
storage HTTP port = 8888
store path count = 1
subdir count per path = 256
current write server index = 0
current trunk file id = 0

    Storage 1:
        id = 118.138.233.26
        ip_addr = 118.138.233.26 (vm-118-138-233-26.erc.monash.edu.au)  ACTIVE
        http domain = 
        version = 5.12
        join time = 2018-05-13 19:55:46
        up time = 2018-05-20 00:51:17
        total storage = 483679 MB
        free storage = 452554 MB
        upload priority = 10
        store_path_count = 1
        subdir_count_per_path = 256
        storage_port = 23000
        storage_http_port = 8888
        current_write_path = 0
        source storage id = 
        if_trunk_server = 0
        connection.alloc_count = 256
        connection.current_count = 3
        connection.max_count = 3
        total_upload_count = 1
        success_upload_count = 1
        total_append_count = 0
        success_append_count = 0
        total_modify_count = 0
        success_modify_count = 0
        total_truncate_count = 0
        success_truncate_count = 0
        total_set_meta_count = 0
        success_set_meta_count = 0
        total_delete_count = 0
        success_delete_count = 0
        total_download_count = 0
        success_download_count = 0
        total_get_meta_count = 0
        success_get_meta_count = 0
        total_create_link_count = 0
        success_create_link_count = 0
        total_delete_link_count = 0
        success_delete_link_count = 0
        total_upload_bytes = 87026
        success_upload_bytes = 87026
        total_append_bytes = 0
        success_append_bytes = 0
        total_modify_bytes = 0
        success_modify_bytes = 0
        stotal_download_bytes = 0
        success_download_bytes = 0
        total_sync_in_bytes = 11288
        success_sync_in_bytes = 11288
        total_sync_out_bytes = 0
        success_sync_out_bytes = 0
        total_file_open_count = 5
        success_file_open_count = 5
        total_file_read_count = 0
        success_file_read_count = 0
        total_file_write_count = 5
        success_file_write_count = 5
        last_heart_beat_time = 2018-05-24 01:26:54
        last_source_update = 2018-05-17 01:27:29
        last_sync_update = 2018-05-17 01:06:46
        last_synced_timestamp = 1970-01-01 10:00:00 (never synced)
    Storage 2:
        id = 118.138.233.27
        ip_addr = 118.138.233.27 (vm-118-138-233-27.erc.monash.edu.au)  ACTIVE
        http domain = 
        version = 5.12
        join time = 2018-05-17 00:39:17
        up time = 2018-05-20 00:52:30
        total storage = 2015737 MB
        free storage = 1689979 MB
        upload priority = 10
        store_path_count = 1
        subdir_count_per_path = 256
        storage_port = 23000
        storage_http_port = 8888
        current_write_path = 0
        source storage id = 
        if_trunk_server = 0
        connection.alloc_count = 256
        connection.current_count = 3
        connection.max_count = 3
        total_upload_count = 0
        success_upload_count = 0
        total_append_count = 0
        success_append_count = 0
        total_modify_count = 0
        success_modify_count = 0
        total_truncate_count = 0
        success_truncate_count = 0
        total_set_meta_count = 0
        success_set_meta_count = 0
        total_delete_count = 0
        success_delete_count = 0
        total_download_count = 0
        success_download_count = 0
        total_get_meta_count = 0
        success_get_meta_count = 0
        total_create_link_count = 0
        success_create_link_count = 0
        total_delete_link_count = 0
        success_delete_link_count = 0
        total_upload_bytes = 0
        success_upload_bytes = 0
        total_append_bytes = 0
        success_append_bytes = 0
        total_modify_bytes = 0
        success_modify_bytes = 0
        stotal_download_bytes = 0
        success_download_bytes = 0
        total_sync_in_bytes = 98314
        success_sync_in_bytes = 98314
        total_sync_out_bytes = 0
        success_sync_out_bytes = 0
        total_file_open_count = 5
        success_file_open_count = 5
        total_file_read_count = 0
        success_file_read_count = 0
        total_file_write_count = 5
        success_file_write_count = 5
        last_heart_beat_time = 2018-05-24 01:27:08
        last_source_update = 1970-01-01 10:00:00
        last_sync_update = 2018-05-21 16:32:36
        last_synced_timestamp = 2018-05-17 01:06:38 (20m:51s delay)
    Storage 3:
        id = 118.138.233.74
        ip_addr = 118.138.233.74 (vm-118-138-233-74.erc.monash.edu.au)  ACTIVE
        http domain = 
        version = 5.12
        join time = 2018-05-13 20:03:06
        up time = 2018-05-20 00:53:40
        total storage = 100665 MB
        free storage = 72339 MB
        upload priority = 10
        store_path_count = 1
        subdir_count_per_path = 256
        storage_port = 23000
        storage_http_port = 8888
        current_write_path = 0
        source storage id = 
        if_trunk_server = 0
        connection.alloc_count = 256
        connection.current_count = 3
        connection.max_count = 3
        total_upload_count = 2
        success_upload_count = 2
        total_append_count = 0
        success_append_count = 0
        total_modify_count = 0
        success_modify_count = 0
        total_truncate_count = 0
        success_truncate_count = 0
        total_set_meta_count = 2
        success_set_meta_count = 2
        total_delete_count = 0
        success_delete_count = 0
        total_download_count = 0
        success_download_count = 0
        total_get_meta_count = 0
        success_get_meta_count = 0
        total_create_link_count = 0
        success_create_link_count = 0
        total_delete_link_count = 0
        success_delete_link_count = 0
        total_upload_bytes = 11190
        success_upload_bytes = 11190
        total_append_bytes = 0
        success_append_bytes = 0
        total_modify_bytes = 0
        success_modify_bytes = 0
        stotal_download_bytes = 0
        success_download_bytes = 0
        total_sync_in_bytes = 174142
        success_sync_in_bytes = 87026
        total_sync_out_bytes = 0
        success_sync_out_bytes = 0
        total_file_open_count = 3
        success_file_open_count = 3
        total_file_read_count = 0
        success_file_read_count = 0
        total_file_write_count = 3
        success_file_write_count = 3
        last_heart_beat_time = 2018-05-24 01:27:13
        last_source_update = 2018-05-17 01:06:38
        last_sync_update = 2018-05-21 16:32:54
        last_synced_timestamp = 2018-05-17 01:27:30 (-1s delay)
    Storage 4:
        id = 118.138.240.146
        ip_addr = 118.138.240.146 (vm-118-138-240-146.erc.monash.edu.au)  ACTIVE
        http domain = 
        version = 5.12
        join time = 2018-05-20 00:53:13
        up time = 2018-05-20 00:53:13
        total storage = 483679 MB
        free storage = 449872 MB
        upload priority = 10
        store_path_count = 1
        subdir_count_per_path = 256
        storage_port = 23000
        storage_http_port = 8888
        current_write_path = 0
        source storage id = 118.138.233.26
        if_trunk_server = 0
        connection.alloc_count = 256
        connection.current_count = 3
        connection.max_count = 3
        total_upload_count = 0
        success_upload_count = 0
        total_append_count = 0
        success_append_count = 0
        total_modify_count = 0
        success_modify_count = 0
        total_truncate_count = 0
        success_truncate_count = 0
        total_set_meta_count = 0
        success_set_meta_count = 0
        total_delete_count = 0
        success_delete_count = 0
        total_download_count = 0
        success_download_count = 0
        total_get_meta_count = 0
        success_get_meta_count = 0
        total_create_link_count = 0
        success_create_link_count = 0
        total_delete_link_count = 0
        success_delete_link_count = 0
        total_upload_bytes = 0
        success_upload_bytes = 0
        total_append_bytes = 0
        success_append_bytes = 0
        total_modify_bytes = 0
        success_modify_bytes = 0
        stotal_download_bytes = 0
        success_download_bytes = 0
        total_sync_in_bytes = 98314
        success_sync_in_bytes = 98314
        total_sync_out_bytes = 0
        success_sync_out_bytes = 0
        total_file_open_count = 5
        success_file_open_count = 5
        total_file_read_count = 0
        success_file_read_count = 0
        total_file_write_count = 5
        success_file_write_count = 5
        last_heart_beat_time = 2018-05-24 01:27:03
        last_source_update = 1970-01-01 10:00:00
        last_sync_update = 2018-05-21 16:32:54
        last_synced_timestamp = 2018-05-17 01:27:30 (-1s delay)

可以看到,4storage状态都是ACTIVE,表示都启动成功了。

5. 测试上传文件

需要注意一点,我们之后的特征提取程序会在feagen服务器上,所以,我们暂时将client安装在这台服务器上。测试一下在本台服务器上上传文件,能否在所有storage服务器上面查看得到此文件的备份。

5.1 修改tracker服务器上的client配置文件

先后输入以下命令:

cd /etc/fdfs
sudo cp client.conf.sample client.conf
sudo vim client.conf

base_pathtracker_server两处配置修改为:

base_path=/feagen/fastdfs/client
tracker_server=118.138.241.39:22122

shell当中输入下面的命令:

sudo /usr/bin/fdfs_upload_file /etc/fdfs/client.conf fastdfs-master.zip

返回如下,即可表明上传成功:

group1/M00/00/00/dorpG1td37yAFSYPAAZ-Sk23ivY904.zip

这个返回值,在perl当中,以如下方式获取:

my $file_name = qx(sudo /usr/bin/fdfs_upload_file /etc/fdfs/client.conf fastdfs-master.zip);

到任意一个storage服务器当中查看,以Bastion3为例,至此处:

/bastion3_cache/fastdfs/storage/data/00/00

发现存在如下文件:

dorpG1td37yAFSYPAAZ-Sk23ivY904.zip

即表明上传成功。

6. 测试下载文件

当前目录下,运行下面的程序:

sudo /usr/bin/fdfs_download_file /etc/fdfs/client.conf group1/M00/00/00/dorpG1td37yAFSYPAAZ-Sk23ivY904.zip

即可在当前目录下面找到dorpG1td37yAFSYPAAZ-Sk23ivY904.zip,表明下载成功。

至此我们的分布式文件服务器算是搭建完成了。

我们参考了这些文章,表示感谢!
FastDFS分布式文件系统集群安装与配置
FastDFS--原理篇
分布式文件系统FastDFS原理介绍
Ubuntu下安装并配置FastDFS

机器学习项目服务器上线部署全流程记录

Overview

我们团队完整的机器学习项目已经做了两个了,分别是Bastion4Bastion6。之前两个项目上线部署的记录过于片段化,针对现在马上要做完的Bastion3项目,我们在此完整记录搭建服务器各种环境的全部流程,以备不时之需。
完整的项目基本分为三大部分:Java处理业务逻辑;Perl后台消息队列;R机器学习模型预测。每个大部分还有很多细节,我们会在每部分都详细记录。
新申请的云服务器预装的仍然是Ubuntu16.04LTS发行版的Linux系统。

1.Java

Java端负责将用户提交的任务信息提交至后台Perl服务器并记录在MySQL数据库中。因此这部分会安装JDK1.8Tomcat7MySQL5.7

1.1 安装JDK1.8

安装JDK1.8,用apt命令很方便,不用单独下载解压。命令如下:

sudo apt-get install software-properties-common -y
sudo add-apt-repository ppa:webupd8team/java -y
sudo apt-get update
sudo apt-get install oracle-java8-installer oracle-java8-set-default -y

安装完成之后,JDK1.8会被安装在/usr/lib/jvm/java-8-oracle中,在/etc/profile或者~/.bashrc中配置JAVA_HOME变量 (我用的是~/.bashrc文件):

export JAVA_HOME=/usr/lib/jvm/java-8-oracle

安装好之后,需要以下命令使配置生效:

source ~/.bashrc

1.2 安装Tomcat7

使用以下的命令安装Tomcat7:

sudo apt-get install tomcat7

安装过程中,可能会报如下的错误(即使你已经配置好了JAVA_HOME):

Jul 09 16:52:16 bastiondb systemd[1]: Starting LSB: Start Tomcat....
Jul 09 16:52:16 bastiondb tomcat7[6413]:  * no JDK or JRE found - please...E
Jul 09 16:52:16 bastiondb systemd[1]: tomcat7.service: Control process e...1
Jul 09 16:52:16 bastiondb systemd[1]: Failed to start LSB: Start Tomcat..
Jul 09 16:52:16 bastiondb systemd[1]: tomcat7.service: Unit entered fail....
Jul 09 16:52:16 bastiondb systemd[1]: tomcat7.service: Failed with resul....
Hint: Some lines were ellipsized, use -l to show in full.
dpkg: error processing package tomcat7 (--configure):
 subprocess installed post-installation script returned error exit status 1
Errors were encountered while processing:
 tomcat7
E: Sub-process /usr/bin/dpkg returned an error code (1)

出现这个错误,说明tomcat7已经装好了,但是由于tomcat在启动时找不到JAVA_HOME的路径,所以报错。查看/etc/default/tomcat7,会发现下面这行:

#JAVA_HOME=/usr/lib/jvm/openjdk-6-jdk

去掉注释,并改为我们自己的JAVA_HOME路径:

JAVA_HOME=/usr/lib/jvm/java-8-oracle

重新运行安装命令:

sudo apt-get install tomcat7

安装成功...

安装好之后,tomcat7已经在运行了,使用下面命令查看:

ps aux | grep tomcat

用下面的命令启动/停止/重启Tomcat7了:

sudo service tomcat7 start/stop/restart

但是现在还有一个问题,Tomcat7的端口是8080,访问的时候必须在地址后面加上:8080,这样看起来不太和谐。由于Apache已经占用了80端口,所以我们采用Apache反向代理转发Tomcat请求的方式来解决这个问题。

1.2.1 配置Tomcat7启动内存

Tomcat启动内存不大,在网站数据量增多的情况下,就会在网页访问时报错,很难根据错误信息推测到这里。我们提前增大Tomcat的启动内存。
修改/usr/share/tomcat7/bin/catalina.sh文件

sudo vim /usr/share/tomcat7/bin/catalina.sh

可以看到:

# OS specific support.  $var _must_ be set to either true or false.
cygwin=false
darwin=false
os400=false
case "`uname`" in
CYGWIN*) cygwin=true;;
Darwin*) darwin=true;;
OS400*) os400=true;;

在这段前面添加:

JAVA_OPTS="-Xmx4096m"

就可以将tomcat启动内存增加为4G,保存并重启tomcat,就可以了。

下面的内容选择性安装,如果没有特殊需求,最好不要修改

默认的tomcat工作主目录为/var/lib/tomcat6/,网站目录为/var/lib/tomcat6/webapps,如果你的文章会产生大量文件,并且需要存放在网站的目录下,那这个目录就不太合适,因为这个目录通常占用的是系统盘空间。
假设你有一个新的扩展盘,目录为/my_extended_disk,在上面创建一个目录为tomcatWebapps,并想把这个目录,当做你的tomcat网站目录,修改/etc/tomcat7/server.xml

sudo vim /etc/tomcat7/server.xml

<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

修改为

<Host name="localhost"  appBase="/my_extended_disk/tomcatWebapps"
            unpackWARs="true" autoDeploy="true">

然后重启服务器,就可以了。

1.3 检查安装phpApache2

一般来说,装好的Ubuntu 16.04系统都会默认装好phpApache2,但配置使用之前最好还是检查一下。

使用下面命令检查php

php -v

如果已经安装,大概会显示下面的内容:

PHP 7.0.32-0ubuntu0.16.04.1 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.32-0ubuntu0.16.04.1, Copyright (c) 1999-2017, by Zend Technologies

说明安装了php 7.0。如果没装的话,用下面的命令安装:

sudo apt-get install php7.0

Ubuntu 16.04中,直接用

sudo apt-get install php

默认安装的也是php7.0版本。

使用下面命令检查Apache2

apache2 -v

如果已经安装,大概会显示下面的内容:

Server version: Apache/2.4.18 (Ubuntu)
Server built:   2018-04-18T14:53:04

说明没装的话,用下面的命令安装:

sudo apt-get install apache2

注意:如果phpApache2都没有安装的情况下,安装顺序一定要先装php,在装Apache2,如果顺序反了,可能会导致Apache2服务器不能识别php页面,在你访问这些页面的时候,直接显示页面的代码,而不是页面本身。 参见 php页面不能被解析成网页,而是直接显示了页面代码

1.4 设置Apache2反向代理

Apache2默认是随系统安装的,但有时候为了快速安装,去掉了也有可能。由于Apache2是随系统自动启动的,如果Apache2已经安装了并且没有人主动关闭的话,使用:

ps aux | grep apache2

就应该看到进程信息,如果没看到,用下面的命令安装:

sudo apt-get install apache2

安装成功之后,使用服务器的地址(比如bastion3.erc.monash.edu)访问,就应该看到Apache2的欢迎界面。 如果安装成功,但是网址却无法访问,说明80端口没开,联系管理员,打开这个端口。

修改Apache2配置文件:

sudo vim /etc/apache2/apache2.conf

在文件末尾添加以下内容:

ProxyPass / http://bastion3.erc.monash.edu:8080/
ProxyPassReverse / http://bastion3.erc.monash.edu:8080/

可以让Apache2http://bastion3.erc.monash.edu请求转发到http://bastion3.erc.monash.edu:8080/tomcat7处理。如果你在Apache2中有一个网站cgi-bin,你访问http://bastion3.erc.monash.edu/cgi-bin时,就想访问Apache2下的cgi-bin,而不是转成http://bastion3.erc.monash.edu:8080/cgi-bintomcat7处理,那么改成这样就可以了:

ProxyPass /phpmyadmin !
ProxyPass /cgi-bin !
ProxyPass / http://bastion3.erc.monash.edu:8080/
ProxyPassReverse / http://bastion3.erc.monash.edu:8080/

注意:这里同时写了一个phpmyadmin的配置,是因为我们会使用phpmyadmin管理和访问数据库。参考1.6小节的内容。

重启Apache2服务:

sudo service apache2 restart

如果报错:

Job for apache2.service failed because the control process exited with error code. See "systemctl status apache2.service" and "journalctl -xe" for details.

根据提示,使用

systemctl status apache2.service

查看错误信息:

Jul 09 17:15:56 bastiondb apache2[7914]:  * The apache2 configtest failed.
Jul 09 17:15:56 bastiondb apache2[7914]: Output of config test was:
Jul 09 17:15:56 bastiondb apache2[7914]: AH00526: Syntax error on line 223 o
Jul 09 17:15:56 bastiondb apache2[7914]: Invalid command 'ProxyPass', perhap
Jul 09 17:15:56 bastiondb apache2[7914]: Action 'configtest' failed.
Jul 09 17:15:56 bastiondb apache2[7914]: The Apache error log may have more
Jul 09 17:15:56 bastiondb systemd[1]: apache2.service: Control process exite
Jul 09 17:15:56 bastiondb systemd[1]: Failed to start LSB: Apache2 web serve
Jul 09 17:15:56 bastiondb systemd[1]: apache2.service: Unit entered failed s
Jul 09 17:15:56 bastiondb systemd[1]: apache2.service: Failed with result 'e

发现Apache2不能识别新添加的ProxyPass,导致重启失败。这是因为Apache2的代理模块proxy_http未启用,使用下面命令:

sudo a2enmod proxy_http

重新启动Apache2

sudo service apache2 restart

成功...这时候再输入服务器的地址,即可访问到tomcat的默认项目了,后面不用加:8080

1.5 安装MySQL5.7

先更新一下系统,再用apt-get命令直接安装:

sudo apt-get update
sudo apt-get install mysql-server

安装过程会让选择yes/no,选yes;还有就是设置root用户密码。
安装完成可以查看是不是安装好了,即查看MySQL的状态:

sudo service mysql status

显示如下即可:

?.mysql.service - MySQL Community Server
   Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2018-03-19 14:35:03 UTC; 27s ago
 Main PID: 17432 (mysqld)
   CGroup: /system.slice/mysql.service
           ?..17432 /usr/sbin/mysqld

Mar 19 14:35:02 bastion3 systemd[1]: Starting MySQL Community Server...
Mar 19 14:35:03 bastion3 systemd[1]: Started MySQL Community Server.

安装好之后,可以用以下命令启动/停止/重启:

sudo service mysql stop/stop/restart

本项目的数据的形式和之前项目的很相似,所以可以将之前的Bastion6项目数据库文件导出,然后再导入本项目。
导出命令:

mysqldump -uroot -p bastion6 > bastion6.sql

回车之后输入数据库密码即可。
bastion6.sql内容修改为自己需要的:

CREATE DATABASE IF NOT EXISTS bastion3;
USE bastion3;
DROP TABLE IF EXISTS `job`;

CREATE TABLE `job` (
  `jobID` int(100)  NOT NULL AUTO_INCREMENT,
  `jobName` varchar(256) NOT NULL,
  `orgnization` varchar(1000) ,
  `email` varchar(100) NOT NULL,
  `status`int(1) NOT NULL,
  `createTime` datetime NOT NULL,
  `startTime` datetime ,
  `endTime` datetime ,
  `sequence` longtext NOT NULL,
  `sequenceNumber` int(10) NOT NULL,
  PRIMARY KEY (`jobID`)
) DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `predictresult`;

CREATE TABLE `predictresult` (
  `jobID` int(100)  NOT NULL AUTO_INCREMENT,
  `jobName` varchar(256) NOT NULL,
  `predictionResult` longtext,
  PRIMARY KEY (`jobID`)
) DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `pssm`;

CREATE TABLE `pssm` (
  `id` int(100)  NOT NULL AUTO_INCREMENT,
  `seq` varchar(10000),
  `output` varchar(500) ,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `downloadInfo`;

CREATE TABLE `downloadInfo` (
  `id` int(100)  NOT NULL AUTO_INCREMENT,
  `type` varchar(10000),
  `count` varchar(500) ,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;

INSERT INTO `downloadInfo` VALUES (1,'originalData','0'),(2,'independentData','0'),(3,'predictData','0');

然后登录数据库:

mysql -u root -p

回车之后输入密码。
将上面的SQL命令输入,回车即可创建完整的数据库表。

至此,Java部分安装配置就算完成了。

1.6 安装配置phpmyadmin

命令行查看和管理MySQL还是有点不方便,所以我们这里安装一个phpmyadmin,就可以使用web界面查看和操作数据库。

这时候直接使用网址+phpmyadmin,浏览器会显示找不到phpmyadmin。那是因为apache2默认的网站路径是/var/www/html,而不是/var/www,编辑/etc/apache2/sites-enabled/000-default.conf

sudo vim /etc/apache2/sites-enabled/000-default.conf

DocumentRoot /var/www/html修改为DocumentRoot /var/www
重启apache2,重新访问,就可以了。

安装phpmyadmin

sudo apt-get install phpmyadmin

安装过程中,会弹出一个Configuring phpmyadmin框,让你选择要运行phpmyadmin的服务器,默认是apache2,还可以选择lighttpd,因为我们之前安装的web服务器是apache2,所以直接敲回车就行了。

然后安装一阵子继续弹出一个Configuring phpmyadmin框,提示你是否需要配置数据库,毕竟phpmyadmin本身就是管理数据库的,不配置好数据库,也就没有安装的意义了,默认选择的是Yes,回车,会转到新的界面让你输入密码,也就是刚才安装MySQL时设置的密码,输入之后敲回车确认,再重复确认密码,完成安装。

安装完成之后,发现在apache2的网站目录/var/www下,并没有多出来一个phpmyadmin,这是因为Ubuntu系统在安装phpmyadmin时,默认安装在了/usr/share/下:

ls /usr/share/

就可以看到里面有phpmyadmin

我们直接创建一个软连接:

sudo ln -s /usr/share/phpmyadmin /var/www/phpmyadmin

这样就可以在/var/www下访问到phpmyadmin

如果发现虽然能访问phpmyadmin了,但是浏览器直接显示了代码,而不是网页,说明apache2没有自动安装解析php的包。

先用下面的命令看看你装的php版本:

php --version

如果是php7.0,那么安装下面的包:

sudo apt-get install libapache2-mod-php7.0

然后重启apache2,现在应该可以访问到正常的网页了。具体原因,参见php页面不能被解析成网页,而是直接显示了页面代码

用户名是root,密码是MySQL设置的密码。

2.Perl后台

Perl的主要作用是它的消息队列以及和Java通讯的CGI模块。因此需要配置Apache2 CGI以及安装相应的Perl模块。

2.1 设置Apache2 CGI

在安装CGI模块之前,最好先将make安装好:

sudo apt-get install make

然后安装PerlCGI模块,推荐使用cpan命令安装 (一定要用sudo权限打开):
先打开cpan

sudo cpan

然后输入下面的命令:

install CGI

下面修改CGI程序的根目录:

sudo vim /etc/apache2/apache2.conf

将配置文件中对应的地方改为如下:

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

/var/www/cgi-bin目录中新建一个cgi_test.pl文件,以创建一个Perl CGI网站,文件内容为:

#!/usr/bin/perl -w
use warnings;
use CGI qw(:standard);
#! must use 'my' to define a variable
print header;
my $now_string = localtime();
print "<b>Hello, CGI using Perl!</b><br/>It's $now_string NOW!<br />";

为此文件添加执行权限:

sudo chmod +x /var/www/cgi-bin/cgi_test.pl

在命令行中执行此文件:

sudo perl /var/www/cgi-bin/cgi_test.pl

如果之前的设置正确,则会显示以下内容:

Content-Type: text/html; charset=ISO-8859-1

<b>Hello, CGI using Perl!</b><br/>It's Tue Mar 20 14:17:15 2018 NOW!<br />

至此,虽然可以在命令行中运行此程序,但是还不能作为服务器远程访问。我们需要做以下配置,让Apache2Perl支持:

sudo vim /etc/apache2/sites-enabled/000-default.conf

将下面的内容:

<VirtualHost *:80>
    ...
 
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www
     
    ...
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
     
</VirtualHost>

修改为:

<VirtualHost *:80>
    ...
 
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www
 
    ScriptAlias /cgi-bin/ /var/www/cgi-bin/
    <Directory "/var/www/cgi-bin">
         AllowOverride all
         Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
         Order allow,deny
         Allow from all
         AddHandler cgi-script .cgi .pl
    </Directory>
    ...
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    
</VirtualHost>

Apache中启用CGI模块。注意 VirtualHost *:80这里的端口号尽量不要改动,因为使用网址或者ip地址访问,不加端口号的话,默认就是访问80端口号,如果改了端口号,就得显示加上。
默认情况下,这个模块是没有开启的,这点可以用以下命令确认:

ls -l /etc/apache2/mods-enabled/ | grep cgi

显示为空表示当前启用的与CGI相关的模块为空。用下面的命令查看有哪些模块可以被启用:

ls -l /etc/apache2/mods-available/ | grep cgi

显示如下:

-rw-r--r-- 1 root root   74 Mar 19  2016 authnz_fcgi.load
-rw-r--r-- 1 root root  115 Mar 19  2016 cgid.conf
-rw-r--r-- 1 root root   60 Mar 19  2016 cgid.load
-rw-r--r-- 1 root root   58 Mar 19  2016 cgi.load
-rw-r--r-- 1 root root   89 Mar 19  2016 proxy_fcgi.load
-rw-r--r-- 1 root root   89 Mar 19  2016 proxy_scgi.load

这样,我们在mods-enabled中创建软连接,指向mods-available中的cgid.*文件:

sudo ln -s /etc/apache2/mods-available/cgid.load /etc/apache2/mods-enabled/
sudo ln -s /etc/apache2/mods-available/cgid.conf /etc/apache2/mods-enabled/

重启Apache服务器:

sudo service apache2 restart

此时,如果在浏览器中访问:http://bastion3.erc.monash.edu/cgi-bin/cgi_test.pl应该会显示:

Hello, CGI using Perl!
It's Tue Mar 20 14:17:15 2018 NOW!

这样就算成功了。

2.2 Perl相关模块安装

在安装这部分模块之前,最好保证gccg++两个程序已经安装好了,如果没有安装好,那么按照以下命令安装:

sudo apt-get install gcc
sudo apt-get install g++

Perl模块仍然要使用sudo cpan命令安装,然后依次输入以下命令:

install Storable
install DBI
install IO::All
install Bio::SeqIO
install Bio::Seq
install Capture::Tiny
install SOAP::Transport::HTTP
install MIME::Lite
install Mail::Sendmail

2.3 gearman消息队列安装

当前最新版的gearmangearmand-1.1.12。我们执行下面几步,先将其下载到本地主文件夹,并解压缩。

cd ~
sudo apt-get update
wget https://launchpad.net/gearmand/1.2/1.1.12/+download/gearmand-1.1.12.tar.gz
tar zxvf gearmand-1.1.12.tar.gz
cd gearmand-1.1.12/

进入gearmand-1.1.12文件夹后,如果直接运行

./configure

就会报缺少如下几个依赖包错误:

configure: error: could not find boost
configure: error: Could not find a version of the library
configure: error: could not find gperf
configure: error: Unable to find libevent
configure: error: Unable to find libuuid

所以,我们先将这些依赖都安装好:

sudo apt-get install libboost-dev
sudo apt-get install libboost-all-dev
sudo apt-get install gperf
sudo apt-get install libevent-dev
sudo apt-get install uuid-dev

安装好之后,如果没有错误,则运行:

./configure

然后仍在gearmand-1.1.12文件夹下运行下面两条命令,编译时间比较长:

sudo make
sudo make install

这个过程中如果出现了错误,就运行下面的命令清除一下之前编译产生的可执行文件以及object文件(即扩展名为o的文件):

sudo make clean

继续重新安装编译:

./configure
sudo make
sudo make install

没有错误的话,就安装gearmanjob server

sudo apt-get install gearman-job-server

安装好以后,运行一下gearman:

gearman -d

会提示错误:

gearman: error while loading shared libraries: libgearman.so.8: cannot open shared object file: No such file or directory

这表示找不到libgearman.so.8所在的目录。这时我们打开/etc/ld.so.conf文件:

sudo vim /etc/ld.so.conf

添加一句话:

include /usr/local/lib

保存退出,并执行下面这句:

sudo /sbin/ldconfig

这样就不会出错了。

启动一下job server

gearmand -d

报错如下:

gearmand: Could not open log file "/usr/local/var/log/gearmand.log", from "/home/ubuntu/gearmand-1.1.12", switching to stderr. (No such file or directory)

我们这样解决:在/usr/local/下面新建var子目录,进去,新建log子目录,再进去,新建文件gearmand.log。这样就没有问题了。

sudo权限运行下面的命令:

sudo gearmand -d -L 127.0.0.1 -p 4730

-d表示daemon,在后台运行;
-L表示监听的ip,默认是localhost
-p表示监听的端口号port,默认是4730

此时,使用下面的命令,即可查看gearman当前状态:

sudo lsof -i:4730

如果显示如下,就表示成功安装:

COMMAND    PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand 27831 gearman   10u  IPv4 320614      0t0  TCP localhost:4730 (LISTEN)

这样gearmanubuntu16.04上面就安装成功了。

至此,我们还需要安装三个Perl模块:

Gearman::Server
Gearman::Client
Gearman::Worker

在安装Gearman::Server的时候,需要依赖Net::SSLeay,IO::Socket::SSLGearman::Util,而安装Net::SSLeay的时候,如果没有libssl-dev这个系统包,是安装不上Net::SSLeay的。所以我们必须要先安装好libssl-dev

sudo apt-get install libssl-dev

然后必须按顺序依次安装Net::SSLeay,顺序不能乱:
继续打开cpan

sudo cpan

然后

install Net::SSLeay
install IO::Socket::SSL
install Gearman::Util

依次安装:

install Gearman::Server
install Gearman::Client
install Gearman::Worker

都安装后之后,可以重启一下机器。
启动之后,用如下命令观察4730端口,查看gearmanjob server是否已经启动(gearmand -d这条命令是否生效):

sudo lsof -i:4730

显示如下:

COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand 907 gearman   10u  IPv4  21414      0t0  TCP localhost:4730 (LISTEN)

可以知道,这个server是开机自启动的。
至此,gearman消息队列的安装就算完成了。

每次重启服务器,都需要重启worker脚本。workerclient脚本都会放在/var/www/cgi-bin/目录下面,因此启动worker和命令如下(比如我们要开16worker):

sudo nohup perl /var/www/cgi-bin/worker_bastion3.pl >~/worker_bastion3_log_1.txt &
sudo nohup perl /var/www/cgi-bin/worker_bastion3.pl >~/worker_bastion3_log_2.txt &
sudo nohup perl /var/www/cgi-bin/worker_bastion3.pl >~/worker_bastion3_log_3.txt &
sudo nohup perl /var/www/cgi-bin/worker_bastion3.pl >~/worker_bastion3_log_4.txt &
...
sudo nohup perl /var/www/cgi-bin/worker_bastion3.pl >~/worker_bastion3_log_16.txt &

client会在提交任务的时候,由Java调用,因此不需要我们手动启动。

现在不再需要手动重启了。 运行sudo crontab -ee代表edit),可以编辑创建一个cron任务,可能需要先选择编辑器,熟悉哪个选哪个就行了,我选的3. vim

@reboot cd /var/www/cgi-bin && sudo perl /var/www/cgi-bin/worker_Bastion3.pl > /var/log/worker_Bastion3_log_1.txt 2>&1
@reboot cd /var/www/cgi-bin && sudo perl /var/www/cgi-bin/worker_Bastion3.pl > /var/log/worker_Bastion3_log_2.txt 2>&1
@reboot cd /var/www/cgi-bin && sudo perl /var/www/cgi-bin/worker_Bastion3.pl > /var/log/worker_Bastion3_log_3.txt 2>&1
@reboot cd /var/www/cgi-bin && sudo perl /var/www/cgi-bin/worker_Bastion3.pl > /var/log/worker_Bastion3_log_4.txt 2>&1
...
@reboot cd /var/www/cgi-bin && sudo perl /var/www/cgi-bin/worker_Bastion3.pl > /var/log/worker_Bastion3_log_16.txt 2>&1

这样之后服务器重启,就不必再手动开这些进程了。

使用sudo crontab -l(l代表list)可以查看所有你创建的cron任务。注意:用sudo创建的任务用sudo查看,才能看得到,同样sudo crontab -l查看不到crontab -e 创建的任务。

相对于手动执行脚本,这里的配置有三个变化:

    1. log日志重定向到了/var/log/目录下,可以直接在这里查看错误信息。
    1. 不再需要用nohup命令了,nohup是因为我们用ssh登录,需要在ssh退出后脚本依然运行才这么做的,现在重启时系统系统这个脚本,这个脚本会一直留在系统中,不必再用nohup
    1. cron启动脚本时,当前工作目录可能跟想象中不一样,我们执行sudo perl /var/www/cgi-bin/worker_bastion3.pl(不管用不用nohup)时,脚本的工作目录在/var/www/cgi-bin,而由cron执行时,当前工作目录却是sudo perl /var/www/cgi-bin/worker_bastion3.pl,导致脚本中使用相对目录的地方会报错,比如这里:

      $seqs > io("sequence/$jobName.fasta");
      …
      
    当然,好的习惯是尽量不要用相对路径,因为你不知道这个脚本会在哪里或者哪种环境下执行,执行时的当前工作目录也可能无法预测。

3. Python相关安装

Python在此系列项目当中,主要是用来提取特征,因此需要依次安装以下几个工具包:

sudo apt-get install python-scipy
sudo apt-get install python-dev
sudo apt-get install python-numpy
sudo apt-get install python-matplotlib
sudo apt-get install python-pandas
sudo apt-get install python-sklearn

4. R语言及相关包安装

R语言在此系列项目当中,既要提取部分特征,又要负责训练模型,还要使用ggplot2画图,所以有很多相关的包是要安装的。
首先安装R语言:

sudo apt-get install r-base

然后安装以下几个包 (其实这个服务器在机器学习部分主要作用就是预测,因为训练部分的工作都会在线下进行,不过仍然将所有机器学习部分必须的包都记录在此,以备查阅)。
sudo权限启动R语言:

sudo R

这里必须用sudo启动R安装,这样R包一般会安装在/usr/local/lib/R/site-library中,不用sudo权限,会把R包装在当前用户的个人空间,比如~/R/x86_64-pc-linux-gnu-library/3.2。在普通状态下这两个位置并无不同,但是如果当前用户进入root模式(比如用sudo -i命令),再使用R就不能正确找到R包了。很不幸,因为我们用了crontab设置了worker开机自启动,导致在sudo模式调用了worker的程序,并由worker进一步调用了R程序,就没能找到普通权限下安装的R包,导致报错了。

然后在启动的R语言对话框中输入以下命令:

install.packages("protr")
install.packages("caret")
install.packages("e1071")
install.packages("plyr")
install.packages("RSNNS")
install.packages("ROCR")
install.packages("ggplot2")
install.packages("randomForest")

至此一个完整的机器学习项目的服务器就已经算是搭建好了。

需要格外注意的是,因为我们的缓存文件都在外接硬盘上,所以每次都重启服务器之后都需要手动加载此硬盘:

sudo mount /dev/vdb /bastion3_cache/

现在不用这么做了,通过配置/etc/fstab可以直接再重启服务器时自动挂载,在/etc/fstab文件中添加下面的行(需要用sudo编辑):

/dev/vdb        /bastion3_cache auto    defaults,nofail,x-systemd.requires=cloud-init.service,comment=cloudconfig       0       2

其中,/dev/vdb是要挂在的物理硬盘盘符,/bastion3_cache是挂载盘目录。

如果你不清楚哪个盘需要挂载,用df -h查看:

ubuntu@bastion3:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
udev             32G     0   32G   0% /dev
tmpfs           6.3G  180M  6.2G   3% /run
/dev/vda1       9.9G  4.2G  5.2G  45% /
tmpfs            32G     0   32G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs            32G     0   32G   0% /sys/fs/cgroup
/dev/vdb        473G  9.0G  440G   3% /bastion3_cache
tmpfs           6.3G     0  6.3G   0% /run/user/1000

如果有硬盘为未挂载,那Mounted on这列应该是空的,或者是/mnt(默认挂载在/mnt目录)。挂载前需要自己创建一个目录,比如sudo mkdir /bastion3_cache

ubuntu14.04安装gearman及perl扩展包

Overview

Bastion4这个项目经过我们实验验证和安全考虑,决定舍弃kafka而转用gearman这个消息队列框架,具体分析将在后续文章中给出,这里只记录gearman相关的安装。

1.下载安装gearman

最新版的gearmangearmand-1.1.12。我们执行下面几步,先将其下载到本地主文件夹,并解压缩。

sudo apt-get update
wget https://launchpad.net/gearmand/1.2/1.1.12/+download/gearmand-1.1.12.tar.gz
tar zxvf gearmand-1.1.12.tar.gz
cd gearmand-1.1.12/

进入gearmand-1.1.12文件夹后,如果直接运行

./configure

就会报缺少如下几个依赖包错误:

configure: error: could not find boost
configure: error: Could not find a version of the library
configure: error: could not find gperf
configure: error: Unable to find libevent
configure: error: Unable to find libuuid

所以,我们先将这些依赖都安装好:

sudo apt-get install libboost-dev
sudo apt-get install libboost-all-dev
sudo apt-get install gperf
sudo apt-get install libevent-dev
sudo apt-get install uuid-dev

安装好之后,如果没有错误,仍在gearmand-1.1.12文件夹下运行下面两条命令,编译时间比较长:

sudo make
sudo make install

这个过程中如果出现了错误,就运行下面的命令清除一下之前编译产生的可执行文件以及object文件(即扩展名为o的文件):

sudo make clean

继续重新安装编译:

./configure
sudo make
sudo make install

没有错误的话,就安装gearmanjob server

sudo apt-get install gearman-job-server

安装好以后,运行一下gearman:

gearman

会提示错误:

gearman: error while loading shared libraries: libgearman.so.8: cannot open shared object file: No such file or directory

这表示找不到libgearman.so.8所在的目录。这时我们打开/etc/ld.so.conf文件:

sudo vim /etc/ld.so.conf

添加一句话:

include /usr/local/lib

保存退出,并执行下面这句:

sudo /sbin/ldconfig

这样就不会出错了。
启动一下job server

gearmand -d

报错如下:

gearmand: Could not open log file "/usr/local/var/log/gearmand.log", from "/home/young/gearmand-1.1.12", switching to stderr. (No such file or directory)

我们这样解决:在/usr/local/下面新建var子目录,进去,新建log子目录,再进去,新建文件gearmand.log。这样就没有问题了。
sudo权限运行下面的命令:

sudo gearmand -d -L 127.0.0.1 -p 4730

-d表示daemon,在后台运行;
-L表示监听的ip,默认是localhost
-p表示监听的端口号port,默认是4730

这样gearmanubuntu14.04上面就安装成功了。

2.安装perl扩展包

perl端需要3个扩展包:

Gearman::Server
Gearman::Client
Gearman::Worker

可以用之前Chris的博客BioPerl(一):安装BioPerl中介绍的方法,先安装好CPAN
之后,用sudo权限打开CPAN

sudo cpan

然后依次安装3个扩展包:

install Gearman::Server
install Gearman::Client
install Gearman::Worker

都安装后之后,可以重启一下机器。
启动之后,用如下命令观察4730端口,查看gearmanjob server是否已经启动(gearmand -d这条命令是否生效):

sudo lsof -i:4730

如果不加sudo是看不到的,所以linux命令建议都要加上sudo

可以看到:

COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand 576 gearman    9u  IPv4  12861      0t0  TCP *:4730 (LISTEN)
gearmand 576 gearman   10u  IPv6  12862      0t0  TCP *:4730 (LISTEN)

服务器端可能会只显示

COMMAND  PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand 576 gearman    9u  IPv4  12861      0t0  TCP *:4730 (LISTEN)

可见这个server是开机启动的。

3.运行测试perl脚本

client.pl将消息发送到server,相当于生产者;
worker.pl来处理这些消息,并把结果返回给client.pl
相当于消费者。我们观察输出即可。
client.pl代码如下:

#!/usr/bin/perl
use strict;
use warnings;
use Gearman::Client;
use Storable; 
use Storable qw(freeze);
use Storable qw(thaw);
use IO::All;

# fork this process
my $pid = fork();
if ($pid == 0)
{
    # do this in the child
    print "start new client \n";
    my $client = Gearman::Client->new;
    print "finish new client \n";
    print "start job_servers \n";
    $client->job_servers('127.0.0.1',4730);
    print "finish job_servers \n";
    # 设置异步任务
    print "start new_task_set \n";
    my $tasks = $client->new_task_set; 
    print "finish new_task_set \n";
    print "start add_task \n";
    #handle database
    my @rows=('hello','byebye');
    $tasks->add_task(
        # 开始任务,多个参数
        showMessage => freeze(\@rows), 
        # 注册回调函数 
        { on_complete => \&complete },  
    );  
    print "finish add_task \n";
    print "start wait \n";
    # 等待任务结束
    $tasks->wait;
    print "finish wait \n";
    exit;
}

print "The background task will be finished shortly.\n";
 
sub complete{   
    my $ret = ${ $_[0] };
    #io("complete.txt")->print($ret);
    print $ret, "\n";
} 
 

worker.pl代码如下:

#!/usr/bin/perl
use strict;
use warnings;
use Gearman::Worker;
use Storable qw(thaw);
use Storable qw(freeze);

 print "start new worker \n";
my $worker = Gearman::Worker->new;
print "finish new worker \n";
print "start job_servers \n";
$worker->job_servers('127.0.0.1',4730);
print "finish job_servers \n";
# Worker 注册可以使用的功能
print "start register_function \n";
$worker->register_function( showMessage => \&showMessage );  
 print "finish register_function \n";
# 等待连接的任务
print "start work \n";

$worker->work while 1;  
print "finish work \n";
sub showMessage{
    my @row=@{ thaw($_[0]->arg) };

    my $job = \@row;
    print "\n";
    print "$row[0] \n";
    print "$row[1] \n";   
    print "start sleep \n";
    my $date = &getTime();  
    print  $date->{date}," ",$date->{hour},":",$date->{minute},":",$date->{second};
    print "\n";
    sleep(10);
    print "finish sleep \n";
    $date = &getTime();  
    print  $date->{date}," ",$date->{hour},":",$date->{minute},":",$date->{second};
    print "\n";

    my $ret = "hello world";
    return $ret;
}

sub getTime
{
    my $time = shift || time();
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);

    $year += 1900;
    $mon ++;

    $min  = '0'.$min  if length($min)  < 2;
    $sec  = '0'.$sec  if length($sec)  < 2;
    $mon  = '0'.$mon  if length($mon)  < 2;
    $mday = '0'.$mday if length($mday) < 2;
    $hour = '0'.$hour if length($hour) < 2;
    
    my $weekday = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$wday];

    return { 'second' => $sec,
             'minute' => $min,
             'hour'   => $hour,
             'day'    => $mday,
             'month'  => $mon,
             'year'   => $year,
             'weekNo' => $wday,
             'wday'   => $weekday,
             'yday'   => $yday,
             'date'   => "$year-$mon-$mday"
          };
}

我们先运行worker.pl

sudo perl worker.pl

再查看4730端口:

sudo lsof -i:4730

发现多了两个占用:

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand  576 gearman    9u  IPv4  12861      0t0  TCP *:4730 (LISTEN)
gearmand  576 gearman   10u  IPv6  12862      0t0  TCP *:4730 (LISTEN)
gearmand  576 gearman   33u  IPv4 191760      0t0  TCP localhost:4730->localhost:37151 (ESTABLISHED)
perl     4508    root    3u  IPv4 192605      0t0  TCP localhost:37151->localhost:4730 (ESTABLISHED)

再运行多个client.pl

sudo perl client.pl

每启动一个client.pl就会多两个端口占用。

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
gearmand  576 gearman    9u  IPv4  12861      0t0  TCP *:4730 (LISTEN)
gearmand  576 gearman   10u  IPv6  12862      0t0  TCP *:4730 (LISTEN)
gearmand  576 gearman   33u  IPv4 191760      0t0  TCP localhost:4730->localhost:37151 (ESTABLISHED)
gearmand  576 gearman   34u  IPv4 215493      0t0  TCP localhost:4730->localhost:37189 (ESTABLISHED)
perl     4508    root    3u  IPv4 192605      0t0  TCP localhost:37151->localhost:4730 (ESTABLISHED)
perl     4709    root    3u  IPv4 214688      0t0  TCP localhost:37189->localhost:4730 (ESTABLISHED)

每运行一次worker.pl表示启动一个新的消费者。如果只启动一个消费者,而启动多个生产者,就可以很好地观察到“排队”效果了:一定是一个任务执行完成之后才会开始处理另一个任务。
这样gearmanperl扩展包的安装使用就结束了。

这篇文章主要参考了如下几篇文章:

Gearman Job Server
Gearman
使用 Gearman 实现分布式处理
Gearman 安装使用 以及 问题处理
Ubuntu下Gearman安装搭建

配置Apache2服务器以CGI方式运行Perl程序

Overview

这次我们开发Bastion4服务器使用了JAVA+Perl的架构,后端用Perl做服务器提供Webservice,用JAVA框架Struts接收处理用户请求,再跟Perl服务器交互。
我们使用Apache2作为Perl服务器,由于Apache2默认并不支持Perl,因此需要简单配置一下,使得Apache2CGI的方式支持Perl运行。在配置的过程中,参考了一些网页,但由于各个网页都没有完整地描述配置过程(至少在我们的服务器上是这样),所以这里记录一下我们配置的全过程。

1. Apache2基本配置

我们为Bastion4申请了一个新的云服务器,版本为NeCTAR Ubuntu 16.04 LTS x86_64,自带了Apache2服务器,下面简单列出了Apache2的一些基本信息:

  • /etc/apache2/ Apache2的配置文件目录
  • /var/www/ Apache2的网站存放目录
  • /var/log/apache2/ Apache2的日志存放目录
  • /etc/apache2/apache2.conf Apache2的配置主文件,以前的Apache版本中,主配置文件名字叫httpd.conf,所以很多网页中还用到这个名字,不知道的话会造成很多混淆。尽管apache2.conf是主配置文件,但是多数具体的配置信息并不是写在这个文件中的,/etc/apache2目录中有还有几个文件夹分别记录了几个模块的配置信息,apache2.conf负责把他们导入整合在一起。
  • /etc/apache2/sites-enabled/ 看名字就可以明白,Apache2的网站配置文件一般都是放在这个目录中的,这个目录下的000-default.conf是我们经常要修改的配置文件。

我们假定Apache存放网站的根目录是/var/www/,如果不确定(因为默认好像是/var/www/html这个目录),打开/etc/apache2/apache2.conf目录,查看下面的配置:

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

如果在你的配置里是

<Directory /var/www/html/>

修改成

<Directory /var/www/>

这样,当你把一个名叫Mywebsite的网站(通常是一个文件夹),扔到/var/www中时,你就可以以http://localhost/Mywebsite/访问到这个网站了。

如果你的配置是<Directory /var/www/html/>,那你需要把你的网站扔到/var/www/html中,才能使用http://localhost/Mywebsite/访问,这是因为<Directory>设置了Apache的根目录,当你使用http://****/Mywebsite访问时,Apache会去当前的根目录/Mywebsite找这个网站。

由于Apache的端口号默认是80,而不加端口号的url访问都会被服务器默认定向到80端口,因此这里不需要添加端口号,如果你手动将Apache端口号修改成了别的端口号(比如8888),那你需要使用http://localhost:8888/Mywebsite/访问这个网站。

2. 配置Apache2支持Perl CGI程序

2.1 创建一个Perl网站

  1. /var/www下创建网站的目录,我们创建一个名字叫cgi-bin的网站作为例子:

    mkdir /var/www/cgi-bin
    

    需要使用管理员权限的命令,请自己加上sudo

  2. /var/www/cgi-bin中创建一个cgi_test.pl脚本,输入下面的内容:

    #!/usr/bin/perl -w
    use warnings;
    use CGI qw(:standard);
    #! must use 'my' to define a variable
    print header;
    my $now_string = localtime();
    print "<b>Hello, CGI using Perl!</b><br/>It's $now_string NOW!<br />";
    
  3. cgi_test.pl添加可执行权限:

    chmod +x /var/www/cgi-bin/cgi_test.pl
    
  4. 在命令行运行cgi_test.pl

    /var/cgi-bin/www/cgi_test.pl
    

    会得到下面的结果:

    Content-Type: text/html; charset=ISO-8859-1
    
    <b>Hello, CGI using Perl!</b><br/>It's Mon Aug  1 03:35:42 2016 NOW!<br />
    

    成功运行这个perl脚本需要先安装perlCGI

  5. 尽管现在我们可以在本地以命令行的形式运行这个perl脚本,但还是不能让这个脚本在服务器中运行,访问http://localhost:8888/cgi-bin/cgi_test.pl,浏览器会直接显示整个脚本的内容:

    #!/usr/bin/perl -w
    use warnings;
    use CGI qw(:standard);
    #! must use 'my' to define a variable
    print header;
    my $now_string = localtime();
    print "<b>Hello, CGI using Perl!</b><br/>It's $now_string NOW!<br />";
    

    而不是只把脚本打印的内容显示出来,所以,接下来我们继续配置Apache服务器。

2.2 配置Apache服务器

  1. 打开/etc/apache2/sites-enabled/000-default.conf配置文件,找到下面的配置信息:

    <VirtualHost *:8080>
    ...
    
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www
        
    ...
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
        
    </VirtualHost>
    

    我们需要添加一些配置信息,添加之后,000-default.conf的内容如下:

    <VirtualHost *:8080>
    ...
    
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www
    
    ScriptAlias /cgi-bin/ /var/www/cgi-bin/
    <Directory "/var/www/cgi-bin">
             AllowOverride all
             Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
             Order allow,deny
             Allow from all
             AddHandler cgi-script .cgi .pl
    </Directory>
    ...
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
       
    </VirtualHost>
    

    很容易看得出来,这部分配置主要是用来添加Apacheperl的支持。

  2. 默认情况下,Apache并没有启用CGI模块,我们可以从/etc/apache2/mods-enabled/中确认这点。

    ls -l /etc/apache2/mods-enabled/ | grep cgi
    

    显示结果为空。

    ls -l /etc/apache2/mods-available/ | grep cgi
    

    显示下面的结果:

    -rw-r--r-- 1 root root   74 Mar 19 09:48 authnz_fcgi.load
    -rw-r--r-- 1 root root   58 Mar 19 09:48 cgi.load
    -rw-r--r-- 1 root root  115 Mar 19 09:48 cgid.conf
    -rw-r--r-- 1 root root   60 Mar 19 09:48 cgid.load
    -rw-r--r-- 1 root root   89 Mar 19 09:48 proxy_fcgi.load
    -rw-r--r-- 1 root root   89 Mar 19 09:48 proxy_scgi.load
    

    从名字上就可以看出来,mods-enabled中存放的是已经启用的模块,mods-available中存放的是所有可用的模块,所以启用CGI模块变得很简单,把mods-available中的相关文件在mods-enabled中创建软连接就可以了。

  3. mods-enabled中创建软连接,指向mods-available中的cgid.*文件:

    ln -s /etc/apache2/mods-available/cgid.load /etc/apache2/mods-enabled/
    ln -s /etc/apache2/mods-available/cgid.conf /etc/apache2/mods-enabled/
    

    再次查看mods-enabled

    ls -l /etc/apache2/mods-enabled/ | grep cgi
    

    显示结果为:

    lrwxrwxrwx 1 root root 37 Jul 24 11:55 cgid.conf -> /etc/apache2/mods-available/cgid.conf
    lrwxrwxrwx 1 root root 37 Jul 24 11:55 cgid.load -> /etc/apache2/mods-available/cgid.load
    
  4. 重启Apache服务器:

    service apache2 restart
    

    或者重新载入配置文件:

    service apache2 reload
    

    稳妥的方式是restart Apache服务器,而不只是reload服务器,参见3.2

  5. 在浏览器中访问:http://localhost:8888/cgi-bin/cgi_test.pl就会显示:

    Hello, CGI using Perl!
    It's Mon Aug 1 03:48:37 2016 NOW!
    

可以看到perl脚本在Apache服务器中以CGI脚本的形式运行了。

3. 可能遇到的一些错误

实际上,如果你严格按照上面的步骤,基本上不会出现错误,但是在这里,还是列出一些常见的错误,以便真的遇到这些问题时可以快速查看。

本节主要取自Perl/CGI script with Apache2,所以里面的脚本名字(这里是echo.pl,脚本的路径(这里是/var/cgi-bin而不是/var/www/cgi-bin)和错误信息都沿用了这篇文章的内容,与本文上面使用的脚本名字,脚本路径和脚本内容内容稍有不同,但也都大同小异。

3.1 500 Internal Server Error

如果你使用浏览器访问perl脚本时,看到500 Internal Server Error错误,打开Apache的错误日志/var/log/apache2/error.log

  1. 如果显示下面的错误信息:

    [Wed Mar 19 15:19:15.740781 2014] [cgid:error] [pid 3493:tid 139896478103424] (8)Exec format error: AH01241: exec of '/var/cgi-bin/echo.pl' failed
    [Wed Mar 19 15:19:15.741057 2014] [cgid:error] [pid 3413:tid 139896186423040] [client 192.120.120.120:62309] End of script output before headers: echo.pl
    

    说明脚本的第一行sh-bang line没有正确指向'perl'的安装路径,检查你的perl脚本,确认第一行是下面的样子:

    #!/usr/bin/perl
    

    其实这样的错误非常罕见,除非你是新手,而且又完全自己手写了一段perl脚本。

  2. 如果显示下面的错误信息:

    No such file or directory: AH01241: exec of '/var/cgi-bin/echo.pl' failed
    [Wed Mar 19 15:24:33.505429 2014] [cgid:error] [pid 3412:tid 139896261957376] [client 192.120.120.120:58087] End of script output before headers: echo.pl
    

    说明echo.plDOS格式,而非Unix格式,如果你经常的是Windows,或者喜欢在Windows下写好脚本再上传到Unix/Linux服务器中,那么这会是一个常见而且通用的错误。使用dos2unix命令转换脚本的格式:

    dos2unix /var/cgi-bin/echo.pl
    

    系统默认可能并没有装dos2unix命令,需要自己安装一下。如果你用的是Ubuntu,用sudo apt install dos2unix安装。

  3. 如果显示下面的错误信息:

    [Wed Mar 19 15:40:31.179155 2014] [cgid:error] [pid 4796:tid 140208841959296] (13)Permission denied: AH01241: exec of '/var/cgi-bin/echo.pl' failed
    [Wed Mar 19 15:40:31.179515 2014] [cgid:error] [pid 4702:tid 140208670504704] [client 192.120.120.120:60337] End of script output before headers: echo.pl
    

    说明你没有为perl脚本添加可执行权限,使用chmod命令很容易更正这个错误:

    chmod +x /var/cgi-bin/echo.pl
    
  4. 如果显示下面的错误信息:

    Wed Mar 19 16:02:20.239624 2014] [cgid:error] [pid 4703:tid 140208594970368] [client 192.120.120.120:62841] malformed header from script 'echo.pl': Bad header: hi
    

    上面错误对应的脚本:

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    print "hi\n";
    print qq(Content-type: text/plain\n\n);
    

    perl脚本输出Content-type之前输出了别的字符,而浏览器解析的时候把那些字符当做了Content-type,所以报了Bad header错误。所以,不要在print qq(Content-type: text/plain\n\n);之前,输出别的字符。

  5. 如果显示下面的错误信息:

    [Wed Mar 19 16:08:00.342999 2014] [cgid:error] [pid 4703:tid 140208536221440] [client 192.120.120.120:59319] End of script output before headers: echo.pl
    

    还是一个跟header相关的问题,说明你的脚本在打印Content-type之前就出了错误或者异常,error.log中也可能在上面的错误信息之前提供其他更具体的相关信息。所以,请仔细检查打印Content-type之前的perl代码。

    关于End of script output before headers错误,原文作者认为可能与Premature end of script headers是同样的原因。

3.2 503 Service Unavailable

如果在本文2.2节为mods-enabled创建了软连接之后,并及时重载了apache,会报下面的错误:

[Wed Mar 19 15:30:22.515457 2014] [cgid:error] [pid 3927:tid 140206699169536] (22)Invalid argument: [client 192.120.120.120:58349] AH01257: unable to connect to cgi daemon after multiple tries: /var/cgi-bin/echo.pl

我猜reload只是重新载入了服务器配置信息,并未将CGI进程启动,所以尽管已经配置了,但是由于CGI模块并未启动,所以自然也就没法连接CGI的守护进程。
所以,如果你只是修改了配置文件,reload就可以了,如果你启用或禁用了某个模块,需要restart,因为所有启用的模块,是在服务器启动过程中启动的。

稳妥的方式是restart Apache服务器,而不只是reload服务器。

3.3 404 Not Found

如果显示下面的错误信息:

[Wed Mar 19 15:35:13.487333 2014] [cgid:error] [pid 4194:tid 139911599433472] [client 192.120.120.120:58339] AH01264: script not found or unable to stat: /usr/lib/cgi-bin/echo.pl

echo.pl确实已经存在了,那么检查/etc/apache2/sites-enabled/000-default.conf中的DocumentRootScriptAlias是否配置正确。

3.4 403 Forbidden

如果你遇到403 Forbidden错误,问题一般也出现在/etc/apache2/sites-enabled/000-default.conf这里。检查<Directory>,确保里面涉及到权限的语句正确配置了。

4. 小结

CGI的方式运行perl是最直接最原始的方式,如果你已经成功地以CGI形式运行了perl脚本,建议你尝试下面的方式:

参考文章