当前位置: 首页 > news >正文

互联网金融网站建设网站建设教程纯正苏州久远网络

互联网金融网站建设,网站建设教程纯正苏州久远网络,网站开发通常叫什么部门,重庆网站的制作价格缓存双写一致性 更新策略探讨 面试题 缓存设计要求 缓存分类#xff1a; 只读缓存#xff1a;#xff08;脚本批量写入#xff0c;canal 等#xff09;读写缓存 同步直写#xff1a;vip数据等即时数据异步缓写#xff1a;允许延时#xff08;仓库#xff0c;物流 只读缓存脚本批量写入canal 等读写缓存 同步直写vip数据等即时数据异步缓写允许延时仓库物流异常出现有可能需要使用 kafka, rabbitmq 进行弥补重试重写 双检加锁 如果 qps 过高会打高 mysql 数据库和缓存更新的几种策略 》实现最终一致性 可以停机-单线程操作 四种更新策略 先更新数据库再更新缓存 异常问题1-最后更新redis异常出现脏数据 异常问题2-多线程更新快慢问题无法保证第二步写redis的顺序 先更新缓存再更新数据库 业务上mysql是底单数据 仍然是多线程更新的问题 自己的理解只要是写缓存的方式都会存在线程写入先后导致的数据不一致 先删除缓存再更新数据库 第一个进来的线程当数据库写未提交或者其他异常情况的时候仍然可能存在脏数据问题因为无法保证缓存会被一定及时删除可能中途被其他线程回写这段要自己脑子里跑一遍延迟双删来确保旧的缓存会被删除掉 读缓存会写入旧数据 延时双删 先更新数据库再删除缓存-主流 存在问题-没来得及更新完缓存会读取到旧值但伤害较小 只要涉及到数据库和缓存的双写百分百存在一致性问题 如何实现最终一致性 只能实现最终一致性 如何取舍总结 双写一致性落地案例 监听 binlog mysql - canal - redis Home canal 选择版本 1.6.1 mysql: 5.7 docker环境安装 1.mysql 准备 docker run -d -p 3306:3306 --privilegedtrue -v /root/mysql/log:/var/log/mysql -v /root/mysql/data:/var/lib/mysql -v /root/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD123456 --name mysql mysql:5.7docker exec -it e8b72b11df2a /bin/bash //e8b72b11df2a 就是容器idmysql -uroot -p // 密码 123456# 查看是否开启 binlog SHOW VARIABLES LIKE log_bin;# 添加 canal 操作账号 DROP USER IF EXISTS canal%; CREATE USER canal% IDENTIFIED BY canal; GRANT ALL PRIVILEGES ON *.* TO canal% IDENTIFIED BY canal; FLUSH PRIVILEGES;SELECT * FROM mysql.user;# 创建一张表 CREATE TABLE t_user ( id BIGINT ( 20 ) NOT NULL AUTO_INCREMENT, userName VARCHAR ( 100 ) NOT NULL, PRIMARY KEY ( id ) ) ENGINE INNODB AUTO_INCREMENT 10 DEFAULT CHARSET utf8mb42.canal 准备 下载 canal.deployer-1.1.6.tar.gz 修改配置文件 canal.instance.master.addressxxx:xxx:xxx:xxx:3306# username/password (如果配置的是 canal/canal 则默认无需修改) canal.instance.dbUsernamecanal canal.instance.dbPasswordcanal./bin/startup.sh查看启动日志检查运行状态 3.编写 canal-client parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion2.7.10/versionrelativePath/ !-- lookup parent from repository --/parentdependencies!--canal--dependencygroupIdcom.alibaba.otter/groupIdartifactIdcanal.client/artifactIdversion1.1.0/version/dependency!--SpringBoot与Redis整合依赖--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.26/version/dependency/dependenciesbuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId/plugin/plugins/build配置文件(请按需修改) server:port: 5555spring:redis:database: 0host: 127.0.0.1port: 6379 # password: 123456config 文件和 springboot 案例中一致 Configuration public class RedisConfig {Beanpublic RedisTemplateString, Object redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {RedisTemplateString, Object redisTemplate new RedisTemplate();redisTemplate.setConnectionFactory(lettuceConnectionFactory);// 设置key的序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());// 设置value的序列化方式jsonredisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());// 设置hash的key的序列化方式stringredisTemplate.setHashKeySerializer(new StringRedisSerializer());// 设置hash的value的序列化方式jsonredisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;} }biz 操作封装 Component public class RedisCanalClient {ResourceRedisTemplate redisTemplate;/*** 读取 canal 数据写入redis* param columns 行*/public void redisInsert(ListCanalEntry.Column columns) {JSONObject jsonObject new JSONObject();for (CanalEntry.Column column : columns) {System.out.println(column.getName() : column.getValue() update column.getUpdated());jsonObject.put(column.getName(), column.getValue());}if (columns.size()0) {redisTemplate.opsForValue().set(columns.get(0).getValue(), jsonObject.toJSONString());}}/*** 读取 canal 数据删除 redis 行* param columns 行*/public void redisDelete(ListCanalEntry.Column columns) {JSONObject jsonObject new JSONObject();for (CanalEntry.Column column : columns) {System.out.println(column.getName() : column.getValue() update column.getUpdated());jsonObject.put(column.getName(), column.getValue());}if (columns.size()0) {redisTemplate.delete(columns.get(0).getValue());}}/*** 读取 canal 数据修改 redis 行* param columns 行*/public void redisUpdate(ListCanalEntry.Column columns) {JSONObject jsonObject new JSONObject();for (CanalEntry.Column column : columns) {System.out.println(column.getName() : column.getValue() update column.getUpdated());jsonObject.put(column.getName(), column.getValue());}if (columns.size()0) {redisTemplate.opsForValue().set(columns.get(0).getValue(), jsonObject.toJSONString());System.out.println(----------------update after: redisTemplate.opsForValue().get(columns.get(0).getValue()));}}/*** 读取 canal 数据并操作* param entrys 行*/public void printEntry(ListCanalEntry.Entry entrys) {for (CanalEntry.Entry entry : entrys) {if (entry.getEntryType() CanalEntry.EntryType.TRANSACTIONBEGIN || entry.getEntryType() CanalEntry.EntryType.TRANSACTIONEND) {continue;}CanalEntry.RowChange rowChage null;try {rowChage CanalEntry.RowChange.parseFrom(entry.getStoreValue());} catch (Exception e) {throw new RuntimeException(ERROR ## parser of eromanga-event has an error , data: entry.toString(),e);}CanalEntry.EventType eventType rowChage.getEventType();System.out.println(String.format(gt; binlog[%s:%s] , name[%s,%s] , eventType : %s,entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),eventType));for (CanalEntry.RowData rowData : rowChage.getRowDatasList()) {if (eventType CanalEntry.EventType.DELETE) {redisDelete(rowData.getBeforeColumnsList());} else if (eventType CanalEntry.EventType.INSERT) {redisInsert(rowData.getAfterColumnsList());} else {redisUpdate(rowData.getAfterColumnsList());}}}}}test 测试类 SpringBootTest public class CanalClientTest {public static final Integer _60SECONDS 60;ResourceRedisCanalClient redisCanalClient;/*** 测试 canal client 监听 server 实现 mysql - redis*/Testpublic void startClient() {System.out.println(--------------initCanal main()方法------------);// CanalConnector connector CanalConnectors.newSingleConnector(new InetSocketAddress(127.0.0.1, 11111), // canal server 地址example,,);int batchSize 1000;int emptyCount 0;System.out.println(---------------------canal init OK开始监听mysql变化------);try {connector.connect(); // connector.subscribe(.*\\..*);// 设置监听的表connector.subscribe(canal.t_user);connector.rollback();int totalEmptyCount 10 * _60SECONDS;while (emptyCount totalEmptyCount) {System.out.println(我是 canal, 每秒一次正在监听: UUID.randomUUID().toString());Message message connector.getWithoutAck(batchSize); // 获取指定数量的数据long batchId message.getId();int size message.getEntries().size();if (batchId -1 || size 0) {emptyCount;System.out.println(empty count : emptyCount);try {Thread.sleep(1000);} catch (InterruptedException e) {}} else {// 计数器置0emptyCount 0;// System.out.printf(message[batchId%s,size%s] \n, batchId, size);redisCanalClient.printEntry(message.getEntries());}connector.ack(batchId); // 提交确认// connector.rollback(batchId); // 处理失败, 回滚数据}System.out.println(已经监听了totalEmptyCount秒无任何消息请重启重试);} finally {connector.disconnect();}} }启动测试类 4.测试 测试新增 手动添加一条记录 id: 7 name:666 查看 redis 测试修改 修改mysql id:7 的 name 为 777 测试删除 删除 id:7 的这条数据
http://www.hkea.cn/news/14338045/

