canal

并发环境下,先操作数据库还是先操作缓存?

耗尽温柔 提交于 2020-12-05 05:23:55
前言 在分布式系统中,缓存和数据库同时存在时,如果有写操作的时候,先操作数据库还是先操作缓存呢?先思考一下,可能会存在哪些问题,再往下看。下面我分几种方案阐述。 缓存维护方案一 假设有一写(线程A)一读(线程B)操作, 先操作缓存,在操作数据库 。,如下流程图所示: 1)线程A发起一个写操作,第一步del cache 2)线程A第二步写入新数据到DB 3)线程B发起一个读操作,cache miss, 4)线程B从DB获取最新数据 5)请求B同时set cache 这样看,没啥问题 。我们再看第二个流程图,如下: 1)线程A发起一个写操作,第一步del cache 2)此时线程B发起一个读操作,cache miss 3)线程B继续读DB,读出来一个老数据 4)然后老数据入cache 5)线程A写入了最新的数据 OK,酱紫,就有问题了吧,老数据入到缓存了, 每次读都是老数据啦,缓存与数据与数据库数据不一致 。 缓存维护方案二 双写操作, 先操作缓存,在操作数据库 。 1)线程A发起一个写操作,第一步set cache 2)线程A第二步写入新数据到DB 3)线程B发起一个写操作,set cache, 4)线程B第二步写入新数据到DB 这样看,也没啥问题。 ,但是有时候可能事与愿违,我们再看第二个流程图,如下: 1)线程A发起一个写操作,第一步set cache 2)线程B发起一个写操作

致敬最优秀的同行者们

余生颓废 提交于 2020-12-03 07:42:11
做 积 极 的 人 , 越 努 力 越 幸 运 ! 真的非常开心,『中间件兴趣圈』公众号粉丝数正式迈过1W大关,达成一个重要里程碑,笔者感慨真的不容易。 2018年10月19号通过公众号发布第一篇文章,到今天为止,公众号已经发表了145篇原创文章,坚持真的很难,但只要能坚持,就一定会有好的收获,这不,你瞧,1W个人与你一起同行,这成就不可谓不大。 在持续坚持努力下,我出版了《RocketMQ技术内幕》一书,从一家名不经传的小公司顺利跳槽到快递物流头部企业:中通快递,让我能在更高的平台上发光发热,使我深深的认识到: 越努力越幸运,唯有坚持不懈 。希望能用这句话与各位粉丝朋友共勉,相互交流,共同成长。 相信各位读者朋友们也能直观的感受到『中间件兴趣圈』主要发表的文章都比较枯燥,因为大部分都是以源码分析为主,认真读完一篇文章需要极大的耐心,我从后台的统计数据上看到,每篇文章的读完率其平均值在50%左右,这足以说明大家拥有强烈的求知欲望,这里必须有掌声,为各自点个赞吧。与各位优秀的读者同行,是我的一大荣幸,未来继续加油。 『中间件兴趣圈』的定位是记录笔者的学习历程与成长历程,同时也起到驱动笔者去学习,给自己提的要求是尽最大努力保证一周一篇原创文章。 绝不注水、绝不洗稿,这是我的初心也是底线。 『中间件兴趣圈』现阶段主要以源码分析为手段成体系剖析JAVA主流中间件

二十七、mysql如何确保数据不丢失?有几点值得我们借鉴

雨燕双飞 提交于 2020-11-30 01:03:57
本篇文章我们先来看一下mysql是如何确保数据不丢失的,通过本文我们可以了解mysql内部确保数据不丢失的原理,学习里面优秀的设计要点,然后我们再借鉴这些优秀的设计要点进行实践应用,加深理解。 预备知识 mysql内部是使用b+树的结构将数据存储在磁盘中,b+树中节点对应mysql中的页,mysql和磁盘交互的最小单位为页,页默认情况下为16kb,表中的数据记录存储在b+树的叶子节点中,当我们需要修改、删除、插入数据时,都需要按照页来对磁盘进行操作。 磁盘顺序写比随机写效率要高很多,通常我们使用的是机械硬盘,机械硬盘写数据的时候涉及磁盘寻道、磁盘旋转寻址、数据写入的时间,耗时比较长,如果是顺序写,省去了寻道和磁盘旋转的时间,效率会高几个数量级。 内存中数据读写操作比磁盘中数据读写操作速度高好多个数量级。 mysql确保数据不丢失原理分析 我们来思考一下,下面这条语句的执行过程是什么样的: start transaction; update t_user set name = '***' where user_id = 666; commit; 按照正常的思路,通常过程如下: 找到user_id=666这条记录所在的页p1,将p1从磁盘加载到内存中 在内存中对p1中user_id=666这条记录信息进行修改 mysql收到commit指令 将p1页写入磁盘 给客户端返回更新成功

