一、总体介绍
随着公司不断的业务探索和实践,中台逐步完成了多项通用业务的沉淀,为后续项目的快速迭代,提供了有力的保障。
二、中台能力
三、设计实现
1、代理层
- 配置加载:加载配置中心对应的应用配置信息
- 访问控制:
- 请求合法校验(参数、应用、权限、黑名单)
- 流量控制
- 监控告警:
- dubbo线程池状态监控
- 请求质量监控(请求量、响应时长、响应异常)
配置中心
通过配置中心,完成应用接入,对后续服务层和数据层提供访问控制。
技术栈
名称 | 作用 | 说明 |
---|---|---|
mongo | 存储配置信息 | json数据方便配置信息扩展 |
redis | 配置信息缓存 | 提高查询效率 |
caffeine | 配置信息本地缓存 | 提高查询效率,降低数据库访问频率 |
threadlocal | 线程内配置信息共享 | 解耦配置信息获取处理逻辑,方便服务层和数据层使用 |
2、数据层
统一封装了不同应用获取数据源操作,包括mongdb、redis、mysql、elasticsearch,支持了以下特性:
a、横向扩展
为了保证中台数据层的高可用性,对不同应用之间数据源进行了横向扩展隔离,避免了不同应用之间的互相影响,也方便了各自数据的维护。同时,也支持不同应用之间公用库,节约成本。
b、动态注册
通过数据源管理中心,动态管理数据源。添加修改前,主动检查配置信息的正确性。
c、懒加载
启动时不主动加载数据源,当有数据源操作时在加载,避免无用数据源创建。
d、热更新
通过redis发布订阅,实时监听数据源变更,自动完成数据源卸载,再次使用时通过懒加载策略加载最新数据源信息。
// 数据源缓存
private static volatile Map<String, Map<String, Object>> MAP = Maps.newHashMap();
/**
* 缓存获取数据源
**/
public <T, R> R getFromCache(DatabaseContext databaseContext, Class<T> tClass, Class<R> rClass, Function<T, R> function) {
String connectName = databaseContext.getConnectName();
Map<String, Object> beanMap = MAP.get(connectName);
String cacheName = databaseContext.getApp() + rClass.getName();
if (MapUtils.isNotEmpty(beanMap) && beanMap.containsKey(cacheName)) {
return (R) beanMap.get(cacheName);
}
// 双检锁缓存查询
synchronized (this) {
beanMap = MAP.get(connectName);
if (MapUtils.isNotEmpty(beanMap) && beanMap.containsKey(cacheName)) {
return (R) beanMap.get(cacheName);
}
if (beanMap == null) {
beanMap = Maps.newHashMap();
}
// spring容器获取数据源
R result = function.apply(getConnectClient(databaseContext, tClass));
beanMap.put(cacheName, result);
MAP.put(connectName, beanMap);
return result;
}
}
/**
* spring容器获取数据源
**/
public <T> T getConnectClient(DatabaseContext databaseContext, Class<T> tClass) {
ApplicationContext context = ApplicationContextHolder.getContext();
String connectName = databaseContext.getConnectName();
ConnectionTypeEnum type;
if (tClass == SuishenRedisTemplate.class) {
type = ConnectionTypeEnum.REDIS;
connectName += "RedisTemplate";
} else if (tClass == DomainDaoSupport.class) {
type = ConnectionTypeEnum.MYSQL;
connectName += "DomainDaoSupport";
} else if (tClass == MongoTemplate.class) {
type = ConnectionTypeEnum.MONGO;
connectName += "MongoTemplate";
} else if (tClass == ElasticsearchTemplate.class) {
type = ConnectionTypeEnum.ELASTICSEARCH;
connectName += "ElasticsearchTemplate";
} else {
throw new BusinessException("类型不支持!");
}
if (context.containsBean(connectName)) {
return (T) ApplicationContextHolder.getBean(connectName);
}
// 数据中心查询数据源
CustomDatabase config = customDatabaseDao.getDatabase(databaseContext.getProject(), databaseContext.getModel(), type);
if (Objects.isNull(config)) {
throw new BusinessException(connectName + "不存在!");
}
DefaultListableBeanFactory autowireCapableBeanFactory = (DefaultListableBeanFactory) context.getAutowireCapableBeanFactory();
AbstractConnectionBuilder builder = ConnectionBuildFactory.getBuilder(type);
// spring容器加载数据源
builder.build(config.convert(), autowireCapableBeanFactory);
return (T) ApplicationContextHolder.getBean(connectName);
}
五、高可用性
- 基于eone容器化的快速部署、动态扩容;
- 多级缓存策略;
- 基于cat、睿象云、钉钉的实时监控告警策略;
- 数据源隔离,支持快速切换;
- 基于dubbo的限流、熔断、服务降级策略。