昨天面试遇到的一个面试题,到现在还是不明白

沪php攻城师 2015-03-31 10:01:04
昨天去面试了一家公司,架构师职位,两位面试官都着重提出了一个问题问我解决方案。
问题是:MYSQL主从服务器,主写从读,如何保证高并发下主库写入的数据从库一定马上获得该数据?(意思大概是我这里写入了主库,其他程序可以立即拿到更新后的数据,而不是你写入我却拿到更新前的)
我的第一反应是:怎么会有这种需求,有的话也是从业务逻辑上就解决了这种问题。
第二反应是:不可能实现,两台服务器必然有延时,再快速度也必然会有主已经写入而从还没有更新情况。
第三反应是:即使想要和单服务器数据库一样利用事务来解决,两台服务器利用事务的开销也是性能上不可接受的。

不知道有哪位高人能找到完美解决的方法,反正我到现在还是上面三种意见。
...全文
1049 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
fcqm8888 2015-04-13
  • 打赏
  • 举报
回复
用云技术可以解决吧?
zapdos 2015-04-01
  • 打赏
  • 举报
回复
引用 8 楼 jzh2004 的回复:
[quote=引用 5 楼 zapdos 的回复:] [quote=引用 4 楼 jzh2004 的回复:] [quote=引用 3 楼 benluobobo 的回复:] 后台mysql主从复制 在主从复制前面搭建缓存即可 先写缓存,后写主库 先读缓存,后读从库
这是我一开始提出的一个方法,读写缓存,但是面试官的意思是这些数据不是独立的,是可能有复杂查询的,比如某表写入一条数据,读时可能读取包括这条在内的多条数据,甚至可能有多表连接等复杂查询。所以缓存也不现实。 [/quote] 可能她说的不是缓存数据,而是缓存事务信息吧 创建一个全局事务版本信息,主库缓存写事务快照信息,从库在读取时根据缓存的快照决定是否堵塞等待数据复制完毕 不然数据还没复制到从库的话,你怎么折腾也没用 当然有些查询是不需要获取最新数据的,部分查询可以不用等待同步[/quote] 这是一个解决方法,不过不明白如何缓存事务快照,还有就是我的第三个反应的问题,这样做是否会大大影响性能,一个是每个访问先要读缓存,一个是读取缓存后处理事务快照应该也是程序实现的吧,这些开销在高并发下不会小。 [/quote] postgres-xc分布式数据库就是用这个全局事务管理来控制数据版本的,可以参考一下 首先写节点只要把缓存放本地,或者用zookeeper处理了 读节点可以横向扩展,所以高并发的压力可以横向扩展解决,读取缓存的性能开销可以由读节点负责 postgres-xc的数据是多版本的,事务快照存储的是进行中的事务ID和提交完的事务ID等信息,读节点可以根据这个去处理本地数据版本不一致的问题,如果有新的数据提交上来的话可以等待同步,如果事务未处理完可以用旧版本数据,并且读节点一般不加写锁,所以高并发下不会堵塞,只有等待同步的时候才会有所停顿 这种改动不需要用户改变逻辑,而是数据库层面的处理
沪php攻城师 2015-04-01
  • 打赏
  • 举报
回复 1
引用 10 楼 starfd 的回复:
[quote=引用 9 楼 jzh2004 的回复:] [quote=引用 6 楼 starfd 的回复:] SL模式只听过,没接触过…… 我听过新蛋的做法,当然新蛋用的是mssql 它们的做法是:跟新主库的同事,在一个公共库里面插入更新时间戳,同步程序更新完后,更新读库的时间戳,读数据时同时从公共库和读库两个地方读数据,如果发现两边时间戳不一致,就从主库读数据,否则从读库读数据
放在数据库里非常影响性能,放缓存里就和楼上说的差不多,但是这种开销在高并发里还是影响很大的。而且只是时间戳的话,恐怕不能应对多条查询,而如果是锁表的话,那估计在高并发下从库就没用了。[/quote] 因为我也是听新蛋出来的人说的,这个是SQL大版版主邹建设计的,里面肯定没我描述的那么简单[/quote] 其实说穿了,是我还没有明白什么业务场景需要这样的需求,别人做事务是为了防止写冲突,而这个需求却是要求写入马上读取最新数据。 问题是不是同一个用户做的写和读,另一个用户有必要必须马上知道最新的更新吗?难道如果没有最新的写,老数据读取就会出错吗,如果不会出错,那么就当做你读的时候人家还没有写不就行了。 如果一定要实时通知到其他用户,那么做推送好了。
沪php攻城师 2015-04-01
  • 打赏
  • 举报
