精准推送服务系统架构设计
目录
1.功能应用场景与需求分析
1.应用场景
2.需求分析
3.服务架构
2.升级计划
1. 2.0计划
2. 3.0架构升级计划
3.接口设计
1.类图
2.工厂设计模式
3.适配器设计模式
4.表结构设计
1.表结构分析
2.表结构设计
1.功能应用场景与需求分析
1.应用场景
项目需要对接各广告平台OCPX接口,同时需要记录媒体平台请求信息和客户归因信息,服务用作中间代理,负责双方接口对接,需要对各平台请求参数进行转换与处理
2.需求分析
1.对各广告平台和客户提供统一的请求接口,通过本服务配置的链路编码进行区分
2.异步存储平台和客户的请求数据,redis缓存回调,保证服务性能
3.表结构拆分位常用字段和不常用字段分开存储
3.服务架构
版本:1.0.0
UML时序图更新
2.升级计划
1. 2.0计划
由于需要RTA和OCPX两种类型接口,同时链路服务又可以共用,于是将服务分为一下四个服务
ocpx服务:
处理ocpx类型服务业务
rta服务:
处理rta类型服务业务(QPS较高,和OCPX分开部署)
公共服务:
处理链路信息和可公用服务
链路服务:
处理每个链路服务信息
2. 3.0架构升级计划
在原有服务基础上添加数据转换服务,在不更改OCPX服务的情况下添加新的链路转换功能。
持续更新中...
3.接口设计
1.类图
2.工厂设计模式
说明:
通过工厂模式生产出具体服务实现接口,实现类统一实现接口,每一个实现类实现不同的业务逻辑,在逻辑中区分出媒体平台和上游客户服务,为进一步使用对象适配器模式做准备
媒体平台控制器如下
package com.hhmt.delivery.controller;import com.hhmt.delivery.entity.BaseMediaDto;
import com.hhmt.delivery.ocpx.service.factory.OcpxMediaServiceFactory;
import com.hhmt.delivery.ocpx.service.media.MediaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** 辉煌明天* FileName: OcpxMediaController* Author: huachun* email: huachun_w@163.com* Date: 2021/12/7 10:42* Description: 腾讯广点通OCPX接口*/
@RestController(value = "媒体对接接口")
@RequestMapping(value = "/v2/ocpx/media", name = "ocpx媒体访问控制")
public class OcpxMediaController {@Autowiredprivate OcpxMediaServiceFactory ocpxMediaServiceFac;@GetMapping(value = "/{code}/click", name = "媒体上报")public <T> T mediaClick(BaseMediaDto mediaDto, @PathVariable("code") String code) {MediaService mediaService = ocpxMediaServiceFac.mediaService(code);return mediaService.clickReportCustomer(mediaDto, code);}
}
代码分析:
在控制层引入工厂类,通过请求中的路径参数code调用工厂类的mediaService(code)方法生产出具体的业务逻辑处理实现类,进一步处理业务。
媒体服务工厂类,用来生产具体媒体实现对象
package com.hhmt.delivery.ocpx.service.factory.impl;import com.hhmt.delivery.continer.ErrorCode;
import com.hhmt.delivery.ocpx.container.ChainConstant;
import com.hhmt.delivery.ocpx.service.factory.OcpxMediaServiceFactory;
import com.hhmt.delivery.ocpx.service.media.MediaService;
import com.hhmt.delivery.utils.exception.ServiceCustomerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.Objects;/*** 辉煌明天* FileName: OcpxMediaServiceFactory* Author: huachun* email: huachun_w@163.com* Date: 2022/1/12 14:45* Description:*/
@Service
public class OcpxMediaServiceFactoryImpl implements OcpxMediaServiceFactory {private static final Logger LOGGER = LoggerFactory.getLogger(OcpxMediaServiceFactoryImpl.class);/*** @Description: 以下为媒体服务实现类* @Author: huachun* @Date: 2021/12/13 11:23* @return: null**/@Resource(name = "tsaMediaService")private MediaService tsaMediaService;@Resource(name = "hwAdsMediaService")private MediaService hwAdsMediaService;@Resource(name = "headLineMediaService")private MediaService headLineMediaService;@Resource(name = "aiqiyMediaService")private MediaService aiqiyMediaService;@Resource(name = "qutoutiaoMediaService")private MediaService qutoutiaoMediaService;@Resource(name = "aliHuiChuanMediaService")private MediaService aliHuiChuanMediaService;@Resource(name = "oppoMediaService")private MediaService oppoMediaService;@Resource(name = "cooTekMediaService")private MediaService cooTekMediaService;@Resource(name = "baiDuMediaService")private MediaService baiDuMediaService;@Resource(name = "quickWorkerMediaService")private MediaService quickWorkerMediaService;/*** @Description: 生产具体的数据转换服务类* @Author: huachun* @Date: 2021/12/7 11:41* @return: com.hhmt.delivery.ocpx.service.MediaCovertService**/@Overridepublic MediaService mediaService(String chain) {String logBy = this.getClass().getName() + ".mediaService:{}";switch (Objects.requireNonNull(ChainConstant.getMediaCode(chain))) {case TENCENT_SOCIAL_ADS:return tsaMediaService;case HUAWEI_ADS:return hwAdsMediaService;case HEADLINE:return headLineMediaService;case AIQIY:return aiqiyMediaService;case QUTOUTIAO:return qutoutiaoMediaService;case ALI_HUICHUAN:return aliHuiChuanMediaService;case OPPO:return oppoMediaService;case COOTEK:return cooTekMediaService;case BAIDU:return baiDuMediaService;case QUICK_WORKER:return quickWorkerMediaService;default:LOGGER.error(logBy, ErrorCode.CHAIN_CODE_ERROR.getMsg());throw new ServiceCustomerException(ErrorCode.CHAIN_CODE_ERROR);}}
}
通过链路参数返回具体的业务逻辑处理实现类,实现类都实现了响应接口,媒体广告平台实现媒体接口,客户实现客户接口
具体的业务实现就不做过多的展示了...
3.适配器设计模式
说明:
由于多个平台需要上报同一个客户接口,一客户也需要回调多个平台服务,所以将服务接口抽离出来做成通用接口。
业务逻辑:左边为平台上报,右边为客户回调
通过业务逻辑分析请求接口后需要有两个操作
1.转换数据
将平台请求数据转换为上报客户的请求参数,这里面包含了核心的业务逻辑
2.发送请求
携带请求数据请求客户上报接口
接口定义:
1.统一请求对象和响应
媒体服务请求客户的接口需要封装各个客户请求数据
package com.hhmt.delivery.ocpx.service.media;import com.hhmt.delivery.ocpx.bean.customer.to.KoalaTo;
import com.hhmt.delivery.ocpx.bean.customer.to.MeiTuanNetWorkTo;
import com.hhmt.delivery.ocpx.bean.customer.to.MeiTuanYxTo;
import com.hhmt.delivery.ocpx.bean.customer.to.TaoBaoTo;
import com.hhmt.delivery.ocpx.bean.customer.vo.KoalaVo;
import com.hhmt.delivery.ocpx.bean.customer.vo.MeiTuanNetWorkVo;
import com.hhmt.delivery.ocpx.bean.customer.vo.MeituanYxVo;
import com.hhmt.delivery.ocpx.bean.customer.vo.TaoBaoVo;/*** 辉煌明天* FileName: MediaReqService* Author: huachun* email: huachun_w@163.com* Date: 2021/12/13 18:07* Description:*/
public interface MediaReqService {KoalaVo reqKoala(KoalaTo koalaTo);MeituanYxVo reqMeiTuanYx(MeiTuanYxTo meiTuanYxTo);MeiTuanNetWorkVo reqMeiTuanNetWork(MeiTuanNetWorkTo meiTuanNetWorkTo);TaoBaoVo reqTaoBao(TaoBaoTo taoBaoTo);}
媒体目标请求方法clickReportCustomer,由于业务需要转换数据,所以我把转换数据这一步放在了一起,也可以单独抽离出来
package com.hhmt.delivery.ocpx.service.media;import com.hhmt.delivery.ocpx.bean.customer.to.KoalaTo;
import com.hhmt.delivery.ocpx.bean.customer.to.MeiTuanNetWorkTo;
import com.hhmt.delivery.ocpx.bean.customer.to.MeiTuanYxTo;
import com.hhmt.delivery.ocpx.bean.customer.to.TaoBaoTo;import java.util.Map;/*** 辉煌明天* FileName: MediaCovertService* Author: huachun* email: huachun_w@163.com* Date: 2021/12/7 11:24* Description: 媒体平台数据转换服务*/
public interface MediaService {<T> T clickReportCustomer(Map<String, String> mediaDto, String code);MeiTuanNetWorkTo covertMtNetWorkData(Map<String, String> mediaDto, String realKey);KoalaTo covertKoalaData(Map<String, String> mediaDto, String realKey);MeiTuanYxTo covertMeituanYxData(Map<String, String> mediaDto, String realKey);TaoBaoTo covertTaoBaoData(Map<String, String> mediaDto, String realKey);}
在具体的服务实现类中可以这样使用
package com.hhmt.delivery.ocpx.service.media.impl;import com.hhmt.delivery.async.OcpxAsyncService;
import com.hhmt.delivery.continer.ErrorCode;
import com.hhmt.delivery.ocpx.bean.customer.to.KoalaTo;
import com.hhmt.delivery.ocpx.bean.customer.to.MeiTuanNetWorkTo;
import com.hhmt.delivery.ocpx.bean.customer.to.MeiTuanYxTo;
import com.hhmt.delivery.ocpx.bean.customer.to.TaoBaoTo;
import com.hhmt.delivery.ocpx.container.ChainConstant;
import com.hhmt.delivery.ocpx.container.KoalaConstant;
import com.hhmt.delivery.ocpx.container.TsaConstant;
import com.hhmt.delivery.ocpx.service.media.MediaCovertService;
import com.hhmt.delivery.ocpx.service.media.MediaReqService;
import com.hhmt.delivery.ocpx.service.media.MediaService;
import com.hhmt.delivery.utils.OcpxUtils;
import com.hhmt.delivery.utils.RedisUtils;
import com.hhmt.delivery.utils.exception.ServiceCustomerException;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;/*** 辉煌明天* FileName: TsaKoalaCovertService* Author: huachun* email: huachun_w@163.com* Date: 2021/12/7 11:27* Description: 腾讯转换考拉请求数据服务实现类*/
@Service
public class TsaMediaService implements MediaService {private static final Logger LOGGER = LoggerFactory.getLogger(TsaMediaService.class);private static final String ANDROID = "android";private static final String IOS = "ios";// redis key失效时间一个半小时private static final Long EXPIRE_TIME = 5400L;@Autowiredprivate RedisUtils redisUtils;@Autowiredprivate OcpxUtils ocpxUtils;@Resource(name = "tsaAsyncService")private OcpxAsyncService tsaAsyncService;@Autowiredprivate MediaReqService mediaReqService;@Autowiredprivate MediaCovertService mediaCovertService;/*** @Description: 媒体点击上报客户* @Author: huachun* @Date: 2021/12/7 15:47* @return: T**/@Overridepublic <T> T clickReportCustomer(Map<String, String> mediaDto, String code) {String logBy = this.getClass().getName() + ".clickReportCustomer:{}";String realKry = "";switch (Objects.requireNonNull(ChainConstant.getCustomerCode(code))) {case KOALA:realKry = ocpxUtils.realKey(ChainConstant.TENCENT_SOCIAL_ADS__KOALA.getCode());KoalaTo koalaTo = covertKoalaData(mediaDto, realKry);tsaAsyncService.saveReqParams(mediaDto, realKry);return (T) mediaReqService.reqKoala(koalaTo);case MEITUAN_NET_WORK:realKry = ocpxUtils.realKey(ChainConstant.TENCENT_SOCIAL_ADS__MEITUAN_NET_WORK.getCode());MeiTuanNetWorkTo meiTuanNetWorkTo = covertMtNetWorkData(mediaDto, realKry);tsaAsyncService.saveReqParams(mediaDto, realKry);return (T) mediaReqService.reqMeiTuanNetWork(meiTuanNetWorkTo);default:LOGGER.error(logBy, ErrorCode.CHAIN_CODE_ERROR.getMsg());throw new ServiceCustomerException(ErrorCode.CHAIN_CODE_ERROR);}}/*** @Description: 腾讯广点通数据转换- 美团网盟请求数据* @Author: huachun* @Date: 2021/12/14 11:44* @return: com.hhmt.delivery.ocpx.bean.customer.to.MeiTuanNetWorkTo**/@Overridepublic MeiTuanNetWorkTo covertMtNetWorkData(Map<String, String> mediaDto, String realKey) {return null;}/*** @Description: 腾讯广点通数据-转换考拉海购请求数据* @Author: huachun* @Date: 2021/12/14 11:43* @return: com.hhmt.delivery.ocpx.bean.customer.to.KoalaTo**/@Overridepublic KoalaTo covertKoalaData(Map<String, String> mediaDto, String realKey) { return null;}@Overridepublic MeiTuanYxTo covertMeituanYxData(Map<String, String> mediaDto, String realKey) {return null;}@Overridepublic TaoBaoTo covertTaoBaoData(Map<String, String> mediaDto, String realKey) {return null;}}
这里删除具体的业务逻辑~
此时在腾讯平台适配考拉海购时就可以通过两个步骤完成操作
1.实现转换考拉海购数据接口
KoalaTo koalaTo = covertKoalaData(mediaDto, realKry);
2.请求考拉海购接口
return (T) mediaReqService.reqKoala(koalaTo);
至此,平台->客户的第一个适配就完成了
由于接口响应需要适配多种实体类型,所以这里使用了泛型定义
4.表结构设计
1.表结构分析
接口文档中有很多参数在实际请求中是空值,但是这部分参数又不能舍弃掉,需要对媒体平台的表字段进行拆分,分为存储常用参数表和不常用参数表
2.表结构设计
说明:
1.以ocpx_m开头的是媒体平台表,用来存储媒体请求数据
2.以ocpx_c开头的表是客户表,用来存储客户回传数据
3.ocpx_media_cb_info是用来异步存放回调信息,方便查询
4.ocpx_m_xxx_fill_info用来存储 xxx平台非必要信息,由于平台字段比较多,很多又是不常用但后期可能会用的,所以用关联表记录
数据库表优化:
1.数据量大
a).通过create_time字段进行分区分表
b).创建常用条件查询字段索引,这里使用rs_id字段,索引规则idx_tb_name_column
2.数据插入校验
创建表字段插入约束
如果大家有更好的建议,欢迎在下方评论区和我留言互动哟!
持续完善中...
精准推送服务系统架构设计相关推荐
- 基于大数据的情报分析与服务系统架构设计
一.大数据在军事领域中的应用 技术作为一项从大量数据中获取有用知识的实用技术,已被广泛应用于各行各业并取得了较大的经济和社会效益,而其在军事领域的应用也具有很大的潜力. 1 提升情报获取能力 现代战 ...
- 微服务系统架构设计系列 - RateLimiter - 1. 限流器简介与一般算法
Key TakeAways 限流器是一种防御性的编程实现方式,防止一个大型的分布式系统在不可预知的大流量到来的时候导致系统大规模故障. 限流器可以设置在服务端,主要为了限制资源的使用.放在客户端主要考 ...
- 如何用 Netty 设计一个百万级推送服务?
1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...
- 基于Netty的百万级推送服务设计要点
1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...
- 【Netty系列】Netty百万级推送服务设计要点
一. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...
- Netty系列之Netty百万级推送服务设计要点
原文来自于:李林峰 https://www.infoq.cn/article/netty-million-level-push-service-design-points/ 1. 背景 1.1. 话题 ...
- Netty百万级推送服务设计要点
1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...
- Netty百万级推送服务设计要点!
来源:urlify.cn/3eAZBj 最近很多同学给我发邮件或者微博私信我,咨询推送服务相关的问题. 问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为如下几类: Net ...
- Netty学习总结(3)——Netty百万级推送服务
1. 背景 1.1. 话题来源 最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题.问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为 ...
最新文章
- 77底盒和86底盒的区别_86型开关底盒的具体参数
- IOS-React-Native:No bundle URL present
- 双网卡上网冲突解决_双网卡冲突解决方法——route命令
- 动态Java代码注入
- React单元测试:Jest + Enzyme(二)
- 7.MongoDB与python交互
- CREAMy简洁大气模板Typecho主题
- Typecho博客支持Emoji表情功能设置
- 模型操作_77个典型岗位员工胜任素质模型操作指导手册
- 2021-04-26 Matlab遗传算法工具箱的使用及实例(线性规划)
- 鞠今日截语2014.05.11火星合月
- 我的RHCE认证考试经历
- 科学计算机已知角度和边长怎样算斜长,等腰三角形斜长计算公式
- ubuntu系统安装教程之启动盘制作
- MATLAB机器人寻找轨迹路线规划源代码
- 2021辽宁正高考试成绩查询,2021考试成绩
- 三维扫描技术的好伙伴-点云处理软件在土方测量中的应用
- 低调做人,高调做事,开发就是这么坑!
- python机器学习 train_test_split()函数用法解析及示例 划分训练集和测试集 以鸢尾数据为例 入门级讲解
- U-Boot的内存分布图
热门文章
- sysmac studio
- 02 css实现文字下划线动画效果
- 国际跆拳道联盟考核制度标准
- android实现抖音列表,Android使用RecyclerView实现抖音主界面
- ts453bmini 内存_为华硕天选游戏本而生:8GB DDR4-3200单条跌至194,补齐内存短板
- C#窗体设计button中的Enable和visible的区别
- DDS(数据分发服务)技术
- 关于无反相机(欢迎大家补充和提出异议)
- 洛谷 P1203 [USACO1.1]坏掉的项链Broken Necklace 动态规划
- 搭建zookeeper服务器集群