- 博客(177)
- 资源 (7)
- 收藏
- 关注
原创 Redis入门概述
一般像 MySQL 这类的数据库的 QPS(Query Per Second,服务器每秒可以执行的查询次数)大概都在 1w 左右(4 核 8g) ,使用 Redis 缓存之后很容易达到 10 w+,甚至最高能达到 30 w+(单机 Redis 的情况,Redis 集群的话会更高)。由此可见,直接操作缓存能够承受的数据库请求数量是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库,也就提高了系统整体的并发。
2024-08-04 22:30:43
664
原创 应用服务器集群的Session管理方案
应用服务器开启Web 容器的Session复制功能,在集群中的几台服务器之间同步Session对象,使得每台服务器上都保存所有用户的Session信息,这样任何一台机器宕机都不会导致 Session 数据丢失,而服务器使用Session时,也只需在本机获取。早期系统使用C/S架构,一种管理Session的方式是将Session记录在客户端,每次请求服务器的时候,将Session放在请求中发送给服务器,服务器处理完请求后再将修改过的Session响应给客户端。答案就是Session服务器!
2024-07-31 09:27:22
421
原创 几种分库分表后全局id生成方案
假设,在2175/11/7 12:12:14时间里,机房17的机器25,发送了第二条消息,snowflake算法服务,会发现说机房17的机器25,在2175/11/7 12:12:14时间里,在这一毫秒,之前已经生成过一个id了,此时如果你同一个机房,同一个机器,在同一个毫秒内,再次要求生成一个id,此时我只能把加1。twitter开源的分布式id生成算法,把一个64位的long型的id,1个bit是不用的,用其中的41 bit作为毫秒数,用10 bit作为工作机器id,12 bit作为序列号。
2024-07-30 21:10:12
397
原创 如何保证分布式服务接口的幂等性
系统异常时666请求到了,单号更成666,接着888请求到了,单号又更新成888,但是666更新成功的响应丢了,调用方没收到成功响应,自动重试,再次发起666请求,单号又被更新成666了,这数据显然就错了.若有一个订单已支付,就已经有了一条支付流水,那么如果重复发送这个请求,则此时先插入支付流水,orderId已存在,唯一键约束生效,报错插入不进去。对于更新订单服务,可以通过一个版本号机制,每次更新数据前校验版本号,更新数据同时自增版本号,这样的方式,来解决ABA问题,确保更新订单服务的幂等性。
2024-07-29 09:38:40
286
原创 分布式Session架构演示史
相应的用户会话都能放入redis中进行管理,如此,Tomcat中的会话,就是有状态的,一旦用户和服务端交互,就有会话,会话保存了用户的信息,这样用户就"有状态”了, 服务端会和每个客户端都保持着这样的一层关系,这个由容器来管理(也就是tomcat) , 这个session会话是保存到内存空间里。本质都是多个系统,假设这个里有两个服务器节点,分别是AB系统,他们可以是集群,也可以是分布式系统,一开始用户和A系统交互,那么这个时候的用户状态,我们可以保存到redis中, 作为A系统的会话信息,随后用户的请求。
2024-07-28 22:10:29
343
原创 从RPC角度如何看待Dubbo还是SpringCloud
所以语言不会成为使用上面这几种RPC框架的约束,而gRPC和Thrift虽然支持跨语言的RPC调用,但是因为它们只提供了最基本的RPC框架功能,缺乏一系列配套的服务化组件和服务治理功能的支撑,所以使用它们作为跨语言调用的RPC框架,就需要自己考虑注册中心、熔断、限流、监控、分布式追踪等功能的实现,不过好在大多数功能都有开源实现,可以直接采用。IDL使用了ProtoBuf,ProtoBuf是由Google开发的一种数据序列化协议,它的压缩和传输效率极高,语法也简单,所以被广泛应用在数据存储和通信协议上。
2024-07-28 09:25:20
262
原创 java常用消息模型
在Topic的消费过程,由于消息需要被不同组进行多次消费,所以消费完的消息并不会立即被删,这需要RocketMQ为每个消费组在每个队列维护一个消费位置(Consumer Offset),该位置之前的消息都被消费过,之后消息都未被消费过,每成功消费一条消息,消费位置加一。消费者在收到消息并完成消费业务逻辑(比如将数据保存到数据库)后,也会给服务端发消费成功的确认,服务端只有收到消费确认后,才认为一条消息被成功消费,否则它会给消费者重发送这条消息,直到收到对应的消费成功确认。如果可以,该如何实现?
2024-07-27 19:19:11
401
原创 消息队列面试之为什么要使用消息队列
如果你说的共享内存指的是PageCache,很多消息队列都会用到,RDMA据我所知常见的几种消息队列应该都还没有使用,像Kafka它在消费的时候,直接使用Zero Copy,数据直接从PageCache写到NIC的缓冲区中,都不需要进入应用内存空间。消息队列不可能能存放无限的消息,消息队列满应该也会有拒绝策略,比如线程池的任务队列,任务队列满,并且超过最大的线程池数,四种的拒绝策略。秒杀开始后,当短时内大量秒杀请求到达网关,不会直接冲击后端秒杀服务,而是先堆积在MQ,后端服务尽力从MQ消费请求并处理。
2024-07-26 08:35:17
228
原创 Java异步编程常用 场景梳理
看transfer()方法,先调用一次账户服务accountService.add()方法从fromAccount扣减相应金额,因add()方法返回的就是个CompletableFeture对象,可用CompletableFeture的thenCompose()方法将下一次调用accountService.add()串联起来,实现异步依次调用两次账户服务完整转账。太多的线程会造成频繁的cpu上下文切换,你可以想象一下,假设你的小公司只有8台电脑,你雇8个程序员一直不停的工作显然是效率最高的。
2024-07-25 08:46:47
705
原创 NIO网络编程详解之Selector事件选择器
在并发量大的时候,使用同一个线程处理连接请求以及消息服务,可能会出现拒绝连接的情况,这是因为当该线程在处理消息服务的时候,可能会无法及时处理连接请求,从而导致超时;通过keys()和selectKeys()返回的键的集合是Selector对象内部的私有的Set对象集合的直接引用。已注册的键的集合是只读的。如果在多个线程并发地访问一个选择器的键的集合的时候存在任何问题,可以采用同步的方式进行访问,在执行选择操作时,选择器在Selector对象上进行同步,然后是已注册的键的集合,最后是已选择的键的集合。
2024-07-24 08:24:09
801
原创 Netty4-实战精华之EventLoop和线程模型详解
然而在一些无状态上下文中,它仍可被用于在多个 Channel 之间共享一些重度的或者代价昂贵的对象,甚至是事件。但在 Netty3 的模型,因这是个入站事件,需在调用线程中执行代码,然后将事件移交给 I/O 线程去执行,这会带来额外上下文切换开销。而 Netty 的线程模型强大又易用,正如 Netty 的宗旨:简化你的应用程序代码,同时最大限度提高性能和可维护性。除这种受限场景,传输所采用的不同事件处理实现,其线程模型也会严重影响排队的任务对整体系统性能影响。中所产生的所有事件,则解决了该问题。
2024-07-21 14:36:17
588
原创 Java高性能系统缓存的最佳实践
如果你的系统是那种可预测未来访问哪些数据的,比如有的系统它会定期做数据同步,每次同步数据范围都一样,这样的系统,缓存策略简单,你要访问什么数据,就缓存什么数据,甚至可做到百分百命中。读写缓存的设计,本身就不可靠,牺牲数据一致性换取性能。从不更新缓存数据,而是给缓存中的每条数据设较短的过期时间,数据过期后即使还存在缓存,也认为不再有效,需从磁盘再次加载这数据,变相实现数据更新。再比如,有会话的系统,你知道现在哪些用户是在线,哪些用户已离线,那优先置换那些已离线用户的数据,尽量保留在线用户的数据也是好策略。
2024-07-20 20:33:05
588
原创 IO多路复用之poll、epoll和select区分
对于第二个缺点,epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。取而代之的是,每个孩子如果自己需要尿尿的时候,自己主动的站到事先约定好的地方,而保姆的职责就是查看事先约定好的地方是否有孩子。select的调用复杂度是线性的,即O(n)。
2024-07-20 10:38:15
1201
原创 操作系统之存储管理
新复制的页面对执行写操作的进程是私有的,对其他共享写时复制页面的进程是不可见的。根据程序的局部性原理,一般情况下,进程在一段时间内总是集中访问一些页面,这些页面称为活跃页面,如果分配给一个进程的物理页面数太少了,使得该进程所需的活跃页面不能全部装入内存,则进程在运行过程中将频繁发生中断。缺页越多,系统的性能越差,这称为颠簸(抖动):虚存中,页面在内存与磁盘之间频繁调度,使得调度页面所需的时间比进程实际运行的时间还多,这样导致系统效率急剧下降,这种现象称为颠簸或抖动。的处理速度和内存的访问速度。
2024-07-16 08:31:46
414
原创 操作系统详解之进程管理
大多数系统调用是阻塞的,因此,由于内核阻塞进程,故进程中所有线程也被阻塞。以一次一页的方式复制父进程的地址空间,这是一个无用功,因为创建子进程就是为了让子进程完成与父进程不同的工作,所以父进程的很多内容其实子进程是不需要的。上面的两个进程都有这样一个地址空间,也就是说这两个进程是在不同的地址空间上的相同的位置,所以虽然地址是一样的,但是实际上在实际内存中的地址是不一样的。一组进程中,每个进程都无限等待被该组进程中另一进程所占用的资源,因而永远无法得到的资源,这种现象称为进程死锁,这一组进程就称为死锁进程。
2024-07-15 08:15:59
954
原创 操作系统之内存管理
内存管理包括内存管理和虚拟内存管理内存管理包括内存管理概念、交换与覆盖、连续分配管理方式和非连续分配管理方式(分页管理方式、分段管理方式、段页式管理方式)。虚拟内存管理包括虚拟内存概念、请求分页管理方式、页面置换算法、页面分配策略、工作集和抖动。3.1 内存管理的概念内存管理(Memory Management)是操作系统设计中最重要和最复杂的内容之一。虽然计算机硬件一直在飞速发展,内存容量也在不断增长,但是仍然不可能将所有用户进程和系统所需要的全部程序和数据放入主存中,所以操作系统必须将内存空间
2024-07-14 21:11:55
660
原创 Java常见JUC并发工具类
所谓的乐观读模式,也就是若读的操作很多,写的操作很少的情况下,你可以乐观地认为,写入与读取同时发生几率很少,因此不悲观地使用完全的读取锁定,程序可以查看读取资料之后,是否遭到写入执行的变更,再采取后续的措施(重新读取变更信息,或者抛出异常) ,这一个小小改进,可大幅度提高程序的吞吐量。当RPC结果返回时,会调用doReceived()方法,这个方法里面,调用lock()获取锁,在finally里面调用unlock()释放锁,获取锁后通过调用signal()来通知调用线程,结果已经返回,不用继续等待了。
2024-07-13 19:55:45
699
原创 了解零拷贝之前必须要了解的操作系统基础知识
当外围设备完成用户请求的操作后,会向 CPU 发出相应的中断信号,这时 CPU 会暂停执行下一条即将要执行的指令而转到与中断信号对应的处理程序去执行,如果前面执行的指令是用户态下的程序,那么转换的过程自然就会是从用户态到内核态的切换。它的原理是:动态保存每一个程序的起始物理内存地址和长度,然后每次访问指定的内存地址时,CPU 会在把地址发往内存总线之前自动把基址寄存器里的值加到该内存地址上,得到一个真正的物理内存地址,同时还会根据界限寄存器里的值检查该地址是否溢出,若是,则产生错误中止程序。
2024-07-13 19:19:37
664
原创 RocketMQ 消费者之顺序消费和流程详解附源码解析
顺序消费的消费任务也由拉取任务提交,逻辑改成了:持续消费一个队列的消息,直到该队列的消息消费完或者超过最大消费时间(1分钟)。队列中的多个消息并发消费:消费者执行消费逻辑时,使用一个消费线程池进行消费,该线程池默认有 20 个线程同时进行消费,所以也有可能并发消费一个队列中的多个消息。),消费任务开始时获取锁,消费任务结束时释放锁,保证就算有多个线程同时消费一个队列,但同时最多只有一个线程真正在执行消费(其他线程都在等待锁释放)。并发消费的消费线程池,每个线程的消费任务是:消费一批(默认一条)消息。
2024-07-12 08:31:19
1089
原创 RocketMQ之消费者,消息消费、消费进度上报流程详解 附源码解析
从上一步拉取消息到消费者后,将拉取到的一批消息提交给并发消费服务,并发消费服务将消息封装成一个个消费请求(每个消费请求将消费一批消息,默认一批只包含一条消息)提交给消费线程池进行消费。新创建的重试消息是定时消息,它的 Topic 是定时消息 Topic,定时消息的机制会不停扫描定时消息 Topic 中的队列,看该消息是否到期,如果到期则投递。Broker 收到请求后用延迟消息机制,用该消息重新消费的次数计算延迟等级,生成一个新消息,将重新消费次数 + 1,作为延迟消息放入消息存储。消费成功则更新消费进度;
2024-07-12 08:24:04
1377
原创 RocketMQ之消费者,消息拉取流程详解附源码解析
上一篇重平衡篇有提到,重平衡将为消费者负载的队列创建拉取请求并放入队列,后续不会新建而是重复使用这个拉取请求,取出执行一次,拉取完成之后更新拉取偏移量,再将它重新放入队列。消息拉取流控检查,检查处理队列中还未被消费的消息,从待消费消息数量、大小和待消费消息偏移量差来判断。根据队列找到对应的消费队列,读取消费队列判断是否有消息可以消费,如果有则根据消费队列中的索引项,用物理偏移量从消息存储中查找消息。消费者的处理线程池处理拉取完成的回调,将消息从拉取到的响应中解码出来,放入消费队列,让消费服务消费。
2024-07-09 08:45:32
685
原创 RocketMQ之消费者,重平衡机制与流程详解附带源码解析
RocketMQ 的重平衡大致实现方式为:在消费者端用一个固定的分配策略将所有的消费队列分配给所有的消费者。通过将每个消费者的分配策略设置成一致,并且将消费者和消费队列排序的方法,保证每个消费者的分配的结果幂等。我把重平衡的触发分为主动触发和被动触发,主动触发是由消费者的启动和停止触发的;推模式消费者启动或恢复时,唤醒本地的重平衡线程,立即重平衡。进行重平衡,客户端实例的该方法没有具体逻辑,仅仅是遍历客户端上注册的所有消费者,获取它们的重平衡实现并且调用。其他消费者收到消费者数量变化请求时进行重平衡。
2024-07-09 08:23:04
1161
原创 RocketMQ之消费者,客户端设计和启动流程详解附带源码解析
推模式消费者实际内部也是通过拉取消息的方式进行消息拉取,只不过封装了订阅和监听器这样的对外接口,让用户在使用时感觉像 Broker 主动推送消息到消费者。拉模式消费者的消费步骤为:拉取消息,执行消费逻辑,上报消费进度,如果有需要的话对于消费失败的消息还需要发回 Broker 重新消费。推模式消费者消费步骤更简单,只需要订阅一个 Topic,然后指定消费回调函数,即可在收到消息时自动消费。就是我们实际消费中需要新建的消费者对象。由于拉模式和推模式消费者的启动流程大致相同,所以只介绍推模式消费者的启动流程。
2024-07-08 22:43:08
861
原创 RocketMQ之消费者带你了解概念和消费流程
需要注意的是,这里所说的顺序消费指的是队列维度的顺序,即在消费一个队列时,消费消息的顺序和消息发送的顺序一致。为消费者分配队列消费的这一个负载过程并不是一劳永逸的,比如当消费者数量变化、Broker 掉线等情况发生后,原先的负载就变得不再均衡,此时就需要重新进行负载均衡,这一过程被称为重平衡机制。如果是集群消费模式,还需要将消费进度让其他消费者知道,所以需要提交消费进度。在集群消费模式下,消费组中的消费者共同消费订阅的 Topic 中的所有消息,这里就存在 Topic 中的队列如何分配给消费者的问题。
2024-07-08 08:15:27
889
原创 RocketMQ IndexFile 索引文件
存储的每个值是在索引文件中 索引的逻辑下标。因为索引文件的 Header 和 Hash Slot 部分长度都是固定的,每个索引的长度也是固定的,所以可以通过逻辑下标计算出索引项在索引文件中的绝对偏移量。列表中的索引文件,查找索引对应的 message 符合时间的 IndexFile([beginTimestamp, endTimestamp] 与 [begin, end] 有交集的索引文件)索引文件的刷盘机制并不是采取定时刷盘机制,而是每写满一个索引文件时就新建一个文件,并且将上一个写满的索引文件刷盘。
2024-07-04 08:51:51
398
原创 RocketMQ 消息发送设计和原理详解 源码剖析
消息的路由指的是发送消息时需要先获取 Topic 的路由信息(其中包含每个 Topic 的队列和它们所在的 Broker 地址),然后选择一个队列进行发送。消息发送的 API 提供了参数,可以传入要发送的队列信息,或者传入队列选择方法,以供用户选择发往某个 Broker 的具体队列。RocketMQ 的 Java 客户端提供了丰富的消息发送 API,支持多种消息发送的方式和特殊消息的发送。包括 3 种发送方式(同步、异步、单向)和多种特殊消息(顺序消息、延时消息、批量消息、过滤消息、事务消息)。
2024-07-04 08:26:14
344
原创 RocketMQ NameServer源码剖析
基于性能的考虑,NameServer 本身的实现非常轻量,而且可以通过增加机器的方式水平扩展,增加集群的抗压能力,而 zookeeper 的写是不可扩展的,而zookeeper 要解决这个问题只能通过划分领域,划分多个zookeeper集群来解决,首先操作起来太复杂,其次这样还是又违反了CAP中的A的设计,导致服务之间是不连通的。NameServer 是一个简单的 Topic 路由注册中心,类似 Kafka、Dubbo 中的 Zookeeper,支持 Broker 的动态注册与发现。
2024-07-03 08:47:55
694
原创 RabbitMQ 进程内流控(Flow Control) 源码解析
Erlang没有对进程邮箱的大小进行限制,所以当有大量消息持续发往某个进程时,会导致该进程邮箱过大,最终内存溢出并崩溃。这可能是由于将消息存入队列的过程中引起服务器 CPU 负载过高,或者是将队列中的消息存入磁盘的过程中引起服务器 I/O 负载过高而引起的此种情形。状态,说明它们最近处于流控状态。当 reader 进程开始处理一条消息,它会先将自己的信用值-1,然后将消息处理完后发给 channel 进程(图中2)这里的进程与操作系统的进程不同,是一个由 Erlang 系统管理的轻量级进程。
2024-06-30 16:25:23
371
原创 到底什么是认证
JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该 token 也可直接被用于认证,也可被加密。如果你的用户通过社交账号登录,例如微信登录,微信作为身份提供商会颁发自己的 Access Token,你的应用可以利用 Access Token 调用微信相关的 API。你的应用必须安全地存储 Refresh Token,它的重要性和密码是一样的,因为 Refresh Token 能够一直让用户保持登录。
2024-04-24 23:40:45
497
原创 JVM虚拟机监控及性能调优实战
J-Djava.rmi.server.hostname=xx.xx.xx.xx hostname是本机IP地址,确保client能访问到,另外查看本机的hosts是否有其他配置,这里有坑,具体参照常见问题中的。到https://visualvm.github.io/pluginscenters.html去下载对应的Visual GC Plugins。打开jvisualvm,在远程中添加需要监控的服务器,然后再在该服务器下添加jmx监控连接。jvisualvm集成Visual-GC插件。
2024-04-24 23:30:08
754
1
原创 SpringBoot配置入门
在目前的 Spring Boot 项目中,当发生了任何修改之后我们都需要重新启动才能够正确的得到效果,这样会略显麻烦,Spring Boot 提供了热部署的方式,当发现任何类发生了改变,就会通过 JVM 类加载的方式,加载最新的类到虚拟机中,这样就不需要重新启动也能看到修改后的效果了。如果承载的是WEB项目,使用Spring MVC作为MVC框架,那么工作流程和你上面描述的是完全一样的,因为这部分工作是Spring MVC做的而不是Spring Boot。
2024-04-23 12:10:35
758
原创 单元测试一篇汇总
但事实上,写测试代码与否,还是有很大区别的,如果是在小的项目中,或许这种区别还不太明显,但如果在大型项目中,一旦出现错误或异常,用人力去排查的话,那将会浪费很多时间,而且还不一定排查的出来,但是如果用测试代码的话,JUnit 就是自动帮我们判断一些代码的结果正确与否,从而节省的时间将会远远超过你写测试代码的时间。它还引入了一些新功能,使其更强大,更易于使用,如:注解,运行在大线程池中进行各种策略测试,多线程安全验证代码测试,灵活的测试配置,数据驱动的参数测试支持等等。再码一点,再测一点,如此循环。
2024-04-23 12:07:38
553
原创 Linux内核与基础命令学习总结
因此,目录的 r 权限表示可以读取文件列表;过程调用的流程: fork & exec一个进程生成子进程的过程是,系统首先复制(fork)一份父进程,生成一个暂存进程,这个暂存进程和父进程的区别是pid不一样,而且拥有一个ppid,这时候系统再去执行(exec)这个暂存进程,让他加载实际要运行的程序,最终成为一个子进程的存在。软连接是指一个文件的inode节点不存数据,而是存储着另一个文件的绝对路径,访问文件内容时实际上是去访问对应路径下的文件inode,这样的话文件发生改动或者移动都会导致软连接失效。
2024-04-16 12:58:07
1102
原创 Redis集群机制及一个Redis架构演进实例
Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-Sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。但是,Twemproxy存在诸多不方便之处,最主要的是,Twemproxy无法平滑地增加Redis实例,业务量突增,需增加Redis服务器;
2024-04-16 12:54:33
1123
原创 Hibernate入门经典与注解式开发大全
原因是我们在Customer类中配置了mappedBy=”c”,它代表的是外键的维护由Order方来维护,而Customer不维护,这时你在保存客户时,级联保存订单,是可以的,但是不能维护外键,所以,我们必须在代码中添加订单与客户之间的关系。从上面的HQL查询,我们就可以发现:HQL查询是需要SQL的基础的,因为还是要写少部分的SQL代码....QBC查询就是完全的面向对象查询...但是呢,我们用得比较少。我们是不知道该XML是怎么写的,可以搜索一下Hibernate文件夹中后缀为.hbm.xml。
2024-04-15 13:02:26
885
原创 搞懂分布式技术:缓存更新的套路
一个是查询操作,一个是更新操作的并发,首先,没有了删除cache数据的操作了,而是先更新了数据库中的数据,此时,缓存依然有效,所以,并发的查询操作拿的是没有更新的数据,但是,更新操作马上让缓存的失效了,后续的查询操作再把数据从数据库中拉出来。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。不是的,比如,一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,所以,会造成脏数据。
2024-03-17 11:53:29
746
原创 一文搞懂分布式事务常用解决方案
用户通过页面投保,提交一笔订单过来,这个订单通过上游服务,处理保单相关的业务逻辑,最后流入下游服务,处理业绩、人员晋升、分润处理等等业务。从这三种一致型的模型上来说,我们可以看到,弱一致性和最终一致性一般来说是异步冗余的,而强一致性是同步冗余的,异步处理带来了更好的性能,但也需要处理数据的补偿。最后,达到最大重试次数以后,可以将消息加入到一个告警列表,这个告警列表可以展示在管理后台或其他监控系统中,展示一些必要的信息,去供公司内部人员去人工介入,处理这种异常的数据,使得数据达到最终一致性。
2024-01-22 09:40:24
1046
原创 一文搞懂分布式session解决方案与一致性hash
hash环上顺时针从整数0开始,一直到最大正整数,我们根据四个ip计算的hash值肯定会落到这个hash环上的某一个点,至此我们把服务器的四个ip映射到了一致性hash环当用户在客户端进行请求时候,首先根据hash(用户id)计算路由规则(hash值),然后看hash值落到了hash环的那个地方,根据hash值在hash环上的位置顺时针找距离最近的ip作为路由ip.当Web服务器变为多台以后,如果保证同一个会话的请求都在同一个Web服务器上处理,则对该会话来说,与之前单机的情况是一样的。
2024-01-22 09:38:20
932
原创 保证缓存一致性的常用套路
一个是查询操作,一个是更新操作的并发,首先,没有了删除cache数据的操作了,而是先更新了数据库中的数据,此时,缓存依然有效,所以,并发的查询操作拿的是没有更新的数据,但是,更新操作马上让缓存的失效了,后续的查询操作再把数据从数据库中拉出来。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。不是的,比如,一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,所以,会造成脏数据。
2024-01-21 13:13:52
967
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人