回复 1
引用 7 楼 benluobobo 的回复:
需要实时性的直接去主库上查 不需要实时性的去从库上上查 如果真要保证读从写主,中间同步啥耗费的时间还不如直接从主库读
是一个好办法,不过这恐怕不是面试官要的答案,因为这个是从业务逻辑上处理了,而不是他要的实时同步的解决方案。
  • 打赏
  • 举报
回复
引用 9 楼 jzh2004 的回复:
[quote=引用 6 楼 starfd 的回复:] SL模式只听过,没接触过…… 我听过新蛋的做法,当然新蛋用的是mssql 它们的做法是:跟新主库的同事,在一个公共库里面插入更新时间戳,同步程序更新完后,更新读库的时间戳,读数据时同时从公共库和读库两个地方读数据,如果发现两边时间戳不一致,就从主库读数据,否则从读库读数据
放在数据库里非常影响性能,放缓存里就和楼上说的差不多,但是这种开销在高并发里还是影响很大的。而且只是时间戳的话,恐怕不能应对多条查询,而如果是锁表的话,那估计在高并发下从库就没用了。[/quote] 因为我也是听新蛋出来的人说的,这个是SQL大版版主邹建设计的,里面肯定没我描述的那么简单
沪php攻城师 2015-04-01
  • 打赏
  • 举报
回复
引用 6 楼 starfd 的回复:
SL模式只听过,没接触过…… 我听过新蛋的做法,当然新蛋用的是mssql 它们的做法是:跟新主库的同事,在一个公共库里面插入更新时间戳,同步程序更新完后,更新读库的时间戳,读数据时同时从公共库和读库两个地方读数据,如果发现两边时间戳不一致,就从主库读数据,否则从读库读数据
放在数据库里非常影响性能,放缓存里就和楼上说的差不多,但是这种开销在高并发里还是影响很大的。而且只是时间戳的话,恐怕不能应对多条查询,而如果是锁表的话,那估计在高并发下从库就没用了。
沪php攻城师 2015-04-01
  • 打赏
  • 举报
回复
引用 5 楼 zapdos 的回复:
[quote=引用 4 楼 jzh2004 的回复:] [quote=引用 3 楼 benluobobo 的回复:] 后台mysql主从复制 在主从复制前面搭建缓存即可 先写缓存,后写主库 先读缓存,后读从库
这是我一开始提出的一个方法,读写缓存,但是面试官的意思是这些数据不是独立的,是可能有复杂查询的,比如某表写入一条数据,读时可能读取包括这条在内的多条数据,甚至可能有多表连接等复杂查询。所以缓存也不现实。 [/quote] 可能她说的不是缓存数据,而是缓存事务信息吧 创建一个全局事务版本信息,主库缓存写事务快照信息,从库在读取时根据缓存的快照决定是否堵塞等待数据复制完毕 不然数据还没复制到从库的话,你怎么折腾也没用 当然有些查询是不需要获取最新数据的,部分查询可以不用等待同步[/quote] 这是一个解决方法,不过不明白如何缓存事务快照,还有就是我的第三个反应的问题,这样做是否会大大影响性能,一个是每个访问先要读缓存,一个是读取缓存后处理事务快照应该也是程序实现的吧,这些开销在高并发下不会小。
benluobo 2015-04-01
  • 打赏
  • 举报
