文章 62
浏览 15135
哈希槽和一致性hash

哈希槽和一致性hash

- 首先,从使用 hash 取模数据分片开始说起 先从经典的 hash 取模数据分片说起 经典哈希取模分片的问题和对策: -** 一致性 hash 算法** 第一阶段,需要完成 key 到 slot 槽位之间的映射 第二阶段,需要完成 slot 槽位到 Redis node 节点之间的映射。 Hash 槽位环 一致性哈希原理: 经典场景 1:Key 入环 经典场景 2:新增 Redis 节点 经典场景 3:删除 Redis 节点 -** 经典哈希取模与一致性 hash 的对比:** -** 一致性 hash 的数据不平衡(数据倾斜)问题** 什么是 虚拟节点? 一致性 hash 的简易实现 回顾下一致性 Hash 算法 -** Redis 为什么使用哈希槽而不用一致性哈希** -** Redis Cluster 集群核心特点一:去中心化** 先看分布式集群的设计中的核心:元数据存储 设计。 中心化的 元数据存储架构 去中心化的 元数据存储架构 -** 去中心化场景如何保证元数据一致?** 问题 1:Redis 如何进行数据分片的? Redis cluster 哈希槽 增加节点 减少节点....

单生产者单消费者模式队列的搭建(三)

单生产者单消费者模式队列的搭建(三)

包装消费者 我要包装消费者的原因很简单,因为之前我为自己的程序引入进度序号 Sequence 时,我说现在消费者有了自己的消费进度,看起来更加立体了,所以想包装它一下。但是现在我想再跟大家提出另一个要包装它的重要原因。这个原因当然也很简单,那就是消费逻辑都是用户自己定义的,这就决定了它的身份比较特殊,不能只是一个简单的线程执行一个任务。当然,最后用户定义的消费者逻辑,或者说消费者任务肯定是要交给线程执行的。但是,从用户提交消费者任务,到线程最终开始执行这个任务之间会发生什么呢?让我来给大家分析一下。 比如说,还是沿用上一章的例子,环形数组中存放的都是一个个 Request 对象,而生产者真正生产的是 Integer 对象。这就意味着消费者最后要消费的就是这个 Integer 对象。比如说消费者的消费逻辑就是得到这个 Integer 对象,然后在控制台输出一句“我消费了第 +Integer+ 个数据了”,如果是这样的话,那么这个消费逻辑是不是就应该定义到一个 Runnable 当中,然后把这个 Runnable 交给一个消费者线程来执行?那么在线程执行这个任务之前,是不是应该知道,这个任....

单生产者单消费者模式队列的搭建(二)

单生产者单消费者模式队列的搭建(二)

大家好,在上一章的结尾,我苦于程序中存在太多的问题,迫切地希望给程序来一个翻天覆地的变革和重构。并且,我还为自己的队列找准了一个切入点,就是把 ArrayBlockingQueue 类中的 count 成员变量去掉。改为直接比较读写指针来判断我的队列是否可读可写。当然,我知道有的朋友可能会说,只是一个简单的 count 成员变量而已,费不着大动干戈,其实只要把 count 定义为 AtomicInteger 类型的,然后让它使用 getAndIncrement 方法自增就行了,用 CAS 方式解决并发问题。这确实是个好办法,但是,我相信我大刀阔斧重构之后的程序会非常完美,所以,我宁愿按照自己的方式来重构程序。 那么,话说回来,为什么我会忽然产生这样一种想法,或者说我的编程思路怎么突然转变了呢?因为我终于意识到,避免并发问题的终极解决方法,也是最简单的方法,就是不让多个线程产生操作数据的交汇,不让它们操作相同的数据。这一点一旦明确了,很快我就发现我之前在 ArrayBlockingQueue 类中定义的 count 成员变量的唯一作用就是用来和容器数组的长度进行判断,然后决定队列目前是否....

单生产者单消费者模式队列的搭建(一)

单生产者单消费者模式队列的搭建(一)

简单回顾 JDK 中的队列体系 **队列是什么,我相信大家都很清楚了。**所谓队列,就是一个线性容器,加上操作容器的一些规则。线程容器就是数组,链表(其实,在我看来链表并不能算作容器,它的每一个节点都是一个对象,用指针连接构成了链表本身。我们可以说链表就是把一些对象或者说一些数据精心设计之后,实现了容器的作用,但不能说链表本身就是一个容器。但这些小概念都无关紧要了)。而操作这个容器的规则就是从数组的一端存入数据,从另一端将数据取出,并且操作的过程中要让这些数据先进先出。 按照上面的规则来实现一个队列,显然非常容易了。请看下面的定义。 数组 + 先进先出 = 队列 链表 + 先进先出 = 队列 其实,在 JDK 中的队列,几乎都是采用了上面两种定义实现的。比如大家最熟悉的 ArrayBlockingQueue 和 LinkedBlockingQueue 队列。这些队列的结构也都很简单,首先,还是定义一个通用的接口 Queue,然后在该接口中定义几个基础方法。请看下面代码块。 public interface Queue<E> extends Collection<E&g....

