问题
分布式系统的一致性模型包括:强一致性、弱一致性、最终一致性,以及一些最终一致性的变种,如因果一致性、读自己写一致性等。
有个项目,数据存放在主从同步的mysql数据库中,写操作统一落在主库上。由于主从数据库物理位置相距较远(分别在国内机房和国外机房),同步的网络延迟较大,所以有可能因为网络延迟的原因,在读写分离的情况下,读不到自己刚才所写的数据(读从库)。例如用户在国外机房的应用中写完数据后,在延迟时间窗口内立即读,此时写数据还未同步到从库,读从库失败。也就是通常的读写分离方案在这种场景下解决不了读自己写一致性问题。读自己写一致性中的‘自己’可以是进程或系统、也可以是用户。在我们的项目中,’自己‘指的是系统中的用户,用户在系统中发布消息后,要能在消息列表中看到刚才发布的消息。
方案
在通常的读写分离基础上考虑同步延迟窗口:用户在写操作(insert、update、delete)之后进行读(查询),如果是在写操作的同步延迟窗口之内读,则读取主库,其他情况下读从库。如果一个事务中有写操作,不管是否有读操作,肯定是操作主库。
Java实现
使用spring AbstractRoutingDataSource(用于读写分离),Java 注解(Annotation)和aop和thread local。
Spring提供了AbstractRoutingDataSource抽象类用于多数据源的访问也就是分库,可以继承该类覆盖来实现主从数据库的分库访问。
determineCurrentLookupKey()方法来实现读写分离。
RwResourceDesc注解如下,它用在service façade类(façade设计模式)的方法上,用于描述service方法涉及到哪些表或资源的读写。Controller类会调用service façade类的方法,façade类再调用service层的方法。
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RwResourceDesc {
String[] readResources() default ""; //读哪些表
String[] writeResources() default "";//写哪些表
}
例如OrderFacede.java中的下单方法,读product表,写order表
@RwResourceDesc(readResources = { "product" }, writeResources = { "order"} )
public void placeOrder(…) throws Exception {…}
Spring数据访问的xml配置大致如下:
<!-- 前面介绍的aop advice -->
<bean id="contextAwareAdvice class="com.xxx.aop.advice.RWContextAwareAdvice"></bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="load*" read-only="true" propagation="SUPPORTS"/>
<tx:method name="list*" read-only="true" propagation="SUPPORTS"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceFacadeOperation" expression="execution(* com.xxx.service.facade.*.*(..))"/>
<!—注意order属性的大小,决定advice的调用顺序 -->
<aop:advisor order="1" advice-ref="contextAwareAdvice" pointcut-ref="serviceFacadeOperation"/>
<aop:advisor order="2" advice-ref="txAdvice" pointcut-ref="serviceFacadeOperation"/>
</aop:config>
aop advice类:
public class RWContextAwareAdvice implements MethodInterceptor {
//注入该属性
private ContextAwareManager contextAwareManager;
public void setContextAwareManager(ContextAwareManager contextAwareManager) {
this.contextAwareManager = contextAwareManager;
}
public Object invoke(MethodInvocation invocation) throws Throwable {
ContextAware context = contextAwareManager.getContext();
RwResourceDesc rwResourceDesc = invocation.getMethod().getAnnotation(RwResourceDesc.class);
if(null != rwResourceDesc){
//如果有写,则强制读主库
if(!rwResourceDesc.writeResources()[0].isEmpty()){
//设置操作主库标志
context.forceMaster();
}
else{
//没有写,只有读。判断是读主库还是读从库
if(!rwResourceDesc.readResources()[0].isEmpty()){
//以context id加readResources中的表名作为key,如果redis中存在该key, if(context.matchChangedResourceTypeForRead(
rwResourceDesc.readResources())){
//读操作在‘自己’的写操作时间窗口之内,读主库
context.forceMaster();
}
}
}
}
try{
Object result = invocation.proceed();
return result;
}
finally{
if(null != rwResourceDesc){
//如果有写,则记录'自己'写了哪些资源,将key、value放到redis中,过期时间同value。
if(!rwResourceDesc.writeResources()[0].isEmpty()){
context.recordChangedResourceType(rwResourceDesc.writeResources());
}
}
//复位thread local中的context id和读主库标志。
contextAware.resetContext();
}
}
}
使用RwResourceDesc注解来标示方法中读写的表有哪些,如果是使用myibatis作为dao框架,也可以写个myibatis拦截器捕获sql语句来判断读写的表。
相关推荐
mycat 读写分离 优化
mycat读写分离
• 读写分离,解决“数据库读性能瓶颈”问题 • 水平切分,解决“数据库...• 对于互联网大数据量,高并发量,高可用要求高,一致性要求高,前端面向用户的业务场景,微服务缓存架构,可能比数据库读写分离架构更合适
MySQL分库分表,读写分离与Mycat的使用文章中一致性hash分片sql
使用4台虚拟机,如图-1所示,其中192.168.0.10和192.168.0.20,分别提供读、写服务,均衡流量,通过主从复制保持数据一致性,由MySQL代理192.168.0.100面向客户端收到SQL写请求时交给服务器master处理,收到SQL读...
对spring整合mybatis的SqlSessionTemplate进行修改,对数据库数据库垂直、水平拆分及读写分离进行支持,并构建相应的模型。同时实现一致性哈希的分表策略。
五种事务一致性介绍笔记:两阶段提交、TCC、Event Sourcing、读写分离、Sagas
MySQL通过日志记录来保证数据一致性、支持故障恢复和审计需求,主要包括: 错误日志(Error Log):记录MySQL服务器运行期间的严重错误、警告和其他重要事件。 二进制日志(Binary Log,binlog):记录对数据库...
8-20 实现读写分离 8-21 测试与并发 8-22 事件溯源模式与Axon框架总结 第9章 TCC模式和微服务架构的设计模式 本章介绍TCC模式,也对微服务系统的几种设计模式,以及这些模式下分布式事务的实现模式进行了介绍。 9-1...
这种做法,带来的好处是可以让我们的代码读写分离,更好维护,且没有CQ两端的数据一致性问题,因为是共享一个数据库的。我个人认为,这种架构很实用,既兼顾了数据的强一致性,又能让代码好维护。 2.CQ两端数据库和...
当使用Redis作为存储引擎的时候,并且使用Redis读写分离,从机作为读的情况,从机宕机或者和主机断开连接都需要重新连接主机,重新连接主机都会触发全量的主从复制,这时候主机会生成内存快照,主机依然可以对外提供...
He3Proxy是中移(苏州)软件技术有限公司基于PG协议 专为He3DB 打造的高性能数据库代理项目,采用Go语言开发, He3Proxy为He3DB 提供读写分离、负载均衡、连接池管理、 读一致性等基础能力,让用户像使用单机一样...
He3Proxy是中移(苏州)软件技术有限公司基于PG协议 专为He3DB 打造的高性能数据库代理项目,采用Go语言开发, He3Proxy为He3DB 提供读写分离、负载均衡、连接池管理、 读一致性等基础能力,让用户像使用单机一样...
多进程无锁提升运行效率支持透明的后端连接池支持SQL读写分离增强SQL路由解析与注入支持prepare语句支持结果集压缩支持安全性管理支持状态监控支持tcp stream流式支持域名连接后端SSL/TLS支持(客户端)MGR支持读强...
解决思路:复制+冗余副作用:复制+冗余一定会...不做读写分离,在“主”挂掉的情况下,“从”(其实是另外一个主),顶上,如下图优点:读写都到主,解决了一致性问题;“双主”当“主从”用,解决了可用性问题带来的问
这篇文章通过安全性,用法,并发处理等方便详细分析了Mysql事务和数据的一致性处理问题,以下就是全部内容: 在工作中,我们经常会遇到这样的问题,需要更新库存,当我们查询到可用的库存准备修改时,这时,其他的...
Canal 是一款优秀的数据库同步工具,可以帮助用户实现数据库的实时同步。当一个数据库中的数据发生更改时,Canal 可以实时捕获...它适用于需要实时同步数据的各种场景,如数据仓库、日志分析、备份恢复和读写分离等。
9、分布式事务读一致性的功能效果及测试验证方法 10、分布式事务写一致性的功能效果及测试验证方法 11、分布式锁检测死锁的功能效果及测试验证方法 12、分布式锁解除死锁的功能效果及测试验证方法 13、国内...
接着继续讲,接下来主要介绍交易总体设计的技术要点设计,对于电商中台来说,交易系统是核心中的核心,一开始就需要...交易业务要求订单,库存,优惠券,红包,支付等数据要强一致,如何保证这些数据之间的一致性是必须