回复
需要实时性的直接去主库上查 不需要实时性的去从库上上查 如果真要保证读从写主,中间同步啥耗费的时间还不如直接从主库读
  • 打赏
  • 举报
回复
SL模式只听过,没接触过…… 我听过新蛋的做法,当然新蛋用的是mssql 它们的做法是:跟新主库的同事,在一个公共库里面插入更新时间戳,同步程序更新完后,更新读库的时间戳,读数据时同时从公共库和读库两个地方读数据,如果发现两边时间戳不一致,就从主库读数据,否则从读库读数据
zapdos 2015-04-01
  • 打赏
  • 举报
回复
引用 4 楼 jzh2004 的回复:
[quote=引用 3 楼 benluobobo 的回复:] 后台mysql主从复制 在主从复制前面搭建缓存即可 先写缓存,后写主库 先读缓存,后读从库
这是我一开始提出的一个方法,读写缓存,但是面试官的意思是这些数据不是独立的,是可能有复杂查询的,比如某表写入一条数据,读时可能读取包括这条在内的多条数据,甚至可能有多表连接等复杂查询。所以缓存也不现实。 [/quote] 可能她说的不是缓存数据,而是缓存事务信息吧 创建一个全局事务版本信息,主库缓存写事务快照信息,从库在读取时根据缓存的快照决定是否堵塞等待数据复制完毕 不然数据还没复制到从库的话,你怎么折腾也没用 当然有些查询是不需要获取最新数据的,部分查询可以不用等待同步
沪php攻城师 2015-04-01
  • 打赏
  • 举报
回复
引用 3 楼 benluobobo 的回复:
后台mysql主从复制 在主从复制前面搭建缓存即可 先写缓存,后写主库 先读缓存,后读从库
这是我一开始提出的一个方法,读写缓存,但是面试官的意思是这些数据不是独立的,是可能有复杂查询的,比如某表写入一条数据,读时可能读取包括这条在内的多条数据,甚至可能有多表连接等复杂查询。所以缓存也不现实。
沪php攻城师 2015-04-01
  • 打赏
  • 举报
回复
引用 15 楼 zapdos 的回复:
[quote=引用 14 楼 jzh2004 的回复:] [quote=引用 13 楼 zapdos 的回复:] [quote=引用 8 楼 jzh2004 的回复:] [quote=引用 5 楼 zapdos 的回复:] [quote=引用 4 楼 jzh2004 的回复:] [quote=引用 3 楼 benluobobo 的回复:] 后台mysql主从复制 在主从复制前面搭建缓存即可 先写缓存,后写主库 先读缓存,后读从库
这是我一开始提出的一个方法,读写缓存,但是面试官的意思是这些数据不是独立的,是可能有复杂查询的,比如某表写入一条数据,读时可能读取包括这条在内的多条数据,甚至可能有多表连接等复杂查询。所以缓存也不现实。 [/quote] 可能她说的不是缓存数据,而是缓存事务信息吧 创建一个全局事务版本信息,主库缓存写事务快照信息,从库在读取时根据缓存的快照决定是否堵塞等待数据复制完毕 不然数据还没复制到从库的话,你怎么折腾也没用 当然有些查询是不需要获取最新数据的,部分查询可以不用等待同步[/quote] 这是一个解决方法,不过不明白如何缓存事务快照,还有就是我的第三个反应的问题,这样做是否会大大影响性能,一个是每个访问先要读缓存,一个是读取缓存后处理事务快照应该也是程序实现的吧,这些开销在高并发下不会小。 [/quote] postgres-xc分布式数据库就是用这个全局事务管理来控制数据版本的,可以参考一下 首先写节点只要把缓存放本地,或者用zookeeper处理了 读节点可以横向扩展,所以高并发的压力可以横向扩展解决,读取缓存的性能开销可以由读节点负责 postgres-xc的数据是多版本的,事务快照存储的是进行中的事务ID和提交完的事务ID等信息,读节点可以根据这个去处理本地数据版本不一致的问题,如果有新的数据提交上来的话可以等待同步,如果事务未处理完可以用旧版本数据,并且读节点一般不加写锁,所以高并发下不会堵塞,只有等待同步的时候才会有所停顿 这种改动不需要用户改变逻辑,而是数据库层面的处理[/quote] 不改变程序逻辑这个很好,这个分布式数据库不错,不过这个应该不是MYSQL的,需要换数据库? 这应该是一个很好的解决方案,虽然我到现在没想明白他们的业务需求是什么。[/quote] 我只是说说我的思路,POSTGRES-XC是多主节点的,跟你这个情况还不太一样 根据需求来修改源码,很多公司都这样做的,不过MYSQL也没有实现真正的MVCC,所以也很难根据这个思路去修改,倒是可以在POSTGRES上进行扩展试试 我建议你打电话回去问问他们这个怎么搞,然后再回来告诉我们 [/quote] 当时问过为什么有这种需求的,也没有回答,再打也没有意思了,只能说面试的方式有问题,需求场景不讲明,就定死要一个问题的解决方法,碰到这种需求极端的情况,完全莫名其妙了。 其实如果把场景讲明白,为什么要做这种需求都说清,别人说不定能提供不同的解决思路,比如换一种数据库系统,比如从设计上避免。。。
zapdos 2015-04-01
  • 打赏
  • 举报
