Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

hubian/mango-test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

6 Commits

Repository files navigation

mango-test

基于mango写的测试demo

Mango地址:http://mango.jfaster.org/

分库分表注意事项:

1.首先确定数量级别

比如一个B2C电商平台,主要有三个级别的数据

  1. 店铺数据,对应主键merchantNo
  2. 订单数据,对应主键orderNO

通过对数据进行预测:

  1. 店铺规模在1万家以内
  2. 一个店铺的订单总数据在千万条

基于上面的分析,我们认为系统未来要承受非常大的数据,以及并发需求。

2. 项目初期就确定好分库分表策略

我们面临一个问题,如果按照最大评估的量级实施分库分表策略,成本有点高

比如项目初期,一次性上8库,服务器成本高,开发维护测试成本也非常高。

但是如果你一开始不做好策略,以后就很难分了

比如所有的主键都用自增数据,效率杠杠的,但是以后真想分库分表就傻眼了。

因此建议是先设定分库分表策略,但是可以随着业务增长逐渐扩容

如何做?

1. 订单号生成

 public static String makeOrderNumber(String merchantNo) {
 String orderNo=
 "P" //系统号
 +"1"//版本号
 +ShardUtil.getShardKeyByID(merchantNo,8,10,2,2)//分库分表Shard值
 +sdf.format(new Date())//时间戳
 + RandomCodeUtil.getRandomNum(MangoContant.ORDER_NO_RANDOWM_LENGTH) ;
 //随机数,可以用数据库或者其他方式生成
 return orderNo;
 }

我们以订单数据为例,订单号不再使用数字自增ID,而是生成一个字符串,其中包含了很多信息,其中

ShardUtil.getShardKeyByID()

以上个量级的数据字段『店铺数据』merchantNo为输入生成的

getShardKeyByID时要固定未来最大的分库分表的规模

代码中我们设定了未来8库10表的规模

切记,这个是不能改动的,想想为啥呢?

2.分库分表的路由

由步骤1的方法我们生成了一个订单号 P10604201712231334054319

对应的shardId是0604. 这个对于所有merchantNo都是一致的

这样的好处是确保一个商家的订单都在同个库,同个表中。

下面是通过这个shardId,我们要落实到具体的数据库和表中

public class MangoTestShardingStrategy implements ShardingStrategy<String, String> {
 private static final org.slf4j.Logger logger = LoggerFactory.getLogger(MangoTestShardingStrategy.class);
 @Override
 public String getDataSourceFactoryName(String shardID) {
 //String dbname="dsf0";//返回固定库
 String dbname="dsf"+String.valueOf(Integer.valueOf(shardID.substring(0,2))%2);//2个库
 logger.info("-----------db:"+dbname);
 return dbname;
 }
 @Override
 public String getTargetTable(String table, String shardID) {
 //String tablename=table+"_0";//放到一个表里
 String tablename=table+"_"+String.valueOf(Integer.valueOf(shardID.substring(2,4))%10);//10个表
 logger.info("-----------table:"+tablename);
 return tablename;
 }
}

上面的代码帮我们实现了这一功能。

比如项目初期,我们只有一个库,完全可以这样

public String getDataSourceFactoryName(String shardID) {
 String dbname="dsf0";
 return dbname;
 }

//等我们有了8个库,可以这样

public String getDataSourceFactoryName(String shardID) {
 String dbname="dsf"+String.valueOf(Integer.valueOf(shardID.substring(0,2))%8);//8个库
 return dbname;
 }

3.如何扩容

我们以库扩容为例(不考虑原有从库)

我们当前只有1库10个表,要扩展成2个库10个表

  1. 当前的A库增加一个从库B库(DBA操作)
  2. 同步成功后,A B 改为双写(DBA操作)
  3. 业务双写

在没有新业务数据写入前 A B库的数据是完全一致的

这样的好处是由dba负责数据的迁移,业务不需要做逻辑导数据

坏处当然也是有的,就是数据冗余。

4.其他问题

我们目前的策略都是确保一个商户/店铺的订单数据都在一个表里。

这样在商户层面上可以正常各种查询。

但是如果我们按照系统层面上查询,比如查询系统里昨天所有的数据,就要跨库和跨表了。

这有很多实现方法,比如mysql的sharding。

或者干脆做一个大表或者nosql的去存储一个快照。

还有一个问题,如果一个商家的订单数上亿了,那我们就不能用一张表存了,这就涉及到我们最初考虑的问题:

从一开始就要确定我们系统的最大容量。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors

Languages

AltStyle によって変換されたページ (->オリジナル) /