NodeJS与Django协同应用开发(2)—— 业务框架


系列目录


这篇文章主要会讲业务的框架设计,不过可讲内容不会那么多,毕竟不能将公司业务细节公布出来,权当抛砖引玉。

目前来说我们的业务只有一个实时性的要求,简单来说就是多人共同参与一场活动,每个人都能看到其他人的操作,此外还有一部分用户授权系统模拟其自身操作的业务。我们分别说一下开发过程中的几个问题。

首先是系统的入口。
为了灵活起见,前端在连接socket.io时所使用的地址是django后台指定的。这么做有两个好处:

  1. 分散业务
  2. 分散压力
    不过我们的项目目前还体现不出这么做的好处,因为体量比较小,不过体量变大后,一台服务器难以承担压力时,这么做就比较有必要了。我们可以把不同的业务划分在不同集群上,然后按id分配给不同的服务器。

这么做的代码量是会比较大,所以也不必一步做到位,目前对于业务的扩展我们采取的策略还是先扩展模块,并在node.js端做连接类型识别,然后分发给不同的模块。至于我们的服务器,目前还没涉及到集群。
不过这么做麻烦的地方是在部署的时候有些重复的工作,这个在后面的文章再讨论。

其次是用户身份验证。
在连接socket.io时,会由django后台生成identification作为合法用户认证用来连接node.js服务器。这里可以做的工作也比较多。

第一是登录用户和非登录用户的区别。
session管理是由django完成的,因此对于node.js来说一切的连接请求都不可信。所以这里安全的做法是将明文identification(比如用户名或者id)加盐后加密,node.js端再解密进行对比。不过并不确定解密是否会给node.js造成计算压力,node.js对于CPU密集型任务并不是很擅长,如果真的瓶颈在此那可以考虑用cluster.fork()专门开进程处理解密任务。

第二是同一登录用户多终端连接的问题。
非登录用户本身不可识别就不必考虑了,登录用户如果多开终端,那如何针对性推送是需要考虑的事情。如果按socket为单位处理用户,那当同一个用户的socketA触发了一个事件并有一些针对性的回调时,还需要同时调用socketB和socketC的回调。这在设计时非常容易被忽略,并造成一定的困扰。
在这种情况下一个可行的办法是同时只允许一个终端连接,如果有新终端连接那就把旧终端断开。不过这也得按照需求场景来制定策略,并不是所有的业务都可以这么做的。
当然更好的办法是按用户id为单位处理,同一个id下可以有多个socket,任何终端上的操作只要是同一id就视作同一来源。这样在逻辑上更加清晰,只是需要额外的数据结构来保存用户信息,并且要注意及时回收资源以免浪费内存。

第三是用户授权模拟自身操作时的验证。
这相当于用户扔了一个异步任务给后台,后台在某个时间或者某个事件之后会触发该任务,视同用户本身进行了某些操作。原本的方案是复用django api,但是这带来的问题是我们需要记录用户的sessionid和csrftoken,才能够在之后的时刻模拟这个用户。但是一旦用户在随后的时间内登出了或者在终端上切换了账户,sessionid就会失效,整个授权行为就变得无意义了。现在想想最初的方案真的是非常愚蠢,sessionid在任何时候都不该被记录下来并当作凭证,因为它可能在任何时候失效。
后来的做法是将相关的函数提取出纯业务逻辑,以用户id为凭证,再用RPC复用。由于RPC是部署在内网的,就不必担心安全问题,只用确保在授权时是用户本人即可。

再次是API设计
这里的API是指暴露给用户的操作。前文我们也说过在我们设计初衷里node.js服务器不承担或只承担小部分的业务逻辑,所以用户的操作都是不经过node.js而是直接提交给django端,再由django向node.js推送消息并最终将结果推送给用户。并且上文也说到了,对于node.js来说所有连接都是不可信的,这么做就更有必要了。
在我们的需求里,用户提交操作后要求其他用户立刻看到,但是部分操作又包含了大量的信息验证,不仅仅只是登录验证。这些验证与数据库里的数据交互非常多,所以这也是不能放在node.js端的原因之一。
因此我们客户端的代码里除了向node.js提交身份信息以外,其余任务只有接受推送而已。但是这不代表node.js不能够提供api或者socket.io不能够提供event,一些弱安全性的,比如聊天就不需要走django,这反而会给django带来不必要的压力。
也就是说,让node.js服务器变得单纯一些,甚至可以把node.js当作一个可替换组件,不要让它涉及核心业务。

最后是可持续化设计
有没有考虑过一旦node.js崩溃了,正在参与活动的用户怎么办?不像django,node.js可能保存了一定量的用户状态(这种情况可能是业务所需),一旦系统崩溃了这些状态都丢了。这里的解决办法很多,网络上类似的话题也不少,放开了说是一个很大的范畴,就说说我们是怎么办的吧。
我们的解决方案是,不在node.js端储存任何用户状态,一切需要储存的内容都经由django存入数据库。想要允许node.js使用数据库是可以的,但是要保持和django ORM一致却有一定的工作量,而且也不建议这么做。
在我们的业务里用户的状态是由用户操作和一些定时任务修改的,加上我们的api是走的django,所以在用户状态这一环节上node.js完全没有参与。还是那句话,node.js服务器不承担或只承担小部分业务逻辑,多数情况下只把它当作一个单纯的推送服务器。

总的来说开发过程里值得记录的就是这么些问题,然后就是对node.js的测试和优化了,这个我们后文再聊。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容