Flask+nginx负载均衡综合使用

2台机子模仿负载均衡的实验.

本机IP:115.213.73.254 

云主机IP:xxx.xxx.xxx.xxx(保密起见,下同) 公网IP

本机运行连接云主机:

ssh ubuntu@某大佬 -p 10070

---------------------------------------云主机上运行netstat -pan结果如下------------------------------------------------

tcp        0    464 192.168.1.109:22        115.213.73.254:16328    ESTABLISHED -                   
tcp        0      0 192.168.1.109:22        115.213.73.254:16890    ESTABLISHED -                   
tcp        0      0 192.168.1.109:22        115.213.73.254:16253    ESTABLISHED -   

可以看到:

192.168.1.109是云主机的局域网IP

115.213.73.254:16328是台式机所属路由器的端口

----------------------------------自己台式机上运行netstat -pan结果如下-----------------------------------------------------

(python3.6) appleyuchi@ubuntu:~$ netstat -pan|grep 10070
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 192.168.0.101:47450     xxx.xxx.xxx.xxx:10070       ESTABLISHED 8775/SecureCRT      
tcp        0      0 192.168.0.101:47534     xxx.xxx.xxx.xxx:10070       ESTABLISHED 8775/SecureCRT 

192.168.0.101:47450是自己台式机的局域网IP和端口

啦啦啦:10070是云主机的IP和防火墙端口

-------------------------------------------------概念总结--------------------------------------------------------------------------------------------

端口监听就是端口占用

上面涉及了四种端口

本机局域网端口->路由器端口->云主机防火墙端口->云主机内部局域网端口

因为本机是没有公网端口的,所以本地netstat查到的端口与云主机netstat查到的端口是不对应的

主要流程:

云主机内部局域网端口->云主机内部防火墙端口->云主机管理平台防火墙端口->客户路由器端口->客户本地端口->访问内容。

-------------------------------------------能不能用命令查询云主机管理平台防火墙?------------------------------------------------------------------

管理员大大说,refused还是drop都是云主机管理平台设定的,所以不能根据信息来判断端口到底咋了。

问了其他几位网友也是:不能用命令查。

 

命令查询防火墙端口是否没开:

云主机内部:

1.用web app监听一个port的情况下,

2.自己的台式机telnet 云主机IP 端口,返回connection refused

满足上述两个条件,就表示云主机管理平台防火墙端口没开。

-----------------------------------------------------------实验架构--------------------------------------------------------------------------

我们用两台机子,调度分发的时候,一台是发给自己,一台是发给云主机。

Flask+nginx负载均衡综合使用_第1张图片

------------------------------------------------------web app部署、nginx配置、测试-------------------------------------------------------------------

1.《Flask Web开发:基于Python的Web应用开发实战》第四章的代码,具体操作如下:

①git clone https://github.com/miguelgrinberg/flasky

②gitcheck out 4c

③把上述步骤得到的文件夹分别拷贝到本机和云主机任意位置。

分别修改本机和云主机和hello.py,具体修改在文末附录。

分别本机和云主机执行

python3 hello.py

2.

①文末附录的两个nginx.conf分别放到本机和云主机的/etc/nginx/路径下,

②nginx -s reload

3.测试:

chromium浏览器(不要使用Chrome浏览器,因为它会自动补充斜杠"/"导致访问失败,很讨厌,当然可以自己额外去hello.py中修改)

打开http://127.0.0.1:9020/flask_learn2

多打开几次会发现效果如下:

Flask+nginx负载均衡综合使用_第2张图片

Flask+nginx负载均衡综合使用_第3张图片

负载均衡成功。

-----------------------------------------------实验分析与调试---------------------------------------------------------------------

如果运行失败,检查以下环节:

不要在nginx.conf中使用ngrok穿透出来的网址,容易失败。

理清楚端口之间的关系,不要把端口设置重复了。

查清楚上面的“概念总结”中每一层端口是否被封

 

整体端口占用示意图:

                       /本机127.0.0.1:9002->本机127.0.0.1:9000

本机:9020

                        \云主机xx.xx.xx.xx:10072->云主机127.0.0.1:10071

上述9020,9002,10072端口都被nginx占用,其余都被Flask web app占用

 

另外,检查端口是否被占用,可以使用:

lsof -i:port

-------------------------------------------------附录-代码-------------------------------------------------------------------------

云主机的hello.py

from flask import Flask, render_template, session, redirect, url_for, flash
from flask_bootstrap import Bootstrap
from flask_moment import Moment
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

bootstrap = Bootstrap(app)
moment = Moment(app)


class NameForm(FlaskForm):
    name = StringField('What is your name?', validators=[DataRequired()])
    submit = SubmitField('Submit')


@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500


