我们公司的重资产是人员, 我们了解跨境电商物流, 包括跨境电商通关的环节, 关于物流方面的国际法律以及离境品的相关信息, 这些都是我们公司最宝贵的资源.
我们公司底下有一大群长期合作的供应商, 这是我们最大的优势. 我们的难点也是在于这些供应商是不可控的, 因为我们是在使用别人家的服务.
所以除了订单系统还有一个很重要的资产就是我们自营的海外仓储, 这也是我们最核心的价值.
覆盖欧美澳主要市场的服务网络
上图是我们全球布局的物流网络. 这些仓储有大有小, 英国仓库是我们最核心的仓库. 截至 2017 年, 在国内我们一共有八个仓储中心, 重点的是在深圳, 广州和上海.
全球主流电商平台重点推荐物流服务提供商
我们合作的平台推荐我们的物流服务提供商有 Amazon,ebay,wish, 阿里国际, shopee,AliExpress 还有 LAZADA.
出口易新老架构演变过程
我们之前的系统是上图左边的架构, 针对商家第三方的 ERP 和一些商家自己研发的一套系统, 还有一些平台跟我们的系统都是有直接交互. 有的是通过出口易提供了一套 UI 来进行访问, 还有就是大量的线上发货, 我们会采用 API 来进行接入. 我们后台有 admin 管理后台, 还有单独的一块 WMS 系统.
我们认为这个系统有些过于庞大, 想做一些调整. 新的架构大部分还是没有改动, 只是在后端针对 admin 的系统想要往面向服务架构方向落地. 基于业务场景的切分有两块, 一块是基于通用服务, 比如说用户的认证和授权, 还有就是日志.
支付有一些支付网关, 有和 paypal,alipay,payoneer 还有银行的接口.
下面是我们业务最主要模块, 包括产品报价, 客户关系管理系统, 还有订单, 物流网络和运输, 包括 WMS, 支付, 物流轨迹跟踪, 供应商管理系统, 还有结算报表等等诸如此类.
出口易老业务系统特点
单体应用: 前后端系统共用一套 web App Solution.
单一数据库: 采用 MS SQLServer 数据库, 核心业务功能共用一个数据库.
业务功能完整: IT 系统随业务的发展不断扩展新功能. 满足开展跨境电商物流业务最基本的功能性需求.
容易测试和部署: 单独一个 Solution, 系统依赖少, 一旦部署, 全部功能即可测试.
出口易老业务系统不足
不够灵活: 对应用程序做任何细微的修改都需要将整个应用程序重新构建, 重新部署.
妨碍持续交付: 系统规模大, 构建和部署时间也相应地比较长, 不利于频繁部署, 阻碍持续交付.
受技术栈限制: 包括开发语言, 开发工具, 数据库一旦选定, 无法根据实际需要作其他选择.
技术负债: 系统逻辑异常复杂, 随着时间推移, 人员更迭, 技术负债不断累积.
出口易新业务系统特点
面向服务: 根据业务模块切分不同的系统模块, 系统模块采用面向服务架构. 服务与服务通过明确的接口定义进行通讯.
领域驱动设计: 每个业务模块团队负责一个领域或业务功能相关的全部开发. 核心领域根据 DDD 中明确定义的规则实现.
独立部署, 升级, 扩展和替换: 每个服务可以单独部署, 透明升级, 不影响整个系统.
异构 / 采用多种语言: 每个服务开发团队, 可以选择自己熟悉开发语言, 数据库, 开发工具和开发架构.
新架构落地的切入点
身份认证: 每个服务都需要统一的登录认证.
鉴权: 不同的用户使用相同的服务模块都需要鉴权.
由单点登录的页面包括基于 OAuth2 API 这样的方式来接入. 内部采用的是 DDD 这样的一个逻辑架构, 包括应用层, 领域层. 领域层里面又包括了领域模型, 实体子对象, 领域服务, 领域事件和查询的规格.
基于仓储, 要存一个订单, 必须连接实体和子对象一起存储刷新到数据库.
我们做应用的时候更偏向于完成业务, 所以选用了 mangoDB. 我们有一套自己的架构, 在封装的过程中就会把 mangoDB 做一层封装.
上图中面向切面的架构包括了 exertion,loading 和 cache 等切面.
上图是 TMS 系统调拨单聚合根示意图, 它包括了物流轨迹的集合, 预计到货时间等信息, 还有这些调拨单历经的节点信息.
为什么选择 MongoDB?
1, 非事务紧密型. 错误数据容忍性相对比较高.
2, 团队成员有使用 MongoDB 开发经验. 对基于 MongoDB 方面的建模需要考虑的必要冗余有一定的了解.
3,Portal 模块数据库读大于写, 基于 MongoDB 读写方面的高性能, 解决了高并发下系统卡顿问题.
4,TMS 系统模型之间关系复杂, 采用传统关系数据库, 势必增加一堆表. 采用 MongoDB, 可以把复杂的模型, 通过一个 Doucment 存储到一起.
基于 MongoDB 开发需要注意的问题
集合之间不能 Join, 建模方面要特别注意. 建议增加必要的冗余, 减少二次查询.
仅仅支持单个 Document 级别事务. 数据一致性错误时, 要考虑增加必要数据监控和数据修复功能.
聚合查询, 需要通过 MongoDB 聚合管道方式查询, MongoDB C# 驱动提供了良好支持, 但是相对 Linq 查询还是比较繁琐.
基于 MongoDB 的持久化实现
一, 仓储 Repository
仓储限定在对整个聚合根的操作上, 提供聚合根的持久化和重建或查询.
二, 仓储上下文 Repository Context
负责事务处理. 每个聚合根的仓储都会关联到同一个仓库上下文. 但是 MongoDB 不支持事务, 我们提供了虚拟实现. 仓储上下文应用了工作单元模式.
一些关注点
一, 领域模型采用 POCO(POJO)
简单的 CLR 对象(简单的 Java 对象), 不继承任何持久化框架中的基类, 或实现任何持久化框架中的接口. 领域层不引用 MongoDB 类库. MongoDB 仓库层使用 lambda expression 实现类的 Map.
二, ID 生成器
有多种 ID 生成器可供选择. GuidGenerator,OjbectIdGenerator,String OjbectIdGenerator,etc. 我们 ID 一律使用 String 类型. 所以直接使用 MongoDB 的 StringObjectIdGenerator.
三, 多态类的 Map
如果把多态类 (继承) 映射到 MongoDB, 需要指定已知类型.
四, 一些需要了解的约定
NamedIdMemberConvention 可以指定类的哪些属性可以作为 ID.
IgnoreExtraElementsConvention 可以忽略 Document 中不存在于类中的字段, 否则会抛出异常.
EnumRepresentationConvention 可以指定枚举序列化的方式, 我们都指定为 BsonType.String.
MongoDB 聚合框架(C#)
一, 聚合框架
MongoDB2.2 版本引入了此功能, 是数据聚合的一个新框架.
这个框架一是对文档进行 "过滤", 也就是筛选出符合条件的文档; 二是对文档进行 "变换", 也就是改变文档的输出形式. 其他的也包括按照某个指定字段分组和排序等.
它其实是 MapReduce 的替代方案, 但比 MapReduce 简单.
该框架使用声明性管道符号来支持类似 SQL 中的 Group by 操作的功能. 不需要自己编写自定义的 JavaScript.
二, 管道操作符
$project: 数据投影, 主要用于重命名, 增加和删除字段.
$match: 过滤操作, 筛选符合条件文档, 作为下一阶段的输入.
$limit: 限制经过管道的文档数量.
$skip: 从待操作集合开始的位置跳过文档的数目.
$unwind: 将数组元素拆分为独立字段.
$group: 对数据进行分组.
$sort: 对文档按照指定字段排序.
$geoNear: 会返回一些坐标值, 这些值以按照距离指定点距离由近到远进行排序. 这个在地理信息系统中比较常用.
总结
对于大多数的聚合操作, 聚合管道可以提供很好的性能和一致的接口.
使用起来比较简单, 和 MapReduce 一样, 它也可以作用于分片集合.
输出的结果只能保留在一个文档中, 要遵守 BSON Document 大小限制(当前是 16M).
管道对数据的类型和结果的大小会有一些限制, 对于一些简单的固定的.
聚集操作可以使用管道, 但是对于一些复杂的, 大量数据集的聚合任务还是使用 MapReduce.
来源: https://juejin.im/post/5ae4240bf265da0b7527df3e