一种网站架构方案

缘起

毕业之后的第一份工作跟edX相关。

edX是哈佛和MIT各资助了 3000万美元的开源项目,规模可想而知

一个多月来,几乎每天都在翻阅源码,以便做些定制并为移动端提供接口,目前大概骨架算是构建好了,平台运行得也还算稳定

这是我迄今为止折腾过最庞大的项目,粗略地把核心代码翻了一遍。算是对内部逻辑和数据流程有了大致的了解。

从edX中学到许多东西,关于如何构建一个复杂度大,灵活性高的大型项目。

我的确也再没见过比edX更复杂的web站点了

edX的架构

我后边要提到的架构方案结合edX来说可能比较容易说清楚它的意义和特性,这部分不应该忽略。

这实际上提供了为何需要这种架构的理由,如果我们做的只是一个博客或是企业官网,那么随意怎样最终都能折腾出来。

我们实际上是想为高复杂度高灵活性的需求提供解决方案。

关于edX的总体架构,暂时不多谈功能和逻辑上的部分,这部分可能牵扯到业务逻辑,我们点到为止

在此,重点说它的技术架构。

我们跟随数据流从后往前说

服务器:nginx+gunicore

这一部分没啥好说

nginx负责静态文件/反向代理(外部请求转发给端口)

gunicore是Python WSGI的HTTP服务器,用来跑django。

数据库:mysql,mongo

edX同时采用了mysql和mongo,关系型数据库(mysql)用来存储用户相关的信息,而mongo用来存储课程相关的信息。 (相关细节我记录在个人wiki里,暂未整理)

这么做的好处是什么,两个数据库管理起来明显是要麻烦的啊。

我想原因至少有两点:

  • edX的核心框架选择了django,django自带了用户系统,强大实用,且可扩展,对于edX已经足够,而django可用的数据库目前并未包括mongo,所以得用mysql
  • 用户模型,用户与其他东西的关系,也适合用关系描述,加上django的orm,其实使用起来十分方便。此外django中有许多跟用户模块相关的优秀第三方库,诸如django-rest-framework,django-social-auth,edX用上它们,许多工作都省事多了。

也就是说edX由于django的原因,必须用上一个关系型数据库。

pass:github上也有将mongo用作django后端数据库的第三方开源库,不过似乎社区都不活跃

那么使用mongo的原因呢: 应对课程部分的复杂度。

课程是edX的核心部分,我们从代码量上也可以轻易看出。mongo这种文档型/非结构型的特性,再合适不过了,数据模型的变化,根本不影响存储,类似json的树状结构数据,往数据库一丢就行,搜索也方便之极,都跟用上了orm一般方便,甚至可读性更好

此外mongo也存储论坛数据,文档型的树状结构数据使用mongo极其合适,而文档型数据,很可能数据模型常随需求变化,这也是mongo用着很爽的原因。你想啊,使用关系型数据库,django1.7之前如果不用south之类的工具,每次数据模型变更,烦都烦死

总结来说,使用mysql存储用户数据,可以利用django用户系统带来的便利。而使用mongo,可以方便应对灵活多变的文档型数据结构,而大多复杂数据都可以用这种树状结构描述,这也是json和xml使用广泛的原因,他们都是树状的

后端

edX网站后端使用django框架。
这是edX架构中我最熟悉的部分。
其实之所以毕业之后第一份工作选择edX,这也是重要原因。想先深入python/django
django是edX的核心部分,80%以上的代码都是用django写的。

django是个大而全的框架,像edX这种大项目使用django,就免去了大量的杂活。

此外django模板是一直为人诟病的地方,功能实在太鸡肋,于是edX使用了mako替代它,不得不说这是个明智之举,pythonic多了

此外论坛部分不在edx-platform里,论坛部分单独用ruby写,对外提供api接口,django去调用接口获取数据,所以可以将论坛视为一个黑箱服务,对外而言,看去和用django写的没有区别。

前端

前端mvc框架:backbone.js

edX的课程制作部分极其强大,与用户有大量的交互,有大量数据在与后端往来,如果手动操作DOM手动写ajax,估计要累的半死,而且极其容易出错。

backbone.js是前端mvc框架,不仅为代码提供了组织结构,还为我们干了大量杂活,让我们可以专注数据和业务逻辑,当然时下更流行的是angular.js.我也觊觎很久了,不过没怎么在项目中实践过,看了又忘。

此外CSS预处理器使用Scss,js预处理器使用coffeescript,前端自动化使用grunt.js,(依赖于nodejs)


我的架构方案

好啦,是时候亮出我从edX学到的架构方案啦,其实大多内容就是对上边做个总结。

当当当当

服务器

  • nginx
  • gunicore

数据库

  • mysql
  • mongo

mysql跟django紧密结合,主要使用其用户模块功能,其实这一部分功能强大之极。基本功能由django的auth模块提供,django还为我们提供了session(会话),csrf(安全性)等功能,几乎不花功夫就能得到的特性。真是免费的午餐

后端

  • django
  • django-rest-framework

django作为核心框架,提供了骨架和组织方式。

django-rest-framework为我们对外提供restful风格的api接口

重要的是!!

提供这些api接口几乎不费事,只要定义好model就几乎万事大吉了!包括麻烦的用户认证和权限等问题都有现成的解决方案

至于mongo部分,就由pymongo来操作,pymongo操作mongo,其舒适程度与使用orm无异,且查找功能还更清晰明了。当然这主要是mongo本身的特性。

前端

  • angular.js
  • bootstrap

angular.js与后端的django-rest-framework提供的接口交互

如此一来,模板使用angular.js的就行,不需要django的模板了,也避免符号问题

这样大多页面都是无刷新的!

很适合做大型web应用

自适应采用bootstrap

为移动端提供接口

  • nodejs

我最近正在做这一部分,使用nodejs来应对大量的并发请求。

数据来源,使用nodejs直接操控mongo,用户权限方面直接读取mysql中的数据表

当然nodejs有这两个数据库的orm

问题

目前存在问题,以及可能的解决方案:

  • mongo数据如何交给django-rest-framework返回给前端,django-rest-framework功能很全,可以重点用其序列化的功能
  • 重定向问题,前端来控制,或是使用response
  • django本身提供的许多特性,django-rest-framework都支持吗? 从文档上看,绝大多数核心功能都支持
  • 好像存在一个内在矛盾,django-rest-framework需要model,而model本身是结构化的,就是说django和mongo其实不怎么关联。 这部分让django-rest-framework只处理序列化的工作。也就是说django-rest-framework在标准接口中用快捷方式,否则用底层更灵活的方式
  • 让mongo专注于提供文档数据,django-rest-framework来处理权限
  • 让mysql用字段去记录mongo文档对象的id?相当于外键?还是让mongo中记录user id,来管理用户与数据。后者似乎更恰当。 django在后端负责验证,提取request,本质是sessin,而session本质是核对过的用户名与密码,如果用户是他宣称的身份,则允许这个身份操作自己的数据。以上分析中我们学会这样一种方法,id可以用来关联两者,作为定位符,实际上这也是外键的本质。同时我们发现后端其实无所不能,那里混沌未开,一切数据都可以随意流动,我们人为地对其做限制,划分权职,我们采用身份,权限这些概念,让逻辑清晰,这样才可以映射现实,从而为现实服务,本质是我们在运用逻辑和概念,语言和框架是实施和表达这些想法的工具。



Fork me on GitHub