当前位置:Gxlcms > 数据库问题 > 数据库读写分离及问题

数据库读写分离及问题

时间:2021-07-01 10:21:17 帮助过:25人阅读

addUserSuccess = userDao.addUser(registUser); if (addUserSuccess) { cachedThreadPool.execute(() -> { EmailService.SendActivateEmail(userId); }); }
public static void SendActivateEmail(int userId) {
    User user = userDao.getUser(userId);
    String userName = user.getUserName();
    String userEmail = user.getUserEmail();
    String subject = "...";
    String body = "...";
    //调用邮件服务发邮件

}
如上,当新用户注册,在注册完成后,会发一封激活邮件,新增用户是insert,发邮件获取用户是select ,如果master slave存在延迟,有可能在这个时候获取不到用户。

情况二

对于分布式服务系统,都会有一些独立的子服务,比如用户服务,订单服务,这些服务通过http或者rpc访问, 如下是用户服务下的两个接口。  userservice.xx.com/user/userinfo       post请求,用户新增或者更新用户 userservice.xx.com/user/userinfo/1    get请求,用于获取用户信息 这是两个接口服务,一个用于更新用户数据,一个用户获取数据,如果手机APP有一个操作是修改用户名,在调用更新用户接口修改用户名后,紧接着调用获取用户信息的接口,两个请求间隔短,而如果同步延迟,就有可能读取到脏数据。 

如何避免

对于上面第一种情况 1. 我们在可以在dao的方法中,再加一个参数,比如:
public User getUser(int userId, boolean isMaster)
业务层决定要在哪个库操作。 2. 根据具体的业务类型,将读写标志位放到线程上下文中。比如对于注册用户的操作,可以在开始处理的时候,在线程上下文中放入一个标志位master,在所有的dao 方法内,判断该标志位,如果是master,则从master读取。这样读写分离是由具体的业务场景决定的。  对于上面第二种情况 1. 简单的方法,就是在请求参数中再加一个参数,服务端根据参数决定要在哪个库操作, 这样增加了前端的一些工作量。 2. 复杂一点的,可以在服务端处理,当修改了用户信息后,可以在redis或者memcache中新增一条Id记录,5秒过期,每次请求的时候,先到memcache中判断一下,对应的id是否存在,如果存在读master, 否则slave。只是这样无形之中增加了服务端的开销。 

总结

其实数据延迟没有那么严重,基本都是秒级的,对于上面第二个场景,可能两个请求来回,数据就已经同步好。不会出现脏读的情况,但是在一些特殊的场景下,比如网络抖动,新加字段,可能数据同步延迟会变大,此时master slave的数据会出现不一致,而如果业务上出现上面的两种情景,即insert/update/delete后立刻select,就有可能读不到或者脏读。所以具体把读写分离放在哪一层,还是要根据业务类型和实际情况来决定。  

数据库读写分离及问题

标签:rpc   subject   proxy   ati   手机   email   类型   cti   简介   

人气教程排行