实习
近期在某家公司实习,顺应公司部门文化有一场为期十天左右的实习生小组赛,内容就像 黑客马拉松 一样。
正好在此小组负起后台开发的职责,技术选择是 python 的 Web框架 Flask , 至于本文想要记录的并不是 flask 这个框架怎么用,好不好用,而是其他一些一直以来比较零散的知识
也许这是在学校中开发所注意不到的,那就是实际情况总是与理想状态相去甚远。
架构图
![后台开发之架构]()
这个结构是我为本小组提供的后台拓扑,包含三个部分: Nginx 反向代理 Flask 逻辑服务器 mysql 数据库服务器 看起来非常朴实,实际上门门道道,细节问题着实费了我两天时间,特别是在逻辑服务器哪里,因为粗心大意,愣是搭了一个晚上还是失败。 本次是将终端和前端的接口进行了统一,实际上这样对一个快速开发项目来说的确是必须的,不必考虑太多细节,追求的是效率,毕竟 Flask 框架追求的的确就是开发效率,至于并发情况实际上在众多框架中,并不能算太好。 开始记录 Nginx反向代理 这个的应用应该是非常广泛的,而且十分有效 立竿见影的效果就是屏蔽了后端的大部分细节,提高了容错性,以及其本身就是一个超高性能的静态资源服务器,更是能够帮助很多应用提升性能。 在linux下安装 Nginx 就像明面上说的那么简单,但是一般主流的发行版中的 Nginx 的版本都 比较低 ,所以可能有时候用起来不如传闻中的那么神速。 于此你可以选择接受它 或者去官方网下载最新的稳定版本,按照步骤一步一步的安装。 在这里就不再详述,这要是详细记录,又是一个独立的话题了。 Nginx 在Ubuntu下,默认配置文件放在了 /etc/nginx/nginx.conf 以及 /etc/nginx/site-available/default 中 一般情况下,我们修改后者就行,改前记得先备份 Nginx 有自己的URL一套匹配规则,通俗的来说就是将一个完整的链接解析成服务器知道的绝对路径
![后台开发之架构]()
配置完以后,你会发现状态变了,这样才算成功。