相关文章:

  • 网站 业务范围电商运营基础知识
  • 怎样做淘宝商品链接导航网站哪些行业做网站最重要
  • 徐州建筑网站个人衣服定制店铺
  • 移动端网站设计尺寸无锡网站建设楚天软件
  • 视频网站制作教程视频建立平台要多少钱
  • 江夏区做网站建筑行业最新资讯
  • 没有网站也可以做推广吗怎么给老板提供网站建设资料
  • 为什么网站打不开外贸如何开发客户的方式
  • 邯郸专业做网站地方可信赖的商城网站建设
  • 建设网站对公司起什么作用是什么意思网站建设的知识
  • 手机英语网站中国包装设计网
  • 长沙专业网站建设公司哪家好wordpress空间购买
  • 正能量不良网站软件下载东莞网站建设公司口碑排名
  • 滁州网站定制wordpress页眉描述
  • jsp网站建设项目实战 pdf百度云搜索引擎入口网盘搜索神器
  • 网站备案管谁要幕布建设网站费用入会计分录
  • 郑州的网站公司哪家好wordpress怎么恢复默然设置
  • 商机网网站源码长沙有什么好玩的
  • dede做的网站打不开建网站需要什么服务器
  • 国外注册品牌 建设网站wordpress页面修改插件
  • 藁城 网站青海省住房和城乡建设局网站
  • 做网站找图片做爰网站有哪些
  • 电子商务网站建设与全程实例怎样用电脑和网訨自己做网站
  • 江西网站开发公司电话wordpress当前位置
  • 地方门户网站管理系统wordpress ftp主机
  • 怎么在境外做网站搜索引擎关键词快速优化
  • 云浮建设网站长春网站排名推广
  • 如何诊断网站宣城建设网站
  • 做卡贴的网站wordpress大不了
  • 网站加图标wordpress怎么换语言