mysql和redis双写一致性策略分析

大兔子大兔子 提交于 2020-11-28 12:48:11
mysql和redis双写一致性策略分析 一.什么是双写一致性 当我们更新了mysql中的数据后也可以同时保证redis中的数据同步更新; 数据读取的流程: 1.读取redis,如果value!=null,直接返回; 2.如果redis中value=null,读取mysql中数据对应的value,将key-value保存在redis中; 双写一致性策略: 策略1:先更新缓存,再更新数据库; 策略2:先更新数据库,再更新缓存; 策略3:先删除缓存,再更新数据库; 策略4:先更新数据库,再删除缓存; 二.四种策略存在的问题和优势 1.先更新缓存,再更新数据库 问题:这种策略如果redis更新成功,mysql更新失败,这时造成redis脏数据问题,这种策略是绝对不能使用的; 2.先更新数据库,再更新缓存 问题:这种策略的主要问题就是发生在并发场景下,当线程ThreadA更新mysql后由于某种原因并没有立刻更新redis缓存,这时线程ThreadB立即将数据库和缓存都更新成功,最后ThreadA将redis中的数据进行更新,这时就会造成ThreadB对缓存的更新丢失,这是一个很严重的问题; 3.先删除缓存,再更新数据库 问题:这种策略的主要问题也是发生在并发场景下,当ThreadA更新数据库之前先将redis中的数据进行删除,在更新数据库;但是在并发场景下回有一个问题

数据异构重器之 Canal 初探

泪湿孤枕 提交于 2020-11-26 04:13:43
后面会连载 好友丁威 的Canal系列文章,今天为第一篇。 1、应用场景 提到 Canal,大家应该都能想到这是一个用于解析 MySQL binlog 日志的工具,并将 MySQL 数据库中数据同步到其他存储介质中,例如 Elasticsearch。 即 Canal 一个非常常用的使用场景:数据异构,一种更高级别的数据读写分离架构设计方法。 随着业务不断的发展,企业发展到一定阶段,发现单体的关系型数据库已无法支撑业务高速发展带来数据不断累积的压力,从而会诞生出一种设计架构:分库分表。分库分表对缓解单库数据库压力确实是一种非常好的解决方案,但又衍生出另外一种困境,关联查询不友好,甚至跨库JOIN就更加如此。 举例说明如下:例如一个订单系统,通常有两类用户需要去查询订单,一类是顾客,一类是商家,在对数据库进行分库分表时,如果以顾客(buy_id)进行分库的话,同一个商家的订单数据会分布在不同的库中,如果以商家(shop_id)进行分库的话,同一个用户购买的所有订单数据将会分布在不同的库中,这样进行关联查询,就必然需要跨库进行join,其成本都会偏高。而且上面的场景只能满足一方的需求,那如何是好呢? Canal 这个时候就闪亮登场了,在电商设计中,其实商家、顾客会被拆分成两个不同的服务,我们可以为两个不同的服务搭建不同的数据库集群,我们可以用户订单库、商家订单库进行分库

秒杀全网!SpringCloud微服务电商实战项目(整套源码+视频+文档)

强颜欢笑 提交于 2020-11-21 00:36:02
写文章很久了,听到粉丝问的最多的问题就是:有没有新的完整的项目,因为现在很多流传的项目都太老了,实战意义不是很强。很多程序员每项技术单独拿出来有可能很厉害,例如:springcloud、springboot、redis、nginx、mysql、rabbitMq等,但是普遍缺乏将所有的这些技术整合到一起,从前端到后端,从开发到部署上线,从每个知识点到整体的设计。 本次分享不是分享项目而是教你如何开发一个项目细节流程。 简介 项目技术栈 基于springBoot2.x、springCloud采用前后端分离的架构;利用FastDFS作为分布式文件存储系统,Canal实现数据同步,监控数据变化;Elasticsearch+IK+Kibana实现商品搜索功能;Spring Security Oauth2 JWT实现微服务统一认证和资源授权;利用RabbitMq实现异步解耦;Seata实现分布式事务等,从而打造一个高可用的分布式电商系统。 技术架构 系统架构 功能教程 模块说明 项目截图 资料介绍 项目源码 视频教程 工具清单 再次说明,本次分享不是分享项目!而是教你如何开发一个项目细节流程,希望你能够在实际开发中能够得心应手! 需要获取得话麻烦一键三连之后看下图小助理的微信:( vip1024x )添加即可免费获取到哦 来源: oschina 链接: https://my.oschina