这个结构是我为本小组提供的后台拓扑,包含三个部分: Nginx 反向代理 Flask 逻辑服务器 mysql 数据库服务器 看起来非常朴实,实际上门门道道,细节问题着实费了我两天时间,特别是在逻辑服务器哪里,因为粗心大意,愣是搭了一个晚上还是失败。 本次是将终端和前端的接口进行了统一,实际上这样对一个快速开发项目来说的确是必须的,不必考虑太多细节,追求的是效率,毕竟 Flask 框架追求的的确就是开发效率,至于并发情况实际上在众多框架中,并不能算太好。 开始记录 Nginx反向代理 这个的应用应该是非常广泛的,而且十分有效 立竿见影的效果就是屏蔽了后端的大部分细节,提高了容错性,以及其本身就是一个超高性能的静态资源服务器,更是能够帮助很多应用提升性能。 在linux下安装 Nginx 就像明面上说的那么简单,但是一般主流的发行版中的 Nginx 的版本都 比较低 ,所以可能有时候用起来不如传闻中的那么神速。 于此你可以选择接受它 或者去官方网下载最新的稳定版本,按照步骤一步一步的安装。 在这里就不再详述,这要是详细记录,又是一个独立的话题了。 Nginx 在Ubuntu下,默认配置文件放在了 /etc/nginx/nginx.conf 以及 /etc/nginx/site-available/default 中 一般情况下,我们修改后者就行,改前记得先备份 Nginx 有自己的URL一套匹配规则,通俗的来说就是将一个完整的链接解析成服务器知道的绝对路径
例如: http://www.domain.com/index.html 解析成服务器上的 /var/www/html/index.html 路径
这个匹配规则,也是可以单独写成一个话题,那么直接看本次配置的时候遇到的一个问题:除了几种特殊情况意外,其他路径都返回 index.html 这个文件,该如何做到?
server { listen 8080; server_name xxx.xxx.xxx.xxx; #公网地址 location /api/ { include uwsgi_params; uwsgi_pass 127.0.0.1:7001; # 指向uwsgi 所应用的内部地址,所有请 求将转发给uwsgi 处理 uwsgi_param UWSGI_CHDIR /data/mini/www; # 指向网站根目录 uwsgi_param UWSGI_SCRIPT manage:app; # 指定启动程序 } location ~ ^/(js|css)/{ root /data/mini/source/Mini_Production/build; } location ~ ^/(img|lib)/{ root /data/mini/source/Mini_Production/static; } location / { root /data/mini/source/Mini_Production/; index index.html; try_files $uri /index.html; } }重点在于最后一个 location 解决了我的问题
至于其他的规则,网上详细叙述的太多了,这里只是记录一个特殊情况。
说完这个就该来说说,反向代理的简单配置了
说是简单配置,因为将会使用 Nginx 自带的功能,而不引入第三方模块的功能 由于服务的需求,我们的应用需要保存 session ,所以 Nginx 反向代理的时候必须要保证的一个地方就是:同一个 IP 必须反向代理到同一个服务器上,否则会导致某些意想不到的错误。 而Nginx自带的两个策略之一 ip_hash 正为此而生。反向代理的配置分为两个块, upstream 和 server
直接写在 /etc/nginx/nginx.conf 里就行
upstream yuehuo{ ip_hash; server xxx.xxx.xxx.xx1:8080; server xxx.xxx.xxx.xx2:8080; ... } server { listen 9090; location / { proxy_pass http://yuehuo; proxy_set_header X-Real-IP $remote_addr; } }有几台在 upstream 写几个 server ,以分号结尾,这样一来就实现了一个最简单的反向代理,对于晓得项目而言其实是已经足够了。
不用怀疑什么, Nginx 是一个很成熟的开源项目,不像某些开源产品只是一副外壳而已。
实际上,着一些就构成了我们小组后台结构的第一部分,也就是理论上暴露给外部的访问点,就是这台独自承载着 Nginx 反向代理功能的服务器。 任何有效访问只需要访问这台服务器,就能得到他们想要的东西,而不需要去记下多台服务器的域名或者IP。 而我也可以随时替换后端的服务器,并且服务的请求者什么也不会察觉。 甚至还可以配置一个 backup ,在所有服务器都崩溃的时候,它能挽救一下局面。所谓的最初级的容灾。 Flask逻辑服务器 在这个部分,实际上是用的是 Nginx + Supervisor + uwsgi + Flask 进行的搭建 看起来很复杂,很多组建,实际上也就这样: Nginx用来引导所有请求至正确的位置:动态请求转发给 Flask ,静态资源自己处理就行。 uwsgi 则是 Flask 运行的一个平台,不在叙述,可以将两者看成一体,实际上从上面的 Nginx 配置文件中也能发现一些端倪。 其实这样已经能够很好完整的服务各方了,那为什么还有一个 Supervisor 呢?就是为了让这个服务更加规范和自动化,这相当于一个自动化可配置的 uwsgi 启动器(写过 ruby on rails 的应该也很熟悉这个东西)。 Nginx 的配置就如上所示,在 etc/nginx/sites-available/default 里写入上一个模块介绍的内容 安装完 Supervisor 和 uwsgi 之后,将 uwsgi 的配置文件存放好,比如放在 flask 程序的结构包里,总之记好路径,在之后的 Supervisor 中会用到,之后写好它的配置文件之后,启动它的服务就行。 讲的有点泛泛但是却没什么难点,细心一些就能配置对,当然是找到网上的配置教程。 从前端上传的图片,被存放在了 Flask 逻辑服务器上,但是这导致一个缺点,就是如何同步多台逻辑服务器之间的图片资源? 虽然图片是静态资源的一种,但是它具有动态更新的可能性,所以解决方案可以有两种:多台服务器同步或者单独存放在一个独立的图片服务器上。 前者的缺点很明显,这是当前技术领域最难的分布式同步问题。后者相对容易而且能带来很不错的性能,可以选择专业的图片存储服务商,或者自己搭建。 当前架构还算小规模,暂时使用 scp 定时拷贝的策略来同步。总体来说,Flask 服务器被配置成 Nginx -> supervisor(uwsgi -> flask) 的模式
马马虎虎可以的配置教程 数据库分离 之 数据库服务器与读写分离 这个部分是耗时比较久的 首先问题描述: 如果数据库内嵌在 flask Server 中,万一某台 Flask Server 宕机,同时也会损失一台数据库服务。 多台 flask Server 中内嵌的数据库之间的数据该如何做同步? Flask Server 服务器是否过于臃肿 综上问题,我们相出将数据库从 Flask Server 提出来,以分布式的方式实现 首先需要对 Flask Server 做一下数据库系统的透明处理,意思就是让无论多少台 Flask Server 都只感觉在操作同一个数据库。 首先想到数据库中间件 MySQL-Proxy ,做一个读写分离 配置主从数据库,以此实现容灾以及性能提升。 首先将数据库放在单独的服务器中,配置成 一主多从 的的模式,即 一写多读 ,其中 主服务器可读可写 这个可以实现的是,当主数据库被写的时候,可以同步更新到从服务器上。 这么做的目的就是将读的性能大大提升。 其次对前方屏蔽数据库系统的细节,即增加中间件的存在 将之前实现的数据库系统,接在 MySQL-Proxy 的后方,让其帮助我们实现读写分离的功能。 也可以实现 多主多从 的效果,远离和一主多从十分类似,就是将两台 主数据库,互相配置成主从。并在主服务器的MySQL配置的 [mysqld] 选项中增加 log_slave_update 标志 两篇好教程: MySQL数据库主从配置 MySQL-Proxy配置读写分离实现上的细节
当 slave 出现: Connecting to master 且错误码为 2003 的时候,你需要看看你的 MySQL 配置中是否有 bind-address = 127.0.0.1 这个选项,注释掉它
配置完以后,你会发现状态变了,这样才算成功。
万年不变的 MySQL 中文问题
在所有方法都查证之后,四方编码都为 UTF-8 时,却发现还是不行 这时候,可以尝试将整个数据库 Drop ,之后重建。这样会使刚才的配置生效在这个数据库上 其实数据库可以不必 DROP ,只需要将表删了重建即可。 反思 一个最大的问题就是,如果数据已经多到一个 DB 存不下,不得不用多数据库来存储的时候,该怎么办? 这个是我们这个架构最致命的缺点。 如果有更好的解决方案,我再记录