关于数据库服务器的运维:数据库读写与分离

对于数据存储层高并发问题,最先想到的可能就是读写分离,在网站访问量大并且读写不平均的情况下,将存储分为master,slave两台,所有的写都路由到master上,所有的读都路由到slave上,然后master和slave同步。如果一台salve不够,可以加多台,比如一台master,3台slave。对于什么是读写分离,以及读写分离有什么好处,这里不再叙述,有兴趣的可以参考这里 。

在设计读写分离的时候,有几种解决方案:

    1. 将读写分离放在dao层,在dao层, 所有的insert/update/delete都访问master库,所有的select 都访问salve库,这样对于业务层是透明的。

    2. 将读写分离放在ORM层,比如mybatis可以通过mybatis plus拦截sql语句,所有的insert/update/delete都访问master库,所有的select 都访问salve库,这样对于dao层都是透明。

    3. 放在代理层,比如MySQL-Proxy,这样针对整个应用程序都是透明的。

对于绝大多数情景,读写分离都适用,但是读写分离有一个问题是master slave同步,这个同步是会有一定延迟,因此有几个场景还是要注意的:

场景一

考虑下面一个用户注册场景。

复制代码

boolean 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,就有可能读不到或者脏读。所以具体把读写分离放在哪一层,还是要根据业务类型和实际情况来决定。

转载于:https://www.cnblogs.com/adzz/p/9994137.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值