厉害一些的服务器设计(1)
Context
这段时间看了一些架构师的书,感觉是时候练习一下了。
一开始订了一个小目标,做一个http+socket的服务器
后来想了想,把celery加进来
再想把redis也加进来
最后这个就变成了一个更厉害一点儿的系统了
http<->nginx<->uwsgi<->django->rabbitMQ,redis,celery<->twisted<->socket->->->->->
由于最近还看了微服务的书,所以最后甚至想做一个分布式的服务器了!
Plan
这里不讲方案的演变过程,直接讲最后最后确定的方案。
一台高性能服务器装有 nginx,uwsgi,django,rabbitMQ,redis,twisted,celery
两台低配服务器有 twisted和celery
把这整个项目想像成,共享单车(非蓝牙开锁的)服务器架构~高性能服务器用来接受所有的http请求(手机app),所有服务器的twisted用来处理socket请求(共享单车)
其中celery用来做部分异步操作(假设有发短信,发送单车指令)的负载均衡
rabbitMQ用来做celery和twisted的Message Broker。celery的相关操作是自带的,不需要再写很多。而twisted集成rabbitMQ就需要用到pika,需要写一些东西才行。
redis用来做celery的task记录备份数据库,可有可无。
nginx,uwsgi,django不用介绍,就那些功能
最后还要使用JMeter来进行压力测试
Let’s do it
其实这个项目这样理一下,还是挺清晰的。
django就这么搭建,uwsgi和nginx就这么配置。
celery是最近重新好好看了文档之后又拾起来的东西,之前没有好好地用过它,只是知道它好像可以做异步操作而已。
celery
celery在介绍中就写了Broker,很明显他也是用消息队列来做进程间通信的。
celery对django有非常好的支持,具体的配置就要看这里
这里来一段假装是发送短信的异步操作,print这个地方改成一个向SMS网关发送请求的代码,就可以做到发送短信了。因为django的view里面的处理函数需要返回一个response,
但是django自带的发送网络请求的函数都是同步的,所以用了celery就可以很快速的返回一个response给客户端,在此同时再去发送短信,这就不会导致一个http请求产生多方等待的问题。
tasks.py中定义任务:
@shared_task
def send_sms(number, code):
print "sending sms to {} with code {}".format(number, code)
view.py中调用:
@csrf_exempt
@require_POST
def send_sms(request):
parameter = request.POST
tasks.send_sms.delay(parameter["code"], random.randint(1000, 9999))
return JsonResponse({"status": "succeed"})
配置的话,还挺重要的,我搞了一个celeryConfig.py,因为最后会涉及多个服务器一起部署,各自的参数会不一样,所以用一个外置文件来配置,很舒服(要把它gitignore了)
celeryConfig.py:
from __future__ import absolute_import
broker_url = 'amqp://***:***@10.139.***.***:5672/myvhost'
result_backend = 'redis://10.139.***.***:6379/0'
task_serializer = 'json'
result_serializer = 'json'
accept_content = ['json']
enable_utc = True
result_expires = 60
这样配置rabbitMQ和redis的服务器路径就很方便了。
redis
上面说到的celery用到了10.139.***这样的内网ip,没错,现在多台服务器是共用一个redis的,所以需要配置redis让他可以对外
开放
网上很多都说去掉bind 127.0.0.1,关闭protect-mode就好,但是我觉得这个方法并不好,因为直接去掉这一行,会向全网开放,而我只想在内网开放,所以只要把
bind 127.0.0.1
改为
bind 10.139.*** 127.0.0.1
就好了。
但是这样运行起来说不定还是不行,可能会”could not connect”,因为linux还没有把这个端口对外开放。使用这个明令把6379端口给开了
/sbin/iptables -I INPUT -p tcp --dport 6379 -j ACCEPT
然后保存一下
/etc/rc.d/init.d/iptables save
这样应该就ok了
某天晚上想给别人装个逼,打开终端一看,redis跪了。之后发现redis只要运行一段时间就跪了,而且杀不掉,只能重启。之后回到寝室看了报错内容
Failed opening the RDB file dump.rdb (in server root dir /*****) for saving: Permission denied
其实问题很简单,只要把这句话里面的路径的文件的权限给了就行,就会自动恢复。
nginx uwsgi django
这三个东西可以说是用的很熟悉了的~
不过这次想要玩点儿新花样。nginx和uwsgi之间使用socket来通信,而不是直接端口映射
uwsgi.ini:
# mysite_uwsgi.ini file
[uwsgi]
# Django-related settings
# the base directory (full path)
chdir = /***
# Django's wsgi file
wsgi-file = httpServer/wsgi.py
# the virtualenv (full path)
home = /***/venv
master = true
processes = 10
# the socket (use the full path to be safe
socket = /***/advServer.sock
chmod-socket = 664
uid = www-data
gid = www-data
vacuum = true
workers=24
listen=65535
启动之后,nginx访问这个socket总是说permission denied,即便使用的sudo也不行。后来查到资料说,要他们有相同的user和group才行。但是我明明在ini中已经设置了和nginx相同的user和group,却还是报错。
于是最后我只能开大招了:
sudo chown www-data:www-data /***/advServer.sock
真的有效
rabbitMQ
先说说Mac安装了rabbitMQ之后会出现的一个很小很小的问题吧~
运行了./rabbitmq-server之后没反应,过了一会儿提示
error:epmd error for host ******: timeout
这个很简单,只要把这个*加入host就好了
修改/etc/hosts,增加:
127.0.0.1 *****
再试即可!
Pause
今天先整理到这里,明天再把twisted,pika部分的内容整理出来!
睡觉~