数据库技术-liquibase使用和原理

LiquiBase是一个用于数据库重构和迁移的开源工具,通过日志文件的形式记录数据库的变更,然后执行日志文件中的修改,将数据库更新或回滚到一致的状态。

LiquiBase的主要特点有:

  • 支持几乎所有主流的数据库,如MySQL, PostgreSQL, Oracle, Sql Server, DB2等;
  • 支持多开发者的协作维护;
查看更多

netty源码分析之executionMask

老版本的netty,AbstractChannelHandlerContext 有两个bool属性InBound 和outBound,InBound=true表示该节点是inBound,outBound=true表示该节点是outBound,当然也可能同时为true。在我阅读的源代码版本(4.1.50)中已经删除了这两个属性,取而代之的是属性executionMask,通过使用该属性可以在事件传播时,快速的判断出该节点中的Handler在inBound方向和outBound方向有没有重载某事件处理逻辑。

之前分析过Pipeline的源码,在向Pipeline添加节点的时候,会创建DefaultChannelHandlerContext对象,调用其父类构造函数时

1
2
3
4
5
6
7
8
9
10
11
import static io.netty.channel.ChannelHandlerMask.mask;

AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor,
String name, Class<? extends ChannelHandler> handlerClass) {
this.name = ObjectUtil.checkNotNull(name, "name");
this.pipeline = pipeline;
this.executor = executor; // null
this.executionMask = mask(handlerClass); // 生成一个掩码 可以快读判断这个Handler重载了哪些方法
// Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
ordered = executor == null || executor instanceof OrderedEventExecutor; // ture
}

会用mask方法给其成员executionMask赋值,mask是ChannelHandlerMask类的静态方法,本文主要分析这类的源码,该类的源码并不复杂,之所以要拿出来分析,完全是因为这种设计思想还是值得借鉴的。

首先看这个类定义了许多的int型静态变量,作为标记,每一个事件处理方法对应了17位中的一位

查看更多

Nacos(四)数据一致性

两种一致性策略如何在nacos中共存

或许会有疑问,为什么早先的cp模式的Zookeeper或者AP模式的Eureka,都只有支持CAP理论下大家常用的AP实现或者CP实现,而nacos却能够两个都实现呢?

其实CAP理论,仅仅是针对分布式下数据的一致性而言,如果你对于数据的一致性要求不高,可忍受最终一致性,那么AP模式的Eureka就可以满足你了,如果说你对数据的一致性要求很高,那么就使用CP模式的Zookeeper,而追其根本,并不是说EurekaAP的,或者说ZookeeperCP的,而是他们存储的数据的一致性,满足AP或者CP,因此也就不难实现在一个组件中实现AP模式与CP模式共存

DelegateConsistencyServiceImpl是一个一致性策略选择的类,根据不同的策略触发条件(在nacos中,CPAP切换的条件是注册的服务实例是否是临时实例),选择PersistentConsistencyService策略或者EphemeralConsistencyService策略,而EphemeralConsistencyService对应的是DistroConsistencyServiceImpl,采用的协议是阿里自研的Distro,我个人觉得就像gossip协议;PersistentConsistencyService对应的是RaftConsistencyServiceImpl,其底层采用的是Raft协议;这两种一致性策略下的数据存储互不影响,所以nacos实现了AP模式与CP模式在一个组件中同时存在

分析流程之前,插上网图一张,此图逻辑清晰,有助于理解

查看更多

java-Reactor编程入门

https://developer.ibm.com/zh/articles/j-cn-with-reactor-response-encode/

1. 理论基础

反应式编程来源于数据流和变化的传播,意味着由底层的执行模型负责通过数据流来自动传播变化。比如求值一个简单的表达式 c=a+b,当 a 或者 b 的值发生变化时,传统的编程范式需要对 a+b 进行重新计算来得到 c 的值。如果使用反应式编程,当 a 或者 b 的值发生变化时,c 的值会自动更新。反应式编程最早由 .NET 平台上的 Reactive Extensions (Rx) 库来实现。后来迁移到 Java 平台之后就产生了著名的 RxJava 库,并产生了很多其他编程语言上的对应实现。在这些实现的基础上产生了后来的反应式流(Reactive Streams)规范。该规范定义了反应式流的相关接口,并将集成到 Java 9 中。

在传统的编程范式中,我们一般通过迭代器(Iterator)模式来遍历一个序列。这种遍历方式是由调用者来控制节奏的,采用的是拉的方式。每次由调用者通过 next()方法来获取序列中的下一个值。使用反应式流时采用的则是推的方式,即常见的发布者-订阅者模式。当发布者有新的数据产生时,这些数据会被推送到订阅者来进行处理。在反应式流上可以添加各种不同的操作来对数据进行处理,形成数据处理链。这个以声明式的方式添加的处理链只在订阅者进行订阅操作时才会真正执行。

反应式流中第一个重要概念是负压(backpressure)。在基本的消息推送模式中,当消息发布者产生数据的速度过快时,会使得消息订阅者的处理速度无法跟上产生的速度,从而给订阅者造成很大的压力。当压力过大时,有可能造成订阅者本身的奔溃,所产生的级联效应甚至可能造成整个系统的瘫痪。负压的作用在于提供一种从订阅者到生产者的反馈渠道。订阅者可以通过 request()方法来声明其一次所能处理的消息数量,而生产者就只会产生相应数量的消息,直到下一次 request()方法调用。这实际上变成了推拉结合的模式。

前面提到的 RxJava 库是 JVM 上反应式编程的先驱,也是反应式流规范的基础。RxJava 2 在 RxJava 的基础上做了很多的更新。不过 RxJava 库也有其不足的地方。RxJava 产生于反应式流规范之前,虽然可以和反应式流的接口进行转换,但是由于底层实现的原因,使用起来并不是很直观。RxJava 2 在设计和实现时考虑到了与规范的整合,不过为了保持与 RxJava 的兼容性,很多地方在使用时也并不直观。Reactor 则是完全基于反应式流规范设计和实现的库,没有 RxJava 那样的历史包袱,在使用上更加的直观易懂。Reactor 也是 Spring 5 中反应式编程的基础。学习和掌握 Reactor 可以更好地理解 Spring 5 中的相关概念。

查看更多