@app.route('/flask_learn2', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():#用戶第2次以上訪問程序,這個地方的有效性(validate)驗證就是看你輸入了東西沒,沒輸入東西的話就會提醒你輸入
        print(dir(session))
        old_name = session.get('name')#直接從回話中讀取name參數的值
        # old_name = session['name']
        #session用来跨请求保存数据!
        # old_name没有跨请求的能力
        
        print("old_name=",old_name)
        if old_name is not None and old_name != form.name.data:#form.name.data是html页面传过来的新数据
            flash('Looks like you have changed your name!')
        session['name'] = form.name.data
        return redirect(url_for('index'))
    if session.get("name") is None:
        print("进入if")
        return render_template('index.html', form=form, name=session.get('name'))#用戶第一次訪問程序
    else:
        print("进入else")
        return render_template('index.html', form=form, name=session.get('name')+"当前是(云主机)")
    #form.name.data最新提交的數據,但是這個請求一旦結束,數據就丟失了
    #session.get('name')老數據
    #session['name']老數據
    #從上面的代碼來看,session['name']完全等效於session.get('name')


#----------------------------关闭被占用的端口-----------------------------------------
def killport(port):
    command='''kill -9 $(netstat -nlp | grep :'''+str(port)+''' | awk '{print $7}' | awk -F"/" '{ print $1 }')'''
    os.system(command) 

if __name__ == '__main__':
    port=10071
    app.run(host="127.0.0.1", port=port)

本机(就是自己的电脑)中的hello.py如下:

from flask import Flask, render_template, session, redirect, url_for, flash
from flask_bootstrap import Bootstrap
from flask_moment import Moment
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

bootstrap = Bootstrap(app)
moment = Moment(app)


class NameForm(FlaskForm):
    name = StringField('What is your name?', validators=[DataRequired()])
    submit = SubmitField('Submit')


@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500


@app.route('/flask_learn2', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():#用戶第2次以上訪問程序,這個地方的有效性(validate)驗證就是看你輸入了東西沒,沒輸入東西的話就會提醒你輸入
        print(dir(session))
        old_name = session.get('name')#直接從回話中讀取name參數的值
        # old_name = session['name']
        #session用来跨请求保存数据!
        # old_name没有跨请求的能力
        
        print("old_name=",old_name)
        if old_name is not None and old_name != form.name.data:#form.name.data是html页面传过来的新数据
            flash('Looks like you have changed your name!')
        session['name'] = form.name.data
        return redirect(url_for('index'))
    if session.get("name") is None:
        print("进入if")
        return render_template('index.html', form=form, name=session.get('name'))#用戶第一次訪問程序
    else:
        print("进入else")
        return render_template('index.html', form=form, name=session.get('name')+"当前是(本地)")
    #form.name.data最新提交的數據,但是這個請求一旦結束,數據就丟失了
    #session.get('name')老數據
    #session['name']老數據
    #從上面的代碼來看,session['name']完全等效於session.get('name')


#----------------------------关闭被占用的端口-----------------------------------------
def killport(port):
    command='''kill -9 $(netstat -nlp | grep :'''+str(port)+''' | awk '{print $7}' | awk -F"/" '{ print $1 }')'''
    os.system(command) 

if __name__ == '__main__':
    port=9000
    app.run(host="127.0.0.1", port=port)

-------------------------------------------------附录-nginx-----------------------------------------------------------------------

云主机完整nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip on;
        gzip_disable "msie6";

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;



server {
    listen       10072;
    #server_name  mycard.moe;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;



    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://127.0.0.1:10071/;      
        fastcgi_intercept_errors on;  
proxy_redirect off;
    }

}



}

 

本地完整nginx.conf(下面公网IP:xx.xx.xx.xx需要改成自己的)

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types;
        default_type application/octet-stream;

        ##
        # SSL Settings
        ##

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
        ssl_prefer_server_ciphers on;

        ##
        # Logging Settings
        ##

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;

        ##
        # Gzip Settings
        ##

        gzip on;
        gzip_disable "msie6";

        # gzip_vary on;
        # gzip_proxied any;
        # gzip_comp_level 6;
        # gzip_buffers 16 8k;
        # gzip_http_version 1.1;
        # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

        ##
        # Virtual Host Configs
        ##

        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;




    upstream myapp{
        server 127.0.0.1:9002 weight=5;
        server xx.xx.xx.xx:10072 weight=5;
        #server srv3.example.com;
    }
    server{
        listen 9020;
        #server_name
        location / {
            proxy_pass http://myapp;
        }
    }



server {
    listen       9002;
    #server_name  xxx.cn

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;



    location /{
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://127.0.0.1:9000/;
        proxy_redirect off;
    }

}



}

-------------------------------------------------------相关资料阅读和小记------------------------------------------------------------

[1]提到了各种负载均衡的类型(看完了)

[2]提到了flask+uwsgi

根据[3],uwsgi和gunicorn是两个相似的东西

[4]提到了nginx负载均衡, 并且有localhost测试的极好案例。

[5]提到了动静分离(动态网络资源和静态网络资源)

[6]nginx+Django+uwsgi

[7]提到了nginx对四层和七层的负载均衡的实现.

[8]提到了多个nginx的配置文件...不知道怎么一起操作.

[9]中server和upstream一起使用

[10]中一个conf文件里面有多个upstream,不知道含义是什么

[11]中提到,upstream是用来跨越单机(意思应该是转发给别的单机)

三台服务器,需要3个nginx.conf,但是每台机子上的nginx.conf内容都是不同的.

 

Reference:

[1]http://www.ttlsa.com/nginx/using-nginx-as-http-loadbalancer/

[2]https://my.oschina.net/RabbitXiao/blog/1583662

[3]https://segmentfault.com/q/1010000008927097/a-1020000008927326

[4]https://www.jianshu.com/p/4c250c1cd6cd

[5]https://blog.51cto.com/13178102/2063271

[6]https://segmentfault.com/a/1190000016108576

[7]https://www.jb51.net/article/153710.htm

[8]https://www.cnblogs.com/crazymagic/p/11029415.html

[9]https://www.cnblogs.com/winniejohn/p/9855351.html

[10]https://www.cnblogs.com/diantong/p/11208508.html

[11]https://blog.csdn.net/gu_wen_jie/article/details/82149003

你可能感兴趣的:(Flask,nginx的使用)