您的位置:首页 > 数据库

异步化DAO的设计和实践

2016-03-07 10:14 246 查看
摘要: 目前,公司技术规划要求未来所有的服务要全面实现异步化接口,使得每个服务能达到1万/秒的单机性能。我们知道,在一个服务请求中,可能会调用其他服务,还会使用memcache、kv以及mysql等。目前,大众点评的使用的服务框架、kv和cache框架均有异步化调用的接口,但是唯独缺少异步调用数据库的框架支持。这就意味着,如果业务代码一旦其他的请求都异步化了,但是唯独数据库还是同步的,那么就没有达成完全的异步化。在这种情况下,就要求必须有异步化数据库调用的框架支持。zebra-dao就是在这种情况下开发的。

异步化DAO的设计和实践

1. 背景

目前,公司技术规划要求未来所有的服务要全面实现异步化接口,使得每个服务能达到1万/秒的单机性能。我们知道,在一个服务请求中,可能会调用其他服务,还会使用memcache、kv以及mysql等。目前,大众点评的使用的服务框架、kv和cache框架均有异步化调用的接口,但是唯独缺少异步调用数据库的框架支持。这就意味着,如果业务代码一旦其他的请求都异步化了,但是唯独数据库还是同步的,那么就没有达成完全的异步化。在这种情况下,就要求必须有异步化数据库调用的框架支持。zebra-dao就是在这种情况下开发的。

2. 技术选型

调研了目前所有的异步化方案,考虑到有以下的实现:

业务使用时自己将每一次的dao调用放到异步线程池中去。优点是,不需要架构支持什么。缺点是,因为是业务迁移,迁移的代价比较大。

使用google的async-mysql-connector。优点是:背后实现是基于NIO的方式,性能更高。缺点是,异步的jdbc接口上层没有任何的DAO框架支持,公司业务基本无法使用。

所以,笔者主要考虑到业务的易用性和方便迁移,决定将方案定为在MyBatis-Spring的基础上进行封装,背后实现是线程池的方式。

3. API

zebra-dao目前支持两种方式的异步API:回调和Future接口方式,对于每一个异步接口,必须要有相应的同步方法定义,因为其实所有的异步接口最后还是在线程池中调用的同步接口。

public interface UserMapper {
/**
* Normal synchronization dao method.
*/
public UserEntity findUserById(@Param("userId") int userId);

/**
* Asynchronous callback method. Return void and only one
* callback method required.
*/
public void findUserById(@Param("userId") int userId, AsyncDaoCallback<UserEntity> callback);

/**
* Asynchronous future method. Return future and must have the
* same params as synchronization method.
*/
@TargetMethod(name = "findUserById")
public Future<UserEntity> findUserById1(@Param("userId") int userId);
}

业务如果使用的是回调接口,那么在使用的时候必须定义回调方法,在回调方法中,通常做的是把结果放到服务框架的异步回调方法中,这样才能做到一个服务的全部异步化。在下面的例子的回调方法中,隐去了使用服务异步调用接口的具体实现,仅仅展示如何定义回调方法。

dao.findUserById(1, new AsyncDaoCallback<UserEntity>() {
@Override
public void onSuccess(UserEntity user) {
System.out.println(user);

//another asynchronous invoke in the asynchronous invoke
dao.findUserById(2, new AsyncDaoCallback<UserEntity>() {
@Override
public void onSuccess(UserEntity user) {
System.out.println(user);
}

@Override
public void onException(Exception e) {
}
});

//synchronization invoke in the  asynchronous invoke
UserEntity entity = dao.findUserById(3);
System.out.println(entity);
}

@Override
public void onException(Exception e) {
}
});

对于使用的Future接口,就和使用Future一样,没有额外特别之处。

Future<UserEntity> future = dao.findUserById1(1);
UserEntity user = future.get();
System.out.println(user);

更详细的使用方法,请参考这里

4. 总结

目前,公司的价格服务等一系列的服务使用的这个框架去访问数据库,这些服务也因此实现了异步化。未来,公司会将越来越多的服务使用这个框架。目前,这个框架还额外实现了物理分页的功能。这个功能的API的设计也很多为了兼容已有业务代码考虑的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息