回复
引用 14 楼 jzh2004 的回复:
[quote=引用 13 楼 zapdos 的回复:] [quote=引用 8 楼 jzh2004 的回复:] [quote=引用 5 楼 zapdos 的回复:] [quote=引用 4 楼 jzh2004 的回复:] [quote=引用 3 楼 benluobobo 的回复:] 后台mysql主从复制 在主从复制前面搭建缓存即可 先写缓存,后写主库 先读缓存,后读从库
这是我一开始提出的一个方法,读写缓存,但是面试官的意思是这些数据不是独立的,是可能有复杂查询的,比如某表写入一条数据,读时可能读取包括这条在内的多条数据,甚至可能有多表连接等复杂查询。所以缓存也不现实。 [/quote] 可能她说的不是缓存数据,而是缓存事务信息吧 创建一个全局事务版本信息,主库缓存写事务快照信息,从库在读取时根据缓存的快照决定是否堵塞等待数据复制完毕 不然数据还没复制到从库的话,你怎么折腾也没用 当然有些查询是不需要获取最新数据的,部分查询可以不用等待同步[/quote] 这是一个解决方法,不过不明白如何缓存事务快照,还有就是我的第三个反应的问题,这样做是否会大大影响性能,一个是每个访问先要读缓存,一个是读取缓存后处理事务快照应该也是程序实现的吧,这些开销在高并发下不会小。 [/quote] postgres-xc分布式数据库就是用这个全局事务管理来控制数据版本的,可以参考一下 首先写节点只要把缓存放本地,或者用zookeeper处理了 读节点可以横向扩展,所以高并发的压力可以横向扩展解决,读取缓存的性能开销可以由读节点负责 postgres-xc的数据是多版本的,事务快照存储的是进行中的事务ID和提交完的事务ID等信息,读节点可以根据这个去处理本地数据版本不一致的问题,如果有新的数据提交上来的话可以等待同步,如果事务未处理完可以用旧版本数据,并且读节点一般不加写锁,所以高并发下不会堵塞,只有等待同步的时候才会有所停顿 这种改动不需要用户改变逻辑,而是数据库层面的处理[/quote] 不改变程序逻辑这个很好,这个分布式数据库不错,不过这个应该不是MYSQL的,需要换数据库? 这应该是一个很好的解决方案,虽然我到现在没想明白他们的业务需求是什么。[/quote] 我只是说说我的思路,POSTGRES-XC是多主节点的,跟你这个情况还不太一样 根据需求来修改源码,很多公司都这样做的,不过MYSQL也没有实现真正的MVCC,所以也很难根据这个思路去修改,倒是可以在POSTGRES上进行扩展试试 我建议你打电话回去问问他们这个怎么搞,然后再回来告诉我们
沪php攻城师 2015-04-01
  • 打赏
  • 举报
