随着人口红利的慢慢削减,互联网产品的厮杀愈加激烈,大家开始看好下沉市场的潜力,拼多多,趣头条等厂商通过拉新奖励,购物优惠等政策率先抢占用户,壮大起来。其他各厂商也紧随其后,纷纷推出自己产品的极速版,如今日头条极速版,腾讯新闻极速版等,也通过拉新奖励,阅读奖励等政策来吸引用户。

对于这类APP,实时风控是必不可少的,一个比较常见的实时风控场景就是防刷接口作弊。刷接口是黑产的一种作弊手段,APP上的各种操作,一般都会对应后台的某个接口,用户操作APP数据就会通过接口上报到后台,但如果黑产通过破解获取到了APP的新增用户接口,那他们就能跳过登陆APP步骤直接调后台接口构造虚假数据牟利了。对于这类业务,我们可以通过Flink + Redis来实现实时防刷接口的功能。数据流图如下所示:



刷接口作弊一般是越过登陆APP操作,直接调Server端的接口发数据,这些用户在APP的上报日志里面就不存在,那我们可以通过Flink将APP实时上报上来的新增用户写入Redis中,然后Server端将接口上报上来的用户与Redis里的用户进行比对,如果不在Redis里面则判为刷接口用户。

对于这个需求,得要求实时计算引擎能达到毫秒级延迟,否则会造成用户的误判和影响用户体验。为此我们选择了Flink作为实时计算引擎。

主要代码逻辑如下:

//配置flink运行环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
//val env = StreamExecutionEnvironment.createLocalEnvironment()
env.enableCheckpointing(1000 * 60 * 5)
env.getCheckpointConfig.setCheckpointingMode(CheckpointingMode.AT_LEAST_ONCE)
env.getCheckpointConfig.setMinPauseBetweenCheckpoints(1000 * 60 * 3)
env.getCheckpointConfig.setMaxConcurrentCheckpoints(1)
env.setStateBackend(new FsStateBackend(checkPointPath))
env.getConfig.setLatencyTrackingInterval(1000)
env.getConfig.registerTypeWithKryoSerializer(classOf[Log], classOf[ProtobufSerializer])
env.setStreamTimeCharacteristic(EventTime)
env.setParallelism(parallel)
env.getConfig.setLatencyTrackingInterval(1000) //kafka source,实时消费kafka中日志解析出用户id
val stream = env.addSource(new FlinkKafkaConsumer010[Array[Log]](topic, new LogDeserializationSchema(), properties))
val data = stream.flatMap(x => x)
.map(log =>{
val userid = log.getUid.getUuid
val current_time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())
(userid,current_time)
}).filter(record=>{
val userid = record._1
var flag = false
if(userid != null && !"".equals(userid)){
flag = true
}
flag
}) //redis sink,将APP上报日志的用户id写入redis供server端匹配
data.addSink(new RedisSink[(String, String)](getJedisClusterConfig, new RedisSinkMapper))
env.execute("newsinfo_active_userid_to_redis")

其中比较重要的几点:

1 构造kafka source

val stream = env.addSource(new FlinkKafkaConsumer010[Array[Log]](topic, new LogDeserializationSchema(), properties))

一般APP上报的都是序列化的数据,我们需要定义反序列化方法,LogDeserializationSchema 是一个protobuf类型的反序列化方法。

//将kafka中的数据解析为google protobuf 的Log,一个message可能包含多条Log
class LogDeserializationSchema extends AbstractDeserializationSchema[Array[Log]] {
override def deserialize(message: Array[Byte]): Array[Log] = {
val data = ArrayBuffer[Log]()
val input = new ByteArrayInputStream(message)
while (input.available() > 0) {
try {
data += Log.parseDelimitedFrom(input)
} catch {
case _: Throwable =>
}
}
input.close()
data.toArray
}
}

2 redis sink

这里用的是网上开源的flink-connector-redis依赖库。

更多相关内容见:http://bahir.apache.org/docs/flink/current/flink-streaming-redis

Maven依赖如下

<dependency>
<groupId>org.apache.bahir</groupId>
<artifactId>flink-connector-redis_2.11</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>

Redis Sink 提供用于向Redis发送数据的接口的类。接收器可以使用三种不同的方法与不同类型的Redis环境进行通信:

  • 单Redis服务器
  • Redis集群
  • Redis Sentinel

Redis Sink 核心类是 RedisMappe 是一个接口,使用时我们要编写自己的redis操作类实现这个接口中的三个方法,如下所示:

class RedisExampleMapper extends RedisMapper[(String, String)]{
override def getCommandDescription: RedisCommandDescription = {
new RedisCommandDescription(RedisCommand.HSET, "HASH_NAME")
} override def getKeyFromData(data: (String, String)): String = data._1 override def getValueFromData(data: (String, String)): String = data._2
}
val conf = new FlinkJedisPoolConfig.Builder().setHost("127.0.0.1").build()
stream.addSink(new RedisSink[(String, String)](conf, new RedisExampleMapper))

使用RedisCommand设置数据结构类型时和redis结构对应关系。

