发布时间

服装零售决策管理系统技术方案

作者
  • avatar
    作者名字
    Kavin Wang
    Twitter

概述与分析

本系统在进行设计时,必须考虑到品牌公司的数据管理以及数据安全问题,在当前系统资源有限的情况下,还必须考虑服务的效率,以在有限资源下达到最好的服务。

考虑到我们面对的是无数的对数据安全要求比较苛刻的品牌公司,因此可以得出,我们的系统是非常明显的多租户SAAS系统。

基于以往的经验,结合对零售行业的深度学习分析与了解,实施一个服装零售系统的决策系统将是一个复杂沉重的工作,是一个挑战性异常高昂的决定。我们必须慎重选择客户当前最关心最头疼的部分,还要考虑客户对未来数据管理的需要。

因此我们的系统既要保障客户数据的安全,还要考虑系统的可靠扩展性,连续服务的技术一致性等也都变得至关重要。

技术方案与选型

数据库

关于服饰行业的模型复杂性,我们考虑在系统业务处理模型上,尽量使用mongodb数据库来实现,通用数据考虑使用postgre来完成。希望既能保障业务建模的便利完整性,也能在系统管理上尽量简单。

软件技术

涉及到用户信息安全管理方面,尽量使用商业公司提供的安全服务。

关于业务的实现,考虑到初创企业成本限制,需尽量使用已经验证成熟灵活的开源系统和框架,必要之处,再考虑商业公司提供的技术和设施服务。

租户系统

由于我们系统的多租户特性,经过思考和分析,当前可以选择的技术方案有以下几种:

大数据模式

我们把所有的数据保存在一个数据库中,数据之间不做严格的隔离,但会对不同租户赋予不同的安全的uid,并在所有租户相关的数据上赋予这个uid进行区分。

这种模式对系统要求相对比较大,系统租户量不多时,系统实现和执行效果比较满意,担当租户量增大时,考虑到数据量的极度增加,对于数据库系统的挑战将会非常大,并且可能需要投入非常大的硬件设施投入。

轻量租户模式

我们将为每一个租户建立一个独立的数据库,系统使用统一的管理系统来管理租户数据,所有租户共享同一个数据库连接池,系统根据租户的不同来调整连接池中的租用的连接,使之根据不同租户去访问租户的私有数据库。

考虑到共享连接池,因此这种系统租户量可能不会很大,并且对租户的访问要求也比较苛刻,比如要求租户访问时的压力要小于每秒一个请求,任务处理速度也要求应在10ms内完成。原因是某一个租户的慢速访问,会直接影响其它的租户的访问效率。

const express = require('express');
const mongoose = require('mongoose');

mongoose.connect('mongodb://127.0.0.1:27017/main');
mongoose.set('debug', true);

mongoose.model('User', mongoose.Schema({ name: String }));

const app = express();

app.get('/users/:tenantId', function(req, res) {
  const db = mongoose.connection.useDb(`tenant_${req.params.tenantId}`, {
    // `useCache` tells Mongoose to cache connections by database name, so
    // `mongoose.connection.useDb('foo', { useCache: true })` returns the
    // same reference each time.
    useCache: true
  });
  // Need to register models every time a new connection is created
  if (!db.models['User']) {
    db.model('User', mongoose.Schema({ name: String }));
  }
  console.log('Find users from', db.name);
  db.model('User').find().
    then(users => res.json({ users })).
    catch(err => res.status(500).json({ message: err.message }));
});

app.listen(3000);

重度租户模式

这种模式,应该比上一个模式更加灵活,服务质量应该更高,比如可以服务10K个以上的租户,可以要求请求的速度大于每秒一个请求。

因此我们需要要求每一个不同的租户,都需要有自己独立的连接池。单个租户的对系统性能要求比较严格的业务请求,能够较小的影响到其它的租户的使用。

很明显,这种系统实现起来更加困难,也更加复杂。特别是mongodb对最大连接能力的限制,即使使用mongd atlas,也有会对每个连接池中活跃连接数进行限制

const express = require('express');
const mongoose = require('mongoose');

const tenantIdToConnection = {};

const app = express();

app.get('/users/:tenantId', function(req, res) {
  let initialConnection = Promise.resolve();
  const { tenantId } = req.params;
  if (!tenantIdToConnection[tenantId]) {
    tenantIdToConnection[tenantId] = mongoose.createConnection(`mongodb://127.0.0.1:27017/tenant_${tenantId}`);
    tenantIdToConnection[tenantId].model('User', mongoose.Schema({ name: String }));
    initialConnection = tenantIdToConnection[tenantId].asPromise();
  }
  const db = tenantIdToConnection[tenantId];
  initialConnection.
    then(() => db.model('User').find()).
    then(users => res.json({ users })).
    catch(err => res.status(500).json({ message: err.message }));
});

app.listen(3000);