回复
引用 13 楼 zapdos 的回复:
[quote=引用 8 楼 jzh2004 的回复:] [quote=引用 5 楼 zapdos 的回复:] [quote=引用 4 楼 jzh2004 的回复:] [quote=引用 3 楼 benluobobo 的回复:] 后台mysql主从复制 在主从复制前面搭建缓存即可 先写缓存,后写主库 先读缓存,后读从库
这是我一开始提出的一个方法,读写缓存,但是面试官的意思是这些数据不是独立的,是可能有复杂查询的,比如某表写入一条数据,读时可能读取包括这条在内的多条数据,甚至可能有多表连接等复杂查询。所以缓存也不现实。 [/quote] 可能她说的不是缓存数据,而是缓存事务信息吧 创建一个全局事务版本信息,主库缓存写事务快照信息,从库在读取时根据缓存的快照决定是否堵塞等待数据复制完毕 不然数据还没复制到从库的话,你怎么折腾也没用 当然有些查询是不需要获取最新数据的,部分查询可以不用等待同步[/quote] 这是一个解决方法,不过不明白如何缓存事务快照,还有就是我的第三个反应的问题,这样做是否会大大影响性能,一个是每个访问先要读缓存,一个是读取缓存后处理事务快照应该也是程序实现的吧,这些开销在高并发下不会小。 [/quote] postgres-xc分布式数据库就是用这个全局事务管理来控制数据版本的,可以参考一下 首先写节点只要把缓存放本地,或者用zookeeper处理了 读节点可以横向扩展,所以高并发的压力可以横向扩展解决,读取缓存的性能开销可以由读节点负责 postgres-xc的数据是多版本的,事务快照存储的是进行中的事务ID和提交完的事务ID等信息,读节点可以根据这个去处理本地数据版本不一致的问题,如果有新的数据提交上来的话可以等待同步,如果事务未处理完可以用旧版本数据,并且读节点一般不加写锁,所以高并发下不会堵塞,只有等待同步的时候才会有所停顿 这种改动不需要用户改变逻辑,而是数据库层面的处理[/quote] 不改变程序逻辑这个很好,这个分布式数据库不错,不过这个应该不是MYSQL的,需要换数据库? 这应该是一个很好的解决方案,虽然我到现在没想明白他们的业务需求是什么。
benluobo 2015-03-31
  • 打赏
  • 举报
回复
后台mysql主从复制 在主从复制前面搭建缓存即可 先写缓存,后写主库 先读缓存,后读从库
沪php攻城师 2015-03-31
  • 打赏
  • 举报
回复
引用 1 楼 An342647823 的回复:
在高并发的情况,从库马上实时的从主库获得数据。必然给主库造成很大的压力。 实际业务中生产库不容许你这么干。 个人觉得从数据的来源处做文章,把生产数据往消息队列中塞。 这样消费者去订阅同一个topic,从库和主库获得的数据时间基本就 一致了。
你这个想法和我的第一反应差不多,从业务逻辑上进行处理。不过人家不要这样的解决方法,就是要主从实时一致这种类似事务的解决方法啊。
forever_ai 2015-03-31
  • 打赏
  • 举报
回复
在高并发的情况,从库马上实时的从主库获得数据。必然给主库造成很大的压力。 实际业务中生产库不容许你这么干。 个人觉得从数据的来源处做文章,把生产数据往消息队列中塞。 这样消费者去订阅同一个topic,从库和主库获得的数据时间基本就 一致了。

662

社区成员

发帖
与我相关
我的任务
社区描述
提出问题
其他 技术论坛(原bbs)
社区管理员
  • community_281
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