【LeetCode】22 验证回文串

孤街浪徒 提交于 2020-11-20 08:42:41
题目 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 说明 :本题中,我们将空字符串定义为有效的回文串。 示例 1: 输入: "A man, a plan, a canal: Panama" 输出: true 示例 2: 输入: "race a car" 输出: false 思路 就是记住几个常用的内置方法 String的toLowerCase() 字符串转为小写 String的toCharArray() 字符串变换成字符的序列转换。它返回一个新分配的字符数组。返回的数组长度等于字符串的长度 StringBuild的append() 追加字符 StringBuild的reverse() 字符串翻转 Character.isLetterOrDigit 是在Java一个内置的方法,该方法确定是否指定的字符是字母或数字。 代码 import java.util.*; public class Solution { public boolean isPalindrome(String s) { String str = s.toLowerCase(); StringBuilder sb = new StringBuilder(); for(char c : str.toCharArray()){ if(Character.isLetterOrDigit(c

并发环境下,先操作数据库还是先操作缓存?

江枫思渺然 提交于 2020-11-06 23:53:38
前言 在分布式系统中,缓存和数据库同时存在时,如果有写操作,先操作数据库还是先操作缓存呢?本文将分5种方案展开阐述对比,谢谢阅读~ github地址,衷心感谢每一颗star ❝ https://github.com/whx123/JavaHome ❞ 缓存维护方案一 如果是一读(线程B)一写(线程A)操作,「先操作缓存,再操作数据库」。流程图如下所示: 1.线程A发起一个写操作,第一步del cache 2.线程A第二步写入新数据到DB 3.线程B发起一个读操作,cache miss缓存失效了。 4.线程B从DB获取最新数据 5.线程B执行set cache,把从DB读到的数据,更新到缓存。 「这样看,没啥问题」。我们再看第二个流程图,如下: 1.线程A发起一个写操作,第一步del cache 2.此时线程B发起一个读操作,cache miss 3.线程B继续读DB,读出来一个老数据 4.然后老数据设置入cache 5.线程A写入DB最新的数据 OK,酱紫,就有问题了吧,老数据入到缓存了,「每次读都是老数据啦,缓存与数据与数据库数据不一致了」。 缓存维护方案二 上个方案是一读一写,如果是双写操作,「先操作缓存,在操作数据库」,会怎么样呢? 1.线程A发起一个写操作,第一步set cache 2.线程A第二步写入新数据到DB 3.线程B发起一个写操作,set cache 4

验证回文字符串(leetcode)

喜欢而已 提交于 2020-11-02 13:32:47
题目描述如下: 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 说明: 本题中,我们将空字符串定义为有效的回文串。 示例 1: 输入: "A man, a plan, a canal: Panama" 输出: true 示例 2: 输入: "race a car" 输出: false c++代码如下: class Solution { public: bool isPalindrome(string s) { int left = 0, right = s.size(); while (left < right) { if (!isAlphaNum(s[left])) ++left; else if (!isAlphaNum(s[right])) --right; else if ((s[left] + 32 - 'a') %32 != (s[right] + 32 - 'a') % 32) return false; else { ++left; --right; } } return true; } inline bool isAlphaNum(char &ch) { if (ch >= 'a' && ch <= 'z') return true; if (ch >= 'A' && ch <= 'Z') return true; if (ch

「从零单排canal 03」 canal源码分析大纲

独自空忆成欢 提交于 2020-11-02 02:56:21
在前面两篇中,我们从基本概念理解了canal是一个什么项目,能应用于什么场景,然后通过一个demo体验,有了基本的体感和认识。 从这一篇开始,我们将从源码入手,深入学习canal的实现方式。了解canal相关功能的实现方式,其中有很多机制是非常值得深入了解的,从代码实现角度去学习实时数据订阅与同步的核心技术点。当然,如果要在生产中使用这个开源项目,了解源码更是必不可少,是解决问题和新特性定制的前提条件。 本文使用的版本是1.1.4,这也是笔者写这篇博客时的最新稳定版。 1.准备工作 下载源码 git clone https: //github.com/alibaba/canal.git 切换到1.1.4这个tag git checkout canal-1 .1 .4 或者可以关注我的源码注释版本(正在不断更新中) https: / /github.com/saigu /JavaKnowledgeGraph/tree /master/code _reading/canal 2.canal项目模块介绍 canal项目是基于maven构建的,将不同的功能模块划分了不同的子模块。 我们可以简单执行可执行模块deployer,也可以将模块通过maven依赖的方式,将你需要的子模块引入到你自己的项目中进行使用开发。 简单介绍下核心模块的功能: deployer模块:独立部署模块,用于canal