我用spark导出500万数据

我用spark导出500万数据

背景 最近公司需要实现一个报表功能,需要导出近一段时间内的数据,时间段由用户在页面填写,作为 SQL 参数查询过滤,因为涉及到查询的信息详细,需要关联的表过多和字段过多,以及数据量过大,可能会有性能方面的问题 方案一: 多线程分页多 sheet+ 队列(发布订阅) 网上有很多的方案说了,用多线程分批处理,自己也写了个 demo 实现,多线程分批分页查询 + 发布订阅队列 + 分 sheet 写入,虽然功能实现了,最终测试 500 万数据,结果需要将近 8 分钟了,感觉不太满意这种方式,后面想到我们公司的服务器有大数据方面环境,想着能不能用大数据解决,最终决定用 spark 方案二:spark+cxv 经过查找资料和自己学习,基本掌握了一点 spark 的知识和整合 Java +springboot,发现 spark 天生支持这种大数据量的整合处理 基本思路就是,通过 spark 大数据引擎分布式连接 JDBC 读取数据库的数据,然后写入到 CSV 文件到 hdfs 或者到本地文件系统,最终从 hdfs 或者本地写入搭配 response 响应流给前端下载 @GetMapping("/d....

高效能list转tree树形结构,扁平化线性复杂度

高效能list转tree树形结构,扁平化线性复杂度

背景 最近在做业务的时候,发现有很多地方需要将数据库查询出来的 list 转为 tree 结构,基于面向对象的思想,想着做成一个通用的工具类,使用泛型,然后首先想到的是使用递归,O(n * n) 后面觉得递归的传统方式,时间复杂度过高,基于此进行优化,想到了一个线性规划的方式,进行数据扁平化转为线性复杂度 O(N) 接口限定 定义一个 ItreeNode 接口,该接口主要用来子类实现,自己定义父节点的规则,只要使用方自己实现 parent 方法,自己定义父节点的规则,这样就无需 id 和 parentId 必须提前限制类型了, string 或者对象都可以作为获取父节点的基准 import java.util.List; /** * 通过实现该接口的子类 自己定义parent的规则 * @param <T> */ public interface ITreeNode<T> { T parent(); void setChildren(List<T> children); List<T> getChildren(); } 第一版 使用....

当 Redis 碰上 @Transactional,有大坑

当 Redis 碰上 @Transactional,有大坑

标题: 探索 Redis 与 @Transactional 注解的冲突之谜 正文: 前言 在我们的项目中,我们遇到了一个让人费解的生产环境问题:每天早上,当运营人员后台尝试创建新事件时,系统总是无法成功创建。经过重新启动相关微服务后,系统又能恢复正常运行,直到次日早上问题再次出现,又得重启服务。 初步调查 我们发现,问题出现在使用 Redis 生成唯一分布式 ID 的过程中。每天早上,Redis 的递增操作异常地返回了 null 值,导致后续流程中断。重新启动服务似乎是暂时的解决方法,但根本问题仍然悬而未决。 return redisTemplate.opsForValue().increment("count", 1); 深入探索 根据重启后就恢复正常,我们推测晚上执行了大量的 job,大量 Redis 连接未释放,当早上再来执行 Redis 操作时,执行失败。重启后,连接自动释放了。但是其他有使用到 Redis 的业务功能又是正常的,所以推测一的方向有问题,排除 。 通过查询 ```redisTemplate 递增的方法 increment` 源码注释, 发现事务&管道会返....

spring的STOMP落地实践

spring的STOMP落地实践

背景 公司有个主系统 A,这个系统将来用途作为 SaaS 服务系统,设计尽可能保持纯粹,不要引入过多的中间件技术 其下有 B,C 甚至未来还有多个子系统,现在的需求是需要当子系统 B,C 开启了某个配置,需要对接 A 系统,A 系统能够提供 B,C 系统的能力赋能,当 BC 断开配置,B,C 又是个纯粹可以单独运行的系统,某个系统不共用同一套数据,拥有自己的环境和数据,当子系统开启了配置,相关接口功能需要限制,由主系统提供能力,断开配置,A.B,C 三个系统能够独立运行 功能拆分 主系统: 对主系统相关的增量和全量接口数据进行同步传输:这里有两个关键点 有许多增量接口需要进行同步传输&&传输数据的逻辑不能影响原先的业务逻辑(通过 AOP 注解) 需要找到一个类型消息队列 mq 那种形势进行数据同步,A 系统数据发生改动子系统能够感知 但是这个系统不能引入过多的中间件,最终经过调研,选择使用了 Spring 的 STOMP 和 Spring event 事件实现一种伪消息队列 子系统: 子系统相关接口限制:通过 AOP 接口限制 子系统需要接收主系统的全量和增量数据 (S....

人民有信仰 民族有希望 国家有力量