以上我们利用 Flink + Redis 实时了一个基本的实时防刷接口模型。关注微信公众号《大数据技术进阶》,观看更多大数据实战文章。

Flink实战| Flink+Redis实时防刷接口作弊的更多相关文章

  1. 使用Redis 计数器防止刷接口

    业务需求中经常有需要用到计数器的场景:为了防止恶意刷接口,需要设置一个接口每个IP一分钟.一天等的调用次数阈值:为了降低费用,限制发送短信的次数等.使用Redis的Incr自增命令可以轻松实现以上需求 ...

  2. 使用Redis+自定义注解实现接口防刷

    最近开发了一个功能,需要发送短信验证码鉴权,考虑到短信服务需要收费,因此对此接口做了防刷处理,实现方式主要是Redis+自定义注解(需要导入Redis的相关依赖,完成Redis的相关配置,gs代码,这 ...

  3. spring boot 对某个接口进行次数限制,防刷。简易版。demo。

    一般的项目 如果没有做防刷 容易被人爆接口 或者就是说没有做token防刷过滤. 容易被人用正常的token刷接口.有些token非一次性. 用户登录之后生成token会有一个过期时间,但一般没有做频 ...

  4. spring中实现基于注解实现动态的接口限流防刷

    本文将介绍在spring项目中自定义注解,借助redis实现接口的限流 自定义注解类 import java.lang.annotation.ElementType; import java.lang ...

  5. Flink + 强化学习 搭建实时推荐系统

    如今的推荐系统,对于实时性的要求越来越高,实时推荐的流程大致可以概括为这样: 推荐系统对于用户的请求产生推荐,用户对推荐结果作出反馈 (购买/点击/离开等等),推荐系统再根据用户反馈作出新的推荐.这个 ...

  6. 通过Redis、Memcache的 incr 原子操作防刷机制的使用差别

    我的版本如下: Redis:3.2.100 Memcache:1.4.4 最近在处理服务器压力测试的时候,想到一个方案,在一定时间段内限制用户访问次数.具体的实现就是通过redis的院子操作incre ...

  7. Spring Boot项目的接口防刷

    说明:使用了注解的方式进行对接口防刷的功能,非常高大上,本文章仅供参考 一,技术要点:springboot的基本知识,redis基本操作, 首先是写一个注解类: import java.lang.an ...

  8. Jmeter实时监控+SpringBoot接口性能实战

    性能测试 Jmeter实时监控+SpringBoot接口性能实战 自动化 SpringBoot Java Jmeter实时监控+SpringBoot接口性能实战 一.实验目的及实验环境 1.1.实验目 ...

  9. Spring Boot 项目的 API 接口防刷

    首先是写一个注解类 拦截器中实现 注册到springboot中 在Controller中加入注解 说明:使用了注解的方式进行对接口防刷的功能,非常高大上,本文章仅供参考 一,技术要点:springbo ...

随机推荐

  1. oracle 常用脚本以及语句

    oracle 常用脚本以及语句 一.oracle 安装10G 单机初始化环境: #!/bin/bash #关闭selinuxsed -i 's\SELINUX=enforcing\SELINUX=di ...

  2. iOS渠道追踪统计方法大全

    说起 iOS 的渠道统计,不少人会想到苹果官方的 App 分析功能(iTunes Connect),但实际操作中我们会发现,这个服务的统计维度还不够全面,许多广告主和运营人员更关心的是各个推广渠道实际 ...

  3. Mongodb关于查询返回指定字段的方法记录

    //通常指定字段由前端传入后台,例如params 前端以逗号分隔 //后端获取字段后操作如下: Query query = new Query(); if (params != null) { Str ...

  4. Mybatis源码解析,一步一步从浅入深(一):创建准备工程

    Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...

  5. Django REST Framework序列化器

    Django序列化和json模块的序列化 从数据库中取出数据后,虽然不能直接将queryset和model对象以及datetime类型序列化,但都可以将其转化成可以序列化的类型,再序列化. 功能需求都 ...

  6. [phyton]文件的简单读写练习

    f.open() 用于打开一个文件. f=open("record.txt","w",encoding="utf-8")#打开文件,设置文件 ...

  7. word2vec之tensorflow(skip-gram)实现

    关于word2vec的理解,推荐文章https://www.cnblogs.com/guoyaohua/p/9240336.html 代码参考https://github.com/eecrazy/wo ...

  8. java项目打包

    http://blog.csdn.net/qq_34845382/article/details/53885907 自己用Rinnable JAR file 方法也可以.更简单.直接点击Finish即 ...

  9. j2ee开发之Spring2.5框架学习笔记

    Spring 2.5框架学习笔记 1.是一个开源的控制反转IOC和面向切面AOP的容器框架 2.IOC控制反转 public class PersonServiceBean { private Per ...

  10. Flask基础(07)-->正则自定义转换器

    正则自定义转换器 为什么要自定义正则转换器? 因为默认转换器太过于笨重,往往不能满足我们实际业务的需求,这时候我们就需要自定义正则转换器了. 那么我们怎么自定义正则转换器呢? from flask i ...