一致性哈希
分布式缓存对于经常使用的数据,我们一般会使用 Redis 作为缓存机制,为了实现高可用,使用了3台Redis(没有设置集群,集群至少要6台)。 使用hash算法,存储的时候根据公式 h = hash(key)%机器节点数,h 为 Redis 对应的编号,取数据的时候也根据相同的公式取,因此一定可以从存储的机器中拿到想要的数据。但是使用这种策略可能会存在以下问题: 假设有一台 Redis 服务器宕机了,此时每个 key 就要按照 h = hash(key)%(机器节点数-1) 重新计算 假设要新增一台 Redis 服务器,此时每个 key 就要按照 h = hash(key)%(机器节点数+1) 重新计算 也就是说,如果服务节点有变更,会导致缓存失效,大量的 key 需要重新计算,在这期间如果有请求进来,就会直接打到数据库上,导致缓存雪崩。 一致性哈希算法一致性哈希是讲整个哈希空间组织成一个虚拟的圆环,假设哈希函数 H 的值空间为 [0,2^32-1](哈希值是32位无符号整形)。 把服务器按照 IP 或者主机名作为关键字进行哈希,确定服务器在哈希环中的 ...
深入浅出Spring AOP
对AOP的理解AOP(Aspect-Oriented Programming:面向切面编程),它实际做的就是将业务和一些非业务进行拆解,降低彼此业务模块与非业务模块的耦合度,便于后续的扩展维护。例如权限校验、日志管理、事务处理等都可以使用AOP实现。而Spring就是基于动态代理实现AOP的。如果被代理的类有实现接口的话,就会基于JDK Proxy完成代理的创建。反之就是通过Cglib完成代理创建。 Spring AOP和AspectJ AOP的区别知道吗? 答: 其实Spring AOP属于运行时增强,基于代理(Proxying)实现的。而AspectJ AOP属于编译时增强,基于字节码操作(Bytecode Manipulation)实现的。相比之下后者比前者更成熟、更强大一些。如果在切面不多的情况下,两者差异是不大的,如果切面非常多的话,后者性能会比强者好很多。 AOP中有很多核心术语,分别是: 目标(Target): 这就被代理的对象,例如我们希望对UserService每个方法进行增强(在不动它的代码情况下增加一些非业务的动作),那么这个UserService就是目标 ...
MyBatis源码
MyBatis 执行流程首先回顾一下jdbc的执行流程。 MyBatis的执行流程也包含jdbc的执行流程,但是会做一些前置处理。 方法代理(MapperMethod)使用动态代理调用,可以看到非常熟悉的 invoke 方法,这个invoke方法就是动态代理的逻辑,method.invoke()方法就是实现代理类对原始方法的调用。 12345678910111213141516171819202122232425262728public class MapperProxy<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = -6424540398559729838L; private final SqlSession sqlSession; private final Class<T> mapperInterface; private final Map<Method, MapperMethod> ...
jdbc的演变
jdbc流程 jdbc操作jdbc连接123456789101112131415161718@Testpublic void testConnection5() throws Exception {//1.加载配置文件InputStream is =ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);//2.读取配置信息String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");//3.加载驱动 ...
自定义starter
starter介绍Spring Boot Starter是什么? Spring Boot Starter可以被理解为一种依赖的集合,也可以看作是一个空的项目,它由pom.xml文件配置了一堆jar包的组合。 Spring Boot Starter解决了什么问题? Spring Boot Starter解决了手动配置大量依赖项和参数的问题。在Spring Boot之前,如果要开发一个Web应用程序,需要手动添加很多依赖项,如Servlet、JSP、JSTL等,并且还需要配置很多参数,如数据源、事务管理器等。而通过使用Spring Boot Starter,开发者只需要添加一个Starter依赖,就可以轻松地集成各种不同的功能模块,而无需关心底层的配置和集成细节。 Spring Boot Starter的价值是什么? Spring Boot Starter的价值在于它能够提高开发效率和代码质量,同时减少开发成本和复杂度。通过使用Starter,开发者可以专注于业务逻辑的实现,而不需要关心底层的配置和集成细节。另外,Starter还支持更快的迭代和部署,因为它们通常包含了一些可重用的依赖库和 ...
MySQL语句执行原理
count(*) 的实现方式在不同的MySQL引擎中,count(*)有不同的实现方式。 MyISAM引擎把一个表的总行数存在了磁盘上,因此执行count(*)的时候会直接返回这个数,效率很高; 而InnoDB引擎就麻烦了,它执行count(*)的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数。 这篇文章里讨论的是没有过滤条件的count(*),如果加了where 条件的话,MyISAM表也是不能返回得这么快的。 为什么InnoDB不跟MyISAM一样,也把数字存起来呢? 由于多版本并发控制(MVCC)的原因,InnoDB表“应该返回多少行”也是不确定的。每一行记录都要判断自己是否对这个会话可见,因此对于count(*)请求来说,InnoDB只好把数据一行一行地读出依次判断,可见的行才能够用于计算“基于这个查询”的表的总行数。 用缓存系统保存计数一般会想到使用 Redis 缓存总数,但是即使 Redis 正常工作,这个值还是逻辑上不精确的。 因为使用 Redis 存储会存在数据不一致的情况,无论是先往数据表里插入一行,然后 Redis 计数 + 1; 还是先 Redi ...
MySQL高可用
MySQL主备一致MySQL 主从复制 主库将数据库中数据的变化写入到 binlog 在从库上通过change master命令,设置主库的IP、端口、用户名、密码,以及要从哪个位置开始请求binlog,这个位置包含文件名和日志偏移量。 在从库上执行start slave命令,这时候从库会启动两个线程,就是图中的io_thread和sql_thread。其中io_thread负责与主库建立连接。 主库校验完用户名、密码后,创建一个 binlog dump 线程,开始按照从库传过来的位置来发送 binlog ,从库中的 I/O 线程负责接收 从库的 I/O 线程将接收的 binlog 写入到 relay log 中。 从库的 SQL 线程读取 relay log 同步数据本地(也就是再执行一遍 SQL )。 基于位点的主备切换把节点B设置成节点A’的从库的时候,需要执行一条change master命令: 1234567CHANGE MASTER TO MASTER_HOST=$host_name #IPMASTER_PORT=$port #端口M ...
基于Git分支模型的理解与思考
进入企业后,开发过程中为了实现多人同步协作,企业往往会有一套 git 分支规范,这和学习中遇到的分支大有不同。本文是对 git 成熟模型 A successful Git branching model 的理解和对公司约定的 git 分支规范的思考。 在实际生产开发的过程中,如果每个人都随意的创建分支,随意的提交commit,必将导致整个git仓库非常的混乱,不易于团队协作。Vincent Driessen 同学为了解决这个问题提出了 A successful Git branching model,最后形成了业内普遍采用的 git 工作流程,大家都在约定的流程内使用git,使得团队协作效率大大提高‌。 为什么使用Git?Git 是一个分布式版本管理工具,在多人协作的条件下高效处理任何规模的软件工程,并对项目版本、状态做环境隔离。每一个Git克隆都是一个完整的文件库,含有全部历史记录和修订追踪能力,不依赖于网络连接或中心服务器。最大特色是分支和合并操作非常快速、简便。 与SVN相比,git有以下5点优势: 版本库本地化,支持离线提交,相对独立不影响协同开发。每个开发者都拥有自己的版本 ...
MySQL学习笔记
MySQL 的基本架构要想探究 MySQL 的执行原理,首先要了解 MySQL 的基础架构,从中清楚看到 SQL 语句在 MySQL 的各个模块中的执行过程。 Server层涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。 连接器第一步,先连接到数据库,这时候接待你的就是连接器。连接器负责跟客户端建立连接、获取权限、维持和管理连接。连接命令一般是这么写的: 1mysql -h$ip -P$port -u$user -p 连接命令中的mysql是客户端工具,用来跟服务端建立连接。在完成经典的TCP握手后,连接器就要开始认证你的身份,这个时候用的就是你输入的用户名和密码。 如果用户名或密码不对,你就会收到一个”Access denied for user”的错误,然后客户端程序结束执行。 如果用户名密码认证通过,连接器会到权限表里面查出你拥有的权限。之后,这个连接里面的权限判断逻辑,都将依赖于此时读到的权限。 因此,一个用户成功建立连接后,它的权限会维持在建立连接那一刻读到的 ...
对设计模式的理解
设计模式设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。同时设计模式也是软件开发人员在软件开发过程中面临的一般问题的解决方案。 策略模式策略模式主要是会定义一系列的算法或策略,其中的算法和策略都是独立封装,互不影响的。通过策略模式,可以在运行时选择不同的策略进行匹配,而不需要修改客户端的代码。 我们可以参考 xxl-job 里的路由策略编写逻辑,其中的路由策略就是一个标准的策略模式例子。现给出 xxl-job 的路由策略结构图。 同时观察 xxl-job 的源码,XxlJobTrigger 中的 processTrigger() 方法中有一段关于路由策略的逻辑 根据传入的 jobInfo 获取到路由策略的参数 如果是分片广播,则for循环调用外部传入的index获取执行器地址并调用执行器。 反之根据参数获取路由策略调用获取对应地址并调用即可。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051 ...
java8新特性
Java8 新特性Java8 新增了一些新特性,详情请参考 ORACLE官网—JDK8新增功能 本篇文章仅整理出常用的几个特性,日常开发中可灵活使用。 Lambda 表达式以前,我们可以使用Collections 工具类的 Comparator 比较器对给定的 List 集合进行排序。 123456789List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");Collections.sort(names, new Comparator<String>() { @Override public int compare(String a, String b) { return b.compareTo(a); }}); 现在有了 lambda 表达式以后,推荐使用以下方法比较大小: 12Collections.sort(names, ( ...
浅谈RocketMQ负载均衡策略
消息队列存在生产者和消费者,其中RocketMQ的生产者和消费者都有分组。 生产者负载均衡生产者发送消息到RocketMQ时,RocketMQ将根据生产者负载均衡将消息均匀存储在多个队列中。 同步刷盘,只有在消息真正持久化至磁盘后RocketMQ的Broker端才会真正返回给Producer端一个成功的ACK响应。同步刷盘对MQ消息可靠性来说是一种不错的保障,但是性能上会有较大影响,一般适用于金融业务应用该模式比较多。 异步刷盘:能够充分利用OS的PageCache的优势,只要消息写入PageCache即可成功的将ACK返回给Producer端。消息刷盘采用后台异步线程提交的方式进行,降低了读写延迟,提高了MQ的性能和吞吐量。 RoundRobin模式对于非顺序消息(普通消息、定时/延时消息、事务消息),默认且只能使用RoundRobin模式。 生产者发送消息时,以消息为粒度,按照轮询方式将消息发送到指定主题中的所有可写目标队列中,保证消息尽可能均衡分布到所有队列。 故障规避策略当生产者某条消息发送失败时,RocketMQ会决定在接下来一段事件内,跳过本地失败队列所在节点 ...
avatar
Palette
这是一个终身学习的时代
Follow Me
公告

欢迎来到「Palette」个人技术博客!🎉

本平台专注于:

  • > JAVA后端技术笔记
  • > 场景设计解决方案
  • > AI应用实践

🌟 一起钻研技术,共同进步!