@yanglfyangl
2018-05-22T10:07:13.000000Z
字数 2799
阅读 442
- 每个“对前端业务端”的接口的性能都要在平均100ms以下,需要支持批量查询,让业务逻辑能更高效的调用。(目标应该是平均50ms)
- 对于聚合结果部分,不能在“对前端业务端”的调用中进行计算,走异步计算,将计算结果存入。
- Mysql的使用上,只能用主键写入和读取数据库,所有的查询不能用数据库的groupby, join, count, sum 等任何方式。
引擎有很多统计性要求,这些统计型要求如果使用mysql来抗,几乎是不可能的。但对运营或业务来说,统计的实时性又有一定的要求。所以我们也需要进行一定的支持。
基于此,对应的统计方式建议是
将统计方式分为:
- 实时
- 准实时
- 离线
- 非预期
不同的计算方式用不同的技术栈
- 离线部分:主要是指 基于日,周,月的统计和全部数量的计算;由Spark来做。完成后写入历史记录库。
- 准实时部分:每天的统计,走Kafka Streaming或计算中心。
- 实时部分:我们尽量避开
- 难预期部分:我们可以将数据写入HDFS,然后如果需要查询,走Hive.
流程示例:用趣豆花费举例
引擎中有很多调用会涉及到调用第三方,比如
- 融云(注册,发系统消息)
- 短信运营商
- 。。。
调用这些服务最大的问题是时间会很长,很容易造成性能问题,这种情况下的逻辑应该是:
融云创建用户慢的解决方案:
- 提前创建一批融云用户ID和群ID,这样在注册时,就不需要再与融云服务器同步,大大提高速度。
- 当用户注册时,选择一个可用的;
- 同时异步去刷新用户或群状态(头像,名称。。。)
其它的更新操作,全部走“异步,最终一致性”,不轻易使用同步调用。
引擎中有一部分是通过规则来控制流程的。
比如:
一个用户在圈子里购买了什么东西
1. 如果是行为会员,则向圈子里送XXX钱
2. 如果是圈主,则趣币加20%
3. 。。。
这部分我们可以增加一个规则处理中心,这个处理中心通过消息来处理,不要阻塞业务端逻辑
使用规则引擎有如下好处:
1. 规则可以和产品经理一起定义和审核。
2. 规则可以在线不停机修改。(需要一定的工作量)
3. 某种程度上的逻辑变化容易,可维护性高。
也有一些限制
1. 不如写代码灵活。
2. 性能有一定的损失(5%左右)。
3. 调试需要一定的技巧,不太方便。
阿里开源的QLExpress可以做为参考项。
关系尽量走图引擎,这样查询相对容易
创建并加入关系的逻辑走如下模式:
@Translation(...)
bool CreateTopic(){
bool isSucess = true;
try{
TopicService.Save(); //这时候数据库选择需要是关系型的
} catch(error){
isSuccess = false;
}
if(isSuccess){
if(relationEngine.publicTopicToCircle(topicID, circleID)){
rollback();
isSuccess = false;
}
}
return isSucess;
}
我们的场景对于关系的量可能性会比较大,比如:
- 一个圈子里有百W甚至千万的人。
- 一个大V可能会有上千万的粉丝。
- 。。。
需要支持的功能有:
- 快速判断两个ID之间的关系(支持批量判断)
- 快速列举某个范围内的某种关系的列表(比如大V的6w到6w零10个人的列表)
- 支持关系型搜索。
设计思路:
- 关系本身存入KV数据库。
- 为了支持更复杂的查询,一部分最新的数据存入图引擎中。(比如我在圈中好友发的朋友圈。。。)
Kv数据库可选方案
KV数据库Key定义及作用:
Key名 | 格式 | 描述 | 用途 |
---|---|---|---|
Relation_fromID_toID | 固定Value为1 | 用户每加一个关系,增加一条 | 判断两个用户是否有这种关系 |
Relation-List_fromID_toID | ZSet | 用户表,按时间排序 | 某个ID某种关系下的列表 |
伪代码:
RelationType:{
BeFriend,
BeGreenGriend,
...
...
}
bool addRelation(from, to, RelationType){
//
addToKvDB(){
addRelation();
addToList();
}
sendToQueue(){
//队列的接收端执行写入ES操作。
addToTu();
}
}
List<Bool> areTheyFriends(List<id1, id2>){
//如果支持管道,就走管道。
String Key = "BeFriend_" + id1 + "_" + id2;
if(1 == KvDB.getKey(Key)){
如果取出来值为1,则是好
} else {
否则不是好友关系。
}
}
List<String> getSameFriends(fromID, toID){
String Key1 = "BeFriend_List" + fromID
String Key2 = "BeFriend_List" + toID
return sinterstore(key1, key2).get(100); //求交集,只取一定的数量。
}