先说一下需求的场景,策划部门想做一个垂直领域的社区产品,类似与知乎那种,但受益人群是金融行业的从业人员。产品中有一个搜索问题的需求,搜索的问题去题库中进行模糊匹配,终端支持H5/APP/小程序,甚至是微信的自动回复,用过ItChat的人都知道这个强大的工具包,不过最近好像有封号的动作了。做搜索,肯定就会用到分词,当前开源的分词库jieba是做的比较好的了,分析了一下技术栈,就决定用flask来实现一个微服务,供其他的服务模块使用。
本人会着重讲一下环境的搭建,各种配置的坑。
0x01 升级操作系统
操作系统:CentOS 6.x
CentOS 7的玩家手动跳过该环节。首先6.x的版本,默认装的python的版本是2.6的版本,这个版本后面用到的一些软件支持的不是很好,所以我们首先要把python升级到2.7的版本。先创建一个update.sh脚本,然后把下面内容复制进去。
#!/usr/bin/env bash #安装依赖 yum install openssl openssl-devel zlib-devel gcc -y # apt-get install libssl-dev # apt-get install openssl openssl-devel # 下载源码 wget http://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz tar -zxvf Python-2.7.12.tgz cd Python-2.7.12 mkdir /usr/local/python2.7.12 # 开启zlib编译选项 # sed -i '467c zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz' Module/Setup sed '467s/^#//g' Module/Setup ./configure --prefix=/usr/local/python2.7.12 make make install if [ $? -eq 0 ];then echo "Python2.7.12升级完成" else echo "Python2.7.12升级失败,查看报错信息手动安装" fi cd mv /usr/bin/python /usr/bin/python2.6.6 ln -s /usr/local/python2.7.12/bin/python2.7 /usr/bin/python sed -i '1s/python/python2.6/g' /usr/bin/yum wget --no-check-certificate https://bootstrap.pypa.io/get-pip.py python get-pip.py if [ $? -eq 0 ];then echo "pip升级完成" else echo "pip安装失败,查看报错信息手动安装" fi rm -rf /usr/bin/pip ln -s /usr/local/python2.7.12/bin/pip2.7 /usr/bin/pip
然后把这个脚本加上可执行的权限,并且运行。
chmod u+x update.sh
./update.sh
0x02 创建python虚拟空间
这一步完成之后,我们就开始隔离一个虚拟的空间来运行这个微服务,以后我们所有的程序都在隔离的虚拟空间中来运行,有点docker的概念,这样不管是用python2.x还是3.x都可以同时兼容了。
pip install virtualenv
cd /home/test/web
virtualenv ENV
cd bin
source active
至此就启动了这个docker,接下来就是在这个docker中安装我们requirement.txt中所需要的包了。
我们用的包有如下:
pip install flask pip install jieba pip install pymysql pip install redis pip install virtualenv pip install uwsgi pip install xlrd
到此为止就可以在ENV的环境中,测试app的功能了,现在python myapp.py试一下各接口功能。
0x03 安装nginx
尽管测试成功了,但是线上是不能这么运行的,因为flask只是一个web框架,并不是一个web server的容器,flask自带的werkzeug只能用于开发环境,不能用于生产环境,对于web服务器,我们选择更专业的uWSGI,并且配合nginx作为反向代理。
首先,我们安装nginx
yum -y install nginx
默认的nginx的监听端口是80,如果部署在云服务器上,80端口极大的可能被占用了,我们要去修改这个配置文件。
cd /etc/nginx
vim conf.d
查看一下配置端口的配置文件在哪里,我们看到是default.conf这个文件中有端口号的配置,我们把所有端口号都改成我们想要的端口比如8100。
在 /etc/nginx/ngixn.conf 文件的 http 部分添加一条 include 内容,即最后一行
http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; include /etc/nginx/sites-enabled/*; }
创建配置文件 vim /etc/nginx/sites-enabled/hello.conf
server { # Running port listen 8100; # 服务器ip 或者域名 server_name 0.0.0.0; # Proxying connections to application servers location / { include uwsgi_params; uwsgi_pass 127.0.0.1:5000;//和 uWSGI 配置文件中的 ip端口一致 } }
然后看系统中是否有nginx的service脚本
vim /etc/init.d/nginx
如果没有该脚本,在该脚本中写如下内容:
#!/bin/bash # chkconfig: - 85 15 nginx=/usr/sbin/nginx conf=/etc/nginx/nginx.conf case $1 in start) echo -n "Starting Nginx" $nginx -c $conf echo " done" ;; stop) echo -n "Stopping Nginx" $nginx -s stop echo " done" ;; test) $nginx -t -c $conf ;; reload) echo -n "Reloading Nginx" $nginx -s reload echo " done" ;; restart) $0 stop $0 start ;; show) ps -aux|grep nginx ;; *) echo -n "Usage: $0 {start|restart|reload|stop|test|show}" ;; esac
给该文件加上可执行权限
chmod u+x nginx
service nginx start
Nginx 在 /var/log/nginx 目录下有 access.log 和 error.log 两个日志文件,如果有问题可以查看这2个日志文件。
0x04 配置uWSGI
接下来配置uWSGI的启动文件,创建 uwsgi 配置文件
vim /etc/uwsgi/apps-enabled/hello.ini
[uwsgi] // 开启主线程 master = true // 项目目录 base = /home/test/web // 移动到项目目录 cd chdir = %(base) // 本地的ip和端口 socket = 127.0.0.1:5000 // Python 虚拟环境目录 home = %(base)/ENV // 程序启动文件 wsgi-file = hello.py // 项目中引用 flask 实例的变量名 callable = app // 处理器数 processes = 2 // 线程数 threads = 4 // 获取uwsgi统计信息的服务地址 stats = 127.0.0.1:9191
保存配置文件,通过 uwsgi -i /etc/uwsgi/apps-enabled/hello.ini,来启动 uwsgi。
注意在env的环境下,uwsgi安装的目录不会在/usr/bin中,而是在ENV的bin中,所以
在后面的/etc/init.d/uwsgi中的路径要注意。
创建uWSGI的日志文件
vim /var/log/uwsgi/hello.log
创建uWSGI的service文件
vim /etc/init.d/uwsgi
#!/bin/bash # chkconfig: - 85 15 uwsgi=/home/test/web/ENV/bin/uwsgi hello_conf=/etc/uwsgi/apps-enabled/hello.ini case $1 in start) echo -n "Starting uWsgi" nohup $uwsgi -i $hello_conf >/var/log/uwsgi/hello.log 2>&1 & echo " done" ;; stop) echo -n "Stopping uWsgi" killall -9 uwsgi echo " done" ;; restart) $0 stop $0 start ;; show) ps -ef|grep uwsgi ;; *) echo -n "Usage: $0 {start|restart|stop|show}" ;; esac
添加可执行属性
sudo chmod +x /etc/init.d/uwsgi
service uwsgi start
uWSGI 在 /var/log/uwsgi 目录下有项目对应日志,有问题可以查看。
0x05 redis的安装
首先安装redis的编译工具gcc和gcc-c++
yum install gcc gcc-c++
然后从redis的官网上下载redis并且安装
wget http://download.redis.io/releases/redis-3.2.5.tar.gz tar -zxvf /soft/redis-3.2.5.tar.gz cd redis-3.2.5 make & make install
然后配置redis.conf
bind 0.0.0.0
# 3.x版本,将此属性关闭
protected-mode no
添加redis的service服务
vim /etc/init.d/redis
#!/bin/sh # # Simple Redis init.d script conceived to work on Linux systems # as it does use of the /proc filesystem. REDISPORT=6379 EXEC=/usr/local/bin/redis-server CLIEXEC=/usr/local/bin/redis-cli PIDFILE=/var/run/redis_${REDISPORT}.pid CONF="/etc/redis/${REDISPORT}.conf" case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed" else echo "Starting Redis server..." $EXEC $CONF fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE does not exist, process is not running" else PID=$(cat $PIDFILE) echo "Stopping ..." $CLIEXEC -p $REDISPORT shutdown while [ -x /proc/${PID} ] do echo "Waiting for Redis to shutdown ..." sleep 1 done echo "Redis stopped" fi ;; *) echo "Please use start or stop as first argument" ;; esac
然后启动服务
chmod u+x redis
service redis start
0x06 python中引入redis作为缓存
我们知道redis是k-v的数据缓存机制,当缓存数据为string, 或是hash类型的时候,都有原生的函数支持,具体可以参考redis的API文档。
但是当我们缓存我们自定义的实体类的时候,有点力不从心,这时候可以用pickle库来做序列化,先把实体类转换成string类型存储在redis中,取出的时候,再做反序列化的操作,具体代码如下:
#coding=utf-8 import redis import pickle class Redis: @staticmethod def connect(host='localhost', port=6379, db=0): r = redis.StrictRedis(host, port, db) return r # 将内存数据二进制通过序列号转为文本流,再存入redis @staticmethod def set_data(r, key, data, ex=None): r.set(pickle.dumps(key), pickle.dumps(data), ex) # 将文本流从redis中读取并反序列化,返回 @staticmethod def get_data(r, key): data = r.get(pickle.dumps(key)) if data is None: return None return pickle.loads(data)
0x07 总结
到此为止,一个flask的app的部署就基本完成了,中间的环节比较琐碎,但互联网上的资料也很多,基本都可以解决,祝大家玩的开心!