美文网首页
一次flask+redis的微服务实战

一次flask+redis的微服务实战

作者: Hefe | 来源:发表于2018-02-06 15:55 被阅读0次
    flask

    0x00 背景

    先说一下需求的场景,策划部门想做一个垂直领域的社区产品,类似与知乎那种,但受益人群是金融行业的从业人员。产品中有一个搜索问题的需求,搜索的问题去题库中进行模糊匹配,终端支持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的部署就基本完成了,中间的环节比较琐碎,但互联网上的资料也很多,基本都可以解决,祝大家玩的开心!

    相关文章

      网友评论

          本文标题:一次flask+redis的微服务实战

          本文链接:https://www.haomeiwen.com/subject/anvgzxtx.html