暂时未有相关云产品技术能力~
java工程师
LiteFlow学习三之业务编排处理之外
liteflow学习二
liteflow学习一
rayin使用与学习
pipeline设计模式使用
如何设计一个灵活的审批流程
Seata中的TCC模式学习一
Austin消息中心
Cat学习
ageiport使用
eventMesh源码学习
rocketmq获取默认的MQAdminExt时候,需要进行对象的获取,主要在rocketmq可视化中,方便使用,池化作为一个循环利用的过程,其类似于我们常用的数据库连接池一样,节省启动的成本。同时MQAdminExt是作为二次开发的一个主要使用的类。
RocketMQ整合Spring中推拉模式的相关配置介绍和遇到推拉配置出现的问题的解决
从innodb存储引擎的逻辑存储来看,所有数据都被逻辑地存放在一个空间中,称之为表空间tablespace,表空间又由段segment、区extent、页page组成。
CacheCloud中Task任务执行过程实质是先将task进行堆积到taskQueue中,然后进行统一多线程进行处理。
CacheCloud作为一款可视化方便管理redis的开源软件,可以方便redis集群的管理、开发、监控、运维管理,下面就CacheCloud的代码进行一些整理和学习
Mysql文件包括:参数文件、日志文件、socket文件、pid文件、mysql表结构文件、存储引擎文件、参数文件、日志文件,通过了解mysql的文件相关组成,我们可以知道mysql的组成。
InnoDB存储引擎最早由Innobase Oy公司开发,被包括在mysql数据库所有的二进制发行版本中,从mysql5.5版本开始默认的表存储引擎。其中Heikki Tuuri是InnoDB存储引擎的创始人。 InnoDB架构体系包含后台线程、内存、checkpoint技术,其中后台线程包含主线程、io处理线程、回收分配undo线程、页清理线程;内存包括缓冲池、重做日志缓冲、额外缓冲池;checkpoint技术包含 Sharp Checkpoint、FuzzyCheckpoint,数据库运行时,通常会和FuzzyCheckpoint打交道,通常会根据检查点age来处理
整理的原因是在Sentinel源码中,我们可以看到很多关于CompletableFuture的thenCompose的源码。同时在业务系统里面也看到别人写过类似的代码。因此整理了一下关于CompletableFuture使用的相关类型和特性,在处理复杂耗时业务时可以选择组合使用。
如果我们不对Sentinel的异常提示做自定义,那么此时的提示是非常不详细的。如果做了自定义,就可以看到下面自定义的提示。sentinel提供了@SentinelResource注解帮助我们来实现自定义的熔断限流后的自定义方法处理,可以根据sentinel的aop可以看到处理的example,从而更为清晰的认识sentinel强大的功能。
们可以它的一系列动作操作,会首先将相关配置MessageConverterConfiguration、ListenerContainerConfiguration、ExtProducerResetConfiguration、ExtConsumerResetConfiguration、RocketMQTransactionConfiguration、RocketMQListenerConfiguration进行导入。在自动注入前处理事务配置RocketMQTransactionConfiguration,在自动注入后处理消息转换器配置MessageConverterConfiguration。
通常spi可以配合责任链模式、策略模式使用。此时spi,类似于一个上下文的过程,拿到所有的实现class。 与之类似的还有:SpringUtil.getBeans或者ApplicationContext.getBeansOfType。在一些固定的场景下,处理业务的流程过程通常比较明确,第一步做什么,第二步做什么,第三步做什么的时候,这个时候就可以使用责任链模式在处理。也即存在固定的模式的时候,就可以使用。同时在Netty、Sentinel中有重要使用场景,其过程是一个pipeline流水线的过程。
### 一、如何实现一个简单的认证中心? 我们知道单点登录系统:出名的有[apereo](https://github.com/apereo)的cas和OAuth2、JWT等。通常认证有两个方案: 一个方案是基于token,另一个方案是基于cookie的。基于xxl-sso,我们可以学习到实现的基本是基于过滤器的增强,从而实现重定向。我之前的公司使用的是基于[apereo](https://github.com/apereo)的cas进行的二次开发配合统一授权系统使用。cas的单点登录的登录涉及到三个概念:
### 一、实现一个轻量级简单的配置中心,同时不考虑使用zk? 1.由于我们使用的配置中心需要兼容多套环境,因此需要多环境 2.需要有权限控制 3.需要对配置的信息,能够实时响应 4.如果配置信息存储在数据库,为了减轻数据库的压力,可以进行持久化到磁盘文件中 当时这里会有一个问题需要考虑,如果持久化到磁盘,需要考虑如果配置发生了改变,需要能够实时同步到磁盘文件中,因此此时需要考虑一个线程进行实时同步。 5.对应配置信息发生增、删、改,能够实时更新和修改
1)BinLog是Mysql本身就有的,不管使用哪种引擎,都会存在BinLog,而Redo Log是InnoDB引擎特有的。 2)BinLog是一种逻辑日志,记录的是对数据库的所有修改操作,而RedoLog是一种物理日志,记录的是每个数据页的修改。 3)BinLog具有幂等性,而Redo Log不具有幂等性。 4)BinLog开启事务时,会将每次提交的事务一次性写入内存缓冲区,如果未开启事务,则每次成功执行插入、更新和删除语句时,就会将对应的事务信息写入内存缓冲区修改数据,而Redo Log是在数据准备之前将数据写入缓冲区的Redo Log中,然后在缓冲区中修改数据。而且在提交事务时,先将Re
前面我们已经了解了在做好基础数据的准备工作后,启动测试的时候,会做一个注册消费组的工作,完成后,我们就可以执行生产者发消息操作了。发消息的操作是:发送消息完成后,由于其采用的拉模式,我们可以看到消息在经过发送,存储到数据库之后,会做一个通知拉取数据操作,然后执行拉取。拉取完成后,进行响应。此时会进行消费操作,而这个过程的处理关键是handleData操作,从代码中,我们可以看到其是执行的线程操作是一个batchExcute批量执行操作,可以看到其里面有一个重要方法:threadExcute方法,从而进一步看到我们想看到的方法doMessageReceived
首先启动的过程中,会去获取消费组中的配置信息,拿到消费组中的配置信息后,执行注册消费组操作,而执行注册消费组操作中,会首先注册消费者,然后执行消费组操作,然后执行启动消费者轮询服务,执行mq检查服务启动,mq提交服务启动。完成后,执行监控服务配置操作。 这里面最为重要的是启动长轮询服务操作。因为长轮询服务涉及到执行重平衡操作和执行更新元数据操作。更新元数据操作涉及到更新队列元数据操作,此时不可避免的涉及到对偏移量的更新操作。
这个过程首先是创建主题,有了主题,创建消费组,然后基于消费组这个大前提,执行订阅操作,订阅需要进行消费的主题信息,然后在订阅的基础上,进行队列的分配。在这个过程中会执行元数据的变更和重平衡操作。而这些可以从审计日志中获取打印日志中可以看到很清楚。 下一篇,我们来看生产者和消费者的细节。生产者和消费者在执行操作前会执行一个操作init初始化操作,而这个初始化操作会将信息注册到将信息注册到MqClient中,因为只有将其进行统一管理的时候,在创建客户端对象的时候才会方便管理,同时方便调用,此时会启动心跳服务,此时少不了还有一个重要的操作就是注册消费组,同时需要关注一个点就是长轮询操作。
通常递归算法可以将一个问题的重复调用进行分解,将其分解成一个多次调用,最终完成筛选或者需要的数据。比如我们常见的斐波那契数列就是这样的: 0、1、1、2、3、5、8、13、21、34这样的递归数据,可以通过此来总结出它的数学公式规律:F(n) = F(n-1) + F(n-2)的这个过程就是是借助上面的F(0)和F(1)的结果来进行递推的,这个过程在数学上是一个数列的递推公式,在高中我们学过的数列上。我还记得当时求解递推公式可以使用函数方程,而函数方程的思想想想其实是借助了微分方程逆推得到积分方程的过程,或者说是采用不动点法可以实现这一求解的过程。这个过程,在我看到高等数学的时候才明白,现在想
一个好的通信框架是怎样的?同时如何使用netty? 一个好的通信框架,必然是支持双工通信的,同时它能够对半包黏包进行处理,方便高效的编解码、序列化,拥有心跳超时机制,同时支持大量连接并发,方便调用。而这个通信的过程,我始终是觉得它的起源是三次握手和四次挥手。它们影响着消息中间件和通信框架以及SOA框架的发展。netty最简单的是它的EchoServer和EchoClient,两者有同时有自己对应的处理器EchoServerHandler、EchoClientHandler。
首先需要对当前的id进行拦截操作,也即使用aop的切面Aspect对切点进行拦截,在进行新增的时候进行拦截: 也就是说在进行主键的生成时,我们拦截好需要生成的主键,此时就可以对其进行新增操作了,而首要的就是拿到它的primaryKey。由于进行新增操作,通常分为两种情况: 通过字节码拿到声明的方法getId,如果此时存在id,则说明此时的操作是更新操作,因此直接返回。如果当前通过字节码拿到的声明方法getTenant,通过租户方法拿到租户id。拿到租户id后,就可以进行主键id获取了。
需求是基于治疗数据,推送给平台,使用xml对数据进行组装,同时进行加密,里面包含所有的治疗数据与pdf,而生成是在完成治疗后进行数据的推送。这个过程是实时的,因此就需要考虑性能的问题,同时不能影响主流程。因此使用异步进行数据的推送,同时对生成的pdf需要进行加密,放入xml中。而提前的数据信息使用并行流的方式对数据进行组装。这里主要解决推送过程的方式。下面是最近的需求和解决的思路和方式。
SpringFactoriesLoader加载器加载指定ClassLoader下面的所有的META-INF/spring.factories文件,并将文件解析内容存在Map<string,list>中。然后通过loadFactoryNames传递过来的class的名称从map中获取该类的配置列表。通过Set集合进行去重操作。执行过滤组件操作,而这些操作都是在AutoConfigurationImportFilter接口下的组件实现的,也即FilterSpringBootCondition实现抽象类的。下面有OnBeanCondition、OnClassCondition、OnWebApplic
创建大数组实现对象:里面包含的信息公共初始化: 初始化页工厂:索引页工厂、数据页工厂、元数据页工厂,初始化数组索引、初始化数据页索引,通过队列前置索引页工厂获取索引页,获取队列front索引buffer,获取front,也即索引。这个实现和kafka是类似的,也即需要有相关页信息 入队列:进行入队操作是一个追加的操作,首先判断容量是否够,不够,则进行扩容操作。通过缓存拿到映射页实现,然后通过映射页。再通过锁,仅锁定创建页,索引用完后进行移除操作,映射页面实现,使用双向校验,如果为空,则创建页索引对象,通过索引拿到文件名称,然后通过读写通道进行读写操作。使用fileChannal调用映射方法获取
如果我们遇到的缓存比较大时,此时又需要考虑怎样的缓存设计呢? 此时由于缓存的消息或者信息比较大时,同时呈现成批量时,可以基于消息,考虑使用文件存储的方式进行,此时可以考虑NIO的处理方式,使用FileChannel和MappedByteBuffer或者堆外内存的方式,此时基于块状消息处理,使用缓冲区或者使用通道。此时的处理不经过用户态,因此性能上也是比较高的。 当然基于LinkedHashMap也可以实现LRU缓存设计。LinkedHashMap本身就是基于HashMap+双向链表实现的。
基于interceptor可以实现sql的完整打印,除了实现打印之外。其实还可以实现分页和排序,下面的分页和排序基于aop+mybatis的interceptor实现。其本质还是对mappedStament的boundSql进行增强。 下面的项目来源于github,通过这个我们可以很好的学习mybatis中插件interceptor的使用。
pmq是信也科技开源的一款消息中间件,虽然没有RocketMQ和Kafka出名,但是里面的代码还是有值得我们学习的地方的。 pmq的源码里面很多套路还是值得学习的,说实话,这些都是可以用到项目里面的。下面的代码来源于pmq。 首先安装好maven、mysql,对下载下拉的包进行打包: 如果遇到时区问题,则可以调整时区问题。 1.MqBootstrapListener 观察者模式的使用
连接完成之后,不能无所事事,此时应该会执行业务处理。也即此时可以看到上面的NettyServerHandler。因此可以看到dubbo的线程模型: 配置 Dubbo 中的线程模型 如果事件处理的逻辑能迅速完成,并且不会发起新的 IO 请求,比如只是在内存中记个标识,则直接在 IO 线程上处理更快,因为减少了线程池调度。 但如果事件处理逻辑较慢,或者需要发起新的 IO 请求,比如需要查询数据库,则必须派发到线程池,否则 IO 线程阻塞,将导致不能接收其它请求。 如果用 IO 线程处理事件,又在事件处理过程中发起新的 IO 请求,比如在连接事件中发起登录请求,会报“可能引发死锁”异常,但不会真死锁
问题:我们的线程:openSelector在什么时候创建的。 在创建NioEventLoop的时候,创建openSelector。 什么时候创建severSocketChannel、初始化serverSocketChannel,同时给serverSocketChannel从bossGroup中选择一个NioEventLoop 创建serverSocketChannel是在initAndRegister的时候,通过泛型+放射+工厂的方式创建serverSocketChannel。 而初始化则是设置channelOptions的相关参数信息、设置属性信息,同时通过channel的pipeline方
1.单一职责原则 单一职责原则:类的职责单一,不能将太多的职责放在一个类中,该原则是实现高内聚、低耦合的指导方针 比如:进行登录操作需要经过用户请求、参数校验、查找用户、连接数据库、操作数据库等这些操作 开闭原则:一个软件应当对扩展开发、对修改关闭。即在不修改源代码的情况下改变对象的行为 比如:我们现在需要查看报表,但是由于之前没有预留接口,导致没法进行扩展,出现需要修改原来的代码的情况: 里氏代换原则:在软件系统中,一个可以接收基类(父类)对象的地方必然可以接收一个子类对象。其属于开闭原则的实现
kafka分为客户端和服务端,通常我们知道broker是服务端,而生产者和消费者作为客户端。因此在服务端就必定需要解决并发和网络IO的问题。因此不可避免需要用到SocketChannel和ServerSocketChannel,可以看到kafka就使用了ServerSocketChannel,采用Netty来解决这个问题,这里socketServer采用了1个Acceptor,多个Processor。同时将请求发送到请求通道RequestChannel中。而我们知道RequestChannel中有一个请求队列和多个响应队列,通常响应队列是3个,这个参数是在kafka的配置中配置的。通过kafk
这里思考问题,什么时候会用到延迟组件,同时哪些时候会用到延迟组件,同时为什么要用延迟组件? 从kafkaApi中,我们可以知道具体的逻辑实现都是在这里实现的: DelayedOperation调用过程 同时基于时间轮进行时间过期的检测操作。 也即从这里我们可以看到DelayedProduce是协助副本管理器完成相应的延迟操作的,而副本管理器则主要是完成将生产者发送的消息写入到leader副本、管理follwer副本与leader副本之间的同步以及副本角色之间的转换。在上面的生产延迟中,我们可以看到在消息写入leader副本时需要DelayedProdue的协助。同时我们也可以看到:当生产请求的
在kafka启动时,首先执行的broker的操作,然后接着会执行生产者操作,接着将生产者的消息放入到存储中,此时生产者和broker会进行交互,而消费者发送消息,接着消费者会和broker交互。前面我们知道kafka在kafkaApi中会处理具体的请求。首先,我们再次来看kafkaApi的handle,可以看到其入参的参数是RequestChannel.request,也即我们需要找到ReuqestChannel,回忆在RocketMQ中,我们也可以看到请求的参数:ChannelHandlerContext和request在Processor中。也即request.header.apiKey匹
前面我们已经学习了特质类似接口,其可以被继承,同时如果需要继承多个特质的话,则需要使用extends…with…进行继承。其类似java中的接口和抽象方法的结合体,但又比java中的其要强大,因为其可以定义抽象字段和普通字段、抽象方法和普通方法。而在java中接口中可以定义常量,不能定义变量。同时特质还可以继承class类,而在java中接口通常是用来实现的。 Object继承trait
放入消息之后,进行操作体现在asyncSendMessage中。将消息以异步方式存储到存储器中,处理器可以处理下一个请求,而不是在结果完成后等待结果,以异步方式通知客户端。此时可以看到asyncPutMessage的操作中会进入到CommitLog中,此时进行提交日志操作,此时会执行写入到ByteBuffer中,然后刷盘到硬盘中。同时执行统计操作,进行HA同步。
首先NamesrvStartUp启动,首先经过main()方法,也是我们常见的main方法进入到main0()执行创建controller操作与启动controller操作这两个操作。而创建controller的操作则首先需要拿到namesrvConfig的配置信息和NettyServerConfig的配置信息,此时会 创建这两个对象,并填充配置信息然后放入到创建的controller对象中的构造函数中,并进行controller的启动操作,而启动操作首先会初始化一些信息和添加jvm钩子,也即会进行如下操作:加载键值对配置管理器、创建远程服务器remotingServer,创建远程线程池rem
前面我们已经通过quickstrat可以看到nameServer的启动:从启动类中,我们看到:首先创建NamesrvConfig、nettyServerConfig,设置监听端口,将8888改成9876。填充NamesrvConfig、NettyServerConfig、BrokerConfig,获取namesrvAddr,创建Controller,注册钩子函数,启动start。 NamesrvController的属性信息、构造函数:
首先从github中拉取Rocketmq的代码,进行运行。 1.由于rocketmq需要依赖nameServer,类似于zookeeper。首先启动时,配置好NamesrvStartup的环境变量信息,也即rocketmq的ROCKEMQ_HOME与你的项目对应。接着就可以启动了。
前面我们已经知道Netty服务端启动的时候最重要的是进行bind操作,这个操作不仅进行了run()操作进行死循环,而且将线程任务添加到队列中,进行runAllTasks操作。 首先,我们可以看Netty的架构图,图片来自即时通讯网:
前面我们已经了解了官方的Netty的example,知道要编写一个一个聊天demo或者一个简单的rpc,或者应答模式的demo,在Netty中通常需要写服务端和客户端的引导,而引导是启动服务用的,而服务端和客户端的Handler则是用于处理具体的业务逻辑。这个通常在RPC框架中比如Dubbo,通常会在服务进行暴露或者进行引用的时候,需要调用Netty服务进行启动,然后进行暴露或者调用的,此时采用协议适配的时候,采用适配器模式,而我们知道生产者端最重要的方法就是doBind方法,而在消费者端最重要的方法是doConnect方法。而在RocketMQ中,我们也可以看到服务端和消费端中produce