两种实现方式mycat多租户,枚举分片,注解拦截
第一种:
优点:支持进一步分片
缺点:schema配置繁琐
注解式 /*!mycat:schema=[schemaName] */ 注意:这在navicat 里面是会报错的,请用命令行登陆mycat 来测试
mysql> explain /*!mycat:schema=USER1 */ select * from order;
可以在每个sql语句前面添加此注解,Mybatis 可以重写 MappedStatement 的 getBoundSql 来添加。
不管使用什么方式,感觉这都很搓。还要手动在Mycat schema.xml 中添加很冗长的 配置。
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="USER1" checkSQLschema="false" sqlMaxLimit="10000">
.....
</schema> <schema name="USER2" checkSQLschema="false" sqlMaxLimit="10000">
......
</schema>
以下省略无数个 schema
第二种:使用枚举分片实现多租户
优点:schema.xml 配置相对简洁
缺点:不可进一步分片
explain /*!mycat:schema=[schema] */ /*!mycat:dataNode=dn1 */ select * from order;
创建分片枚举规则文件.
cat sharding-by-enum.txt
= = =
修改rule.xml的 function
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">sharding-by-enum.txt</property>
<property name="type">0</property>
<!-- <property name="mapFile">partition-hash-int.txt</property> -->
</function>
测试枚举分片命中率,这就可以使用枚举分片,达到多租户效果
枚举分片,解决查询分片命中问题
mysql> explain select * from order a left join detail b on a.id = b.orderId where a.sharding_id = 0;
+-----------+----------------------------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+----------------------------------------------------------------------------------------------------------------------+
| dn1 | select * from order a left join detail b on a.id = b.orderId where a.sharding_id = 0 |
+-----------+----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
两个表,都有枚举分片字段
mysql> explain select * from order a left detail b on a.id = b.orderId where a.sharding_id and b.sharding_id = 0;
+-----------+----------------------------------------------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------+
| dn1 | select * from order a left detail b on a.id = b.orderId where a.sharding_id and b.sharding_id = 0 |
+-----------+----------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec) mysql> 没有命中条件,造成全盘扫描 mysql> explain select * from order a left join detail b on a.id = b.orderId;
+-----------+----------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+----------------------------------------------------------------------------------------------+
| dn1 | select * from rder a left join detail b on a.id = b.orderId |
| dn2 | select * from rder a left join detail b on a.id = b.orderId |
| dn3 | select * from rder a left join detail b on a.id = b.orderId |
+-----------+----------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec) UPDATE Database changed
mysql> explain update detail set itemNum='' where id = 8079
-> ;
+-----------+--------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+--------------------------------------------------------------+
| dn1 | update detail set itemNum='' where id = 8079 |
| dn2 | update detail set itemNum='' where id = 8079 |
| dn3 | update detail set itemNum='' where id = 8079 |
+-----------+--------------------------------------------------------------+
3 rows in set (0.02 sec) 分片字段不能被更新
mysql> explain update detail set itemNum='',shardingId=0 where id = 8079;
ERROR 1064 (HY000): Sharding column can't be updated DETAIL->SHARDINGID 加上分片字段 mysql> explain update order set itemNum='100' where id = 8079 and shardingId = 0;
+-----------+---------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------------------------------------+
| dn1 | update order set itemNum='100' where id = 8079 and shardingId = 0 |
+-----------+---------------------------------------------------------------------------------+
1 row in set (0.00 sec) 删除,同样全盘扫描
mysql> explain delete detail where id = 8079;
+-----------+--------------------------------------------+
| DATA_NODE | SQL |
+-----------+--------------------------------------------+
| dn1 | delete detail where id = 8079 |
| dn2 | delete detail where id = 8079 |
| dn3 | delete detail where id = 8079 |
+-----------+--------------------------------------------+
3 rows in set (0.00 sec) 强制命中条件
mysql> explain delete detail where id = 8079 and shardingId = 0;
+-----------+---------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+---------------------------------------------------------------+
| dn1 | delete detail where id = 8079 and shardingId = 0 |
+-----------+---------------------------------------------------------------+
1 row in set (0.00 sec) 全局表与分配表 inner join 以及 left jion right jion 都可以命中枚举
mysql> explain select * from user a inner join order b where a.id=b.userId and b.shardingId = 0;
+-----------+----------------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+----------------------------------------------------------------------------------------------------------+
| dn1 | select * from user a inner join order b where a.id=b.userId and b.shardingId = 0|
+-----------+----------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec) mysql> explain select * from user a right join order b on a.id = b.userId where b.shardingId = 0;
+-----------+------------------------------------------------------------------------------------------------------------+
| DATA_NODE | SQL |
+-----------+------------------------------------------------------------------------------------------------------------+
| dn1 |select * from user a right join order b on a.id = b.userId where b.shardingId = 0|
+-----------+------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
无论是用哪一种方式,而枚举方式的schema还简单一点
只需要添加dataNode,即可,没有第一种的方式那么膨胀XML
<dataNode name="dn1" dataHost="localhost1" database="db1" />
关于这个分片标识可以记录再session里面(配合redis session ,不再考虑session 导致的内存溢出问题,万一溢出,那非常值得开心,用户量已经那么高了)
/**
* Created by laizhenwei
*/
@Component("sessionAttributes")
@Scope(scopeName = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionAttributes implements Serializable { private static final long serialVersionUID = -8521804511291179982L; //用户分片标识
private Integer shardId; /**
* 获取当前用户的分片标识
*/
public Integer getCurrentShardId() {
Optional<Integer> shardIdOptional = Optional.ofNullable(shardId);
return shardIdOptional.orElseThrow(() -> new RuntimeException("无法获取当分片标识!"));
}
以上方式不支持多线程.请不要让 SessionAttributes 离开Controller 作用域.如果整个程序都不涉及多线程,那么随意在那一层注入
支持多线程方式,借助 InheritableThreadLocal然后写一个过滤器
/**
* Created by laizhenwei
*/
public class ShardContextFilter implements Filter { @Autowired
private SessionAttributes sessionAttributes; @Override
public void destroy() {
// Do nothing
} @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ContextHolder.create(createContext());
chain.doFilter(request, response);
} @Override
public void init(FilterConfig config) throws ServletException {
// Do nothing
} private Context createContext() {
//....
return context;
} }
当然可以使用注解来过滤需要分片命中的请求的规则
@WebFilter(filterName="contextFilter",urlPatterns = {"/addOrder/*","/whatever/*"})
我喜欢在Security需要验证的资源添加到过滤器链,这样我不需要考虑资源规则问题
http.addFilterAfter(contextFilter(), FilterSecurityInterceptor.class);
最后总结一下:
如果单个用户的数据还需要进一步分片,那么只能使用schema的注解拦截实现,
如果单个用户数据,不需要再进一步分片,那么使用枚举分片会简单一些
但是,无论使用哪种方式,都难免需要人工处理schema.xml,除非开始就预建了很多schema或者dataNode,否则再添加的时候,mycat不能像nginx一样reload配置文件,必须停机重启读取配置文件
mongodb也有类似的多租户分片规则[tag]分片,但是这样无法处理分片数据不均衡,所以还是不建议使用tag分片.
定制业务适合的片键,让mongodb自动分片,能很大程度减少维护成本.
两种实现方式mycat多租户,枚举分片,注解拦截的更多相关文章
- Web APi之认证(Authentication)两种实现方式【二】(十三)
前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ...
- Android中BroadcastReceiver的两种注册方式(静态和动态)详解
今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...
- Android中Fragment与Activity之间的交互(两种实现方式)
(未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...
- JavaScript 函数的两种声明方式
1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...
- Redis两种持久化方式(RDB&AOF)
爬虫和转载请注明原文地址;博客园蜗牛:http://www.cnblogs.com/tdws/p/5754706.html Redis所需内存 超过可用内存怎么办 Redis修改数据多线程并发—Red ...
- struts2+spring的两种整合方式
也许有些人会因为学习了struts1,会以为struts2.struts1与spring的整合也是一样的,其实这两者相差甚远.下面就来讲解一下struts2与spring的整合两种方案.(部分转载,里 ...
- easyui datagride 两种查询方式
easyui datagride 两种查询方式function doReseach() { //$('#tt').datagrid('load', { // FixedCompany: $('.c_s ...
- 【Visual Lisp】两种出错处理方式
两种出错处理方式:一种是对出错函数进行重定义,一种是对错误进行捕捉处理. ;;============================================================= ...
- 两种include方式及filter中的dispatcher解析
两种include方式 我自己写了一个original.jsp,另外有一个includedPage.jsp,我想在original.jsp中把includedPage.jsp引进来有两种方式: 1.& ...
随机推荐
- eclipse-java开发实用快捷键
Expand All:ctrl+小键盘* Collapse All:ctrl+shift+小键盘/
- java里程碑之泛型--擦除和转换
在严格的泛型代码里,带泛型声明的类总应该带着泛型参数.但是为了和古老的java代码保持一致,也就是说为了向下兼容,也允许在使用带泛型声明的类时不指定实际的类型参数.如果没有为这个泛型类指定实际的参数类 ...
- python 控制台颜色
python_控制台输出带颜色的文字方法 控制台输出带颜色的文字方法: 在python开发的过程中,经常会遇到需要打印各种信息.海量的信息堆砌在控制台中,就会导致信息都混在一起,降低了重要信息的可 ...
- awk使用正则精确匹配
[root@localhost home]# cat file 5001][YRSD5-1][YRSD5-1-2][0203008400028411] 010102 5001][YRSD7-1][YR ...
- mybatis-spring最新版下载地址
mybatis-spring最新版下载地址: http://mvnrepository.com/artifact/org.mybatis/mybatis-spring/1.2.3 mybatis-sp ...
- Div+Css画太极图源代码
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>D ...
- 系统uid在1-499的原因
1.因为是保留给系统使用的UID,为了与用户设置的账户区分,防止冲突. 2.并没有其他特别的意义, 3.也叫作虚拟用户,除了0之外,所有的UID在使用上并没有任何区别. 4.linux中文件和程序都要 ...
- nodejs cluster模块初探
大家都知道nodejs是一个单进程单线程的服务器引擎,不管有多么的强大硬件,只能利用到单个CPU进行计算.所以,为了使用多核cpu来提高性能 就有了cluster,让node可以利用多核CPU实现并行 ...
- 安装supervisor
机器版本 centos 6.5 python 版本 2.6.6 在终端输入 easy_install supervisor 并回车,linux会自动联网并下载supervisor源码解压并安装 安装成 ...
- 缓存之ehcache
1.EhCache缓存框架简介 EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认的CacheProvider. 我们使用EhCache缓存框架主要是为 ...