互联网一致性架构实践

同样沈主席分享,分别从如何保证Session一致性、主从、主主一直、缓存一致以及时间问题待分享的冗余数据的一致性、多库事务的一致性、库存扣减的一致性、消息时序的一致性进行讨论。

单机部署必然不会出现保证一致性的系统设计,一致意味着至少大于等于2台服务节点,才有必要考虑双机数据一致的问题。数据多种类型,如上提到的session数据、db集群数据、缓存与db的数据。从具体到抽象,先分别看看各种数据类型在保证一致性方面的经典方式,再通而总之,看看各数据保证一致性是否有通用的设计思路。 

Session一致性

多个web服务,nginx请求分发默认是轮训方式,若用户1访问若web1,而后续访问将请求分发到web2上,则导致web2上无用户session信息,系统提示请重新登录系统。接着web3、web4同理从而导致用户不断重新登入。

那多web节点间如何保证session数据共享且一致呢?

方案一、同步

Tomcat支持session共享的配置,百度一搜N多解决方案,tomcat自带的session共享配置,或是tomcat依赖redis实现session共享配置。

优点:代码0侵入,无需改动任何代码

缺点:若集群扩容不断增加节点,则导致同步实例越来越多,增加扩容成本。

方案二、端

session信息不存到web server上,而是存到端上即浏览器中。这就使得使用同一浏览器进行用户请求到不论哪台web,总能获得用户session信息。

缺点:1、浏览器访问web请求实体将带入更多的session 信息,增大传输数据。

          2、Session数据参与网络传输,需考虑保证数据安全性,防止窃取篡改。

方案三、保证同一用户id落到同一台web,则每次都能拿到用户session(常用)

具体实现:nginx利用uid做哈希取模即可。本方案需考虑uid在web上的分布问题,保证uid取模后,各web承载的uid请求基本持恒,避免出现某几台web高处理量,其他闲置的情况。一般只要uid生成方式均匀(单偶、数据间隔),数据都能保证取模后均匀分布(同db分表原理)

Nginx采用ip做哈希也可以。

方案四、云(常用)

新增一个缓存服务,专门用于存储(uid,session)数据。

优点:充分保证web和server的无状态、透明性,易于扩容操作。

缺点:DB用户info修改,则需考虑缓存与db的同步。

主从一致性 


Mysql主从间同步机制:

通过binlog(按顺序记录主crud操作),从中以单线程记录执行binlog,从而保证从与主数据的一致。

单线程写(串行),如何提高从同步效率?Binlog中记录多个db的执行记录,按照不同db划分,使得matser中db1、db2、db3的binlog按库划分执行,从而提高binlog执行效率。阿里云的数据库同步服务DTS(底层canal)则是将DTS伪装成一个sql slave,基于上述方式,拿到主的binlog快速同步到从中。

写立即读问题:

从经验数据看来,主从间同步有大致500ms的延迟,500ms之内写完立即读,则会出现读不到或读到脏数据问题。

 保证主从一致方式:

方案一、强制读写主库

优点:强制读写均在master上,则不存在读从时,主从数据不一致(binlog执行的时间差)。

缺点:主库的读压力增加,考虑使用缓存减小主库读请求的压力。(实则按下葫芦起了瓢,又需考虑缓存与db的数据一致。这可根据业务实际情况考虑是否适用)

方案二、DBProxy

 

 DBProxy层面控制读落到从库还是主库。具体实现是通过记录500ms内有写请求的key,500ms内对该key有读请求时,则将读请求落到主库上,保证读取最新数据。若无,则落到从库即可。 

主主一致性

主主同步问题:

 

数据同步过程:M1中写入5,在尚未同步到M2之前,M2写入一条新的5,则导致M1 M2分别把自己的5同步给对方,出现主键冲突,M1 M2中各自少了一条记录。

方案一:同步长,不同初始值

M1中分布1357,M2中分布2468,同步长,不同初始值,同步则不会出现上述丢数据问题。

缺点:同一时刻库中数据非全量,扩容非任意时间随时可进行。

方案二、id不采用自增,使用程序生成key做主键
方案三、DNS探测(后续补充) 

缓存一致性


 读流程:

    先读cache,无再读db

    将db中读到数据put进cache,然后返回给service。

写流程:

    写redis、写db

问题1:写redis时,key已存在,是更新还是淘汰?

方法论:如果新的key值能很方便快捷获取到对应value,则直接更新redis即可。如果获取key对应的新value需要耗费多次查询db和内存计算,则直接淘汰掉该key,等待下次重新读取写入即可。一般采用淘汰机制多余更新。

问题2:写的时序性,先写redis还是db?

方法论:由业务场景决定。等同于分布式事务case,商家id关联orderid,与买家id关联orderid的两个索引表,谁先更新,谁后更新。同理

方案一、写db,淘汰redis中对应key,采用schedule定时任务将数据定时写入redis中。

方案二、DTS 监测DB有写入,则同步更新redis。

总结

都是由于冗余而带来的多份冗余服务间同步、一致、读写先后等问题,但因数据类型不同,好像解决方案上各有千秋,笔者未看出如上次分享中高并发-、高可用中均通过扩容、加集群,心跳检测等保证集群间服务可用性探测等通用解决方案。毕竟加机器千篇一率,加完机器后的问题处理思路各有千秋。

ps.如果你看出一致性解决方案的公用处理方法,忘不吝赐教。

猜你喜欢

转载自blog.csdn.net/daybreak1209/article/details/80347744