Python 实现的风控系统(使用了kafka、Faust、模拟drools、redis、分布式数据库)

以下是一个使用 Python 实现的风控系统示例,涵盖以下技术组件:

  1. Kafka 消息中间件:用于实时接收支付业务系统传递的交易数据。
  2. Faust(Kafka Streams 的 Python 等价):用于流式处理 Kafka 中的消息。
  3. 规则引擎:使用 Python 实现简单的规则评估逻辑,模拟 Drools 的功能。
  4. Redis 内存数据库:用于存储风险标签,快速获取账户的风险级别。
  5. 分布式数据库:使用 SQLite 模拟,从中获取风险标签数据(当 Redis 中没有时)。

我们将构建一个简单的风控系统,流程如下:

  • 从 Kafka 中消费实时交易数据。
  • 从 Redis 获取对应的风险标签,如果没有则从分布式数据库获取并更新到 Redis。
  • 使用规则引擎对交易数据和风险标签进行评估。
  • 将评估结果返回给支付业务系统或记录下来。
  实时交易模块:接收交易数据 ------> 获取风险标签(Redis) ------> 调用规则引擎 ------> 评估结果返回
        ↓                                           ↓                          ↑
  规则引擎模块:交易数据 + 风险标签 ---> 规则执行 ----> 输出评估结果(通过/拒绝)

项目结构和依赖

1. 项目结构

risk_control_demo/
├── app.py                      # 主应用程序
├── models.py                   # 数据模型定义
├── rules.py                    # 规则引擎逻辑
├── database.py                 # 数据库服务类
├── redis_service.py            # Redis 服务类
├── requirements.txt            # 项目依赖
└── producer.py                 # Kafka 生产者,发送测试数据
  1. 项目依赖(requirements.txt)

    faust==1.10.4
    redis==4.5.5
    aiokafka==0.7.2
    sqlite3==0.0.1

安装依赖

pip install -r requirements.txt

详细代码

1. models.py(数据模型定义)
# models.py
from dataclasses import dataclass

@dataclass
class Transaction:
    transaction_id: str
    account_id: str
    amount: float
    timestamp: float

@dataclass
class RiskTag:
    account_id: str
    risk_level: int  # 1-低风险, 2-中风险, 3-高风险
2. database.py(数据库服务类)
# database.py
import sqlite3
from models import RiskTag

class DatabaseService:
    def __init__(self):
        # 连接 SQLite 数据库,内存模式
        self.conn = sqlite3.connect(':memory:')
        self.initialize_database()

    def initialize_database(self):
        cursor = self.conn.cursor()
        # 创建风险标签表
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS risk_tags (
                account_id TEXT PRIMARY KEY,
                risk_level INTEGER
            )
        ''')
        # 插入示例数据
        cursor.execute('''
            INSERT INTO risk_tags (account_id, risk_level) VALUES ('account123', 2)
        ''')
        self.conn.commit()

    def get_risk_tag(self, account_id):
        cursor = self.conn.cursor()
        cursor.execute('SELECT risk_level FROM risk_tags WHERE account_id = ?', (account_id,))
        result = cursor.fetchone()
        if result:
            return RiskTag(account_id, result[0])
        else:
            return None

    def close(self):
        self.conn.close()
  1. redis_service.py(Redis 服务类)

    redis_service.py

    import redis
    from models import RiskTag

    class RedisService:
    def init(self, host='localhost', port=6379):
    self.redis_client = redis.Redis(host=host, port=port, decode_responses=True)

     def get_risk_tag(self, account_id):
         risk_level = self.redis_client.get(f'risk:{account_id}')
         if risk_level:
             return RiskTag(account_id, int(risk_level))
         return None
    
     def set_risk_tag(self, risk_tag):
         self.redis_client.set(f'risk:{risk_tag.account_id}', risk_tag.risk_level)
    
     def close(self):
         self.redis_client.close()
    
  2. rules.py(规则引擎逻辑)

    rules.py

    from models import Transaction, RiskTag

    class RiskEvaluator:
    def evaluate(self, transaction: Transaction, risk_tag: RiskTag) -> bool:
    """
    返回 True 表示交易存在风险,需要阻止。
    返回 False 表示交易安全,可以通过。
    """
    # 高风险交易规则
    if transaction.amount > 10000 and risk_tag.risk_level == 3:
    print(f"检测到高风险交易:{transaction}")
    return True # 阻止交易

         # 中风险交易规则
         if 5000 < transaction.amount <= 10000 and risk_tag.risk_level >= 2:
             print(f"检测到中风险交易:{transaction}")
             return True  # 阻止交易
    
         # 低风险交易规则
         print(f"交易通过:{transaction}")
         return False  # 允许交易
    
  3. app.py(主应用程序)

    app.py

    import faust
    import asyncio
    import json
    from models import Transaction, RiskTag
    from database.py import DatabaseService
    from redis_service import RedisService
    from rules import RiskEvaluator

    定义 Faust 应用

    app = faust.App(
    'risk_control_app',
    broker='kafka://localhost:9092',
    value_serializer='raw',
    )

    定义 Kafka 主题

    transaction_topic = app.topic('transaction_topic')

    初始化服务

    redis_service = RedisService()
    database_service = DatabaseService()
    risk_evaluator = RiskEvaluator()

    @app.agent(transaction_topic)
    async def process_transaction(stream):
    async for event in stream:
    try:
    # 解析交易数据
    data = json.loads(event)
    transaction = Transaction(
    transaction_id=data['transaction_id'],
    account_id=data['account_id'],
    amount=data['amount'],
    timestamp=data['timestamp']
    )

             # 从 Redis 获取风险标签
             risk_tag = redis_service.get_risk_tag(transaction.account_id)
             if not risk_tag:
                 # 如果 Redis 中没有,从数据库获取并更新到 Redis
                 risk_tag = database_service.get_risk_tag(transaction.account_id)
                 if risk_tag:
                     redis_service.set_risk_tag(risk_tag)
                 else:
                     # 如果数据库中也没有,设定默认风险标签
                     risk_tag = RiskTag(transaction.account_id, 1)
    
             # 使用规则引擎进行风险评估
             is_risky = risk_evaluator.evaluate(transaction, risk_tag)
    
             # 根据评估结果进行处理
             if is_risky:
                 print(f"交易 {transaction.transaction_id} 存在风险,执行阻止操作")
                 # TODO: 将结果返回给支付业务系统,阻止交易
             else:
                 print(f"交易 {transaction.transaction_id} 安全,允许通过")
                 # TODO: 将结果返回给支付业务系统,允许交易
         except Exception as e:
             print(f"处理交易时发生错误:{e}")
    

    if name == 'main':
    app.main()

注释:

  • 使用 Faust 定义 Kafka Streams 应用程序,处理 transaction_topic 中的消息。
  • process_transaction 函数中,逐条处理交易数据。
  • 从 Redis 获取风险标签,如果没有则从数据库获取并更新到 Redis。
  • 使用自定义的 RiskEvaluator 进行风险评估,根据评估结果执行相应的操作
  1. producer.py(Kafka 生产者,发送测试数据)

    producer.py

    from kafka import KafkaProducer
    import json
    import time

    producer = KafkaProducer(
    bootstrap_servers='localhost:9092',
    value_serializer=lambda v: json.dumps(v).encode('utf-8')
    )

    创建示例交易数据

    transaction_data = {
    'transaction_id': 'tx1001',
    'account_id': 'account123',
    'amount': 12000.0,
    'timestamp': time.time()
    }

    发送交易数据到 Kafka

    producer.send('transaction_topic', transaction_data)
    producer.flush()
    print(f"已发送交易数据:{transaction_data}")
    producer.close()

运行示例

1. 启动必要的服务

注意事项


总结

上述示例提供了一个基本的 Python 程序框架,演示了如何将 Kafka、Faust、Redis、规则引擎和分布式数据库集成在一起,完成实时风控的基本功能。您可以根据具体的业务需求和技术环境,对程序进行扩展和优化。

扩展建议:

  • Redis :确保 Redis 服务在本地的 6379 端口运行

  redis-server

Kafka :确保 Kafka 服务在本地的 9092 端口运行,并创建主题 transaction_topic
*

  # 启动 Zookeeper
  zookeeper-server-start.sh config/zookeeper.properties
  # 启动 Kafka
  kafka-server-start.sh config/server.properties
  # 创建主题
  kafka-topics.sh --create --topic transaction_topic --bootstrap-server localhost:9092

2. 运行应用程序

  • 启动风控系统(app.py):

  python app.py worker -l info

运行 Kafka 生产者,发送交易数据(producer.py):
*

  python producer.py

3. 预期输出

风控系统将处理交易数据,使用规则引擎进行评估,并根据规则打印评估结果。例如:
*

  检测到高风险交易:Transaction(transaction_id='tx1001', account_id='account123', amount=12000.0, timestamp=...)
  交易 tx1001 存在风险,执行阻止操作

说明

  • Faust:Python 的流式处理库,类似于 Kafka Streams,用于处理 Kafka 中的消息流。
  • 规则引擎:使用 Python 自定义规则评估逻辑,模拟 Drools 的功能。
  • Redis:作为缓存,存储风险标签,快速获取账户的风险级别。
  • 分布式数据库(SQLite 模拟):当 Redis 中没有风险标签时,从数据库获取,并更新到 Redis。
  • 风险标签:简单地使用风险级别(1-低风险,2-中风险,3-高风险)来表示。
  • 异常处理:在实际应用中,需要更完善的异常处理机制,防止因异常导致程序崩溃。
  • 引入异步 Redis 客户端 :使用 aioredis 提升 Redis 操作的性能。
  • 使用真正的分布式数据库:替换 SQLite,使用例如 PostgreSQL、MySQL 等数据库,并配置集群模式。
  • 完善规则引擎 :使用现有的 Python 规则引擎库(如 durable_rulesexperta)实现更复杂的规则逻辑。
  • 添加日志和监控 :集成日志系统和监控工具,便于维护和故障排查。
    • 性能优化:对于高并发场景,需要考虑异步 I/O、连接池等技术优化性能。
    • 配置管理:将硬编码的配置(如主机地址、端口、主题名)提取到配置文件或环境变量中,便于管理和修改。
    • 安全性:在生产环境中,注意保护敏感信息,确保数据传输和存储的安全。
相关推荐
永乐春秋9 分钟前
WEB-通用漏洞&SQL注入&CTF&二次&堆叠&DNS带外
数据库·sql
打鱼又晒网42 分钟前
【MySQL】数据库精细化讲解:内置函数知识穿透与深度学习解析
数据库·mysql
大白要努力!1 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
processflow流程图1 小时前
分布式kettle调度平台v6.4.0新功能介绍
分布式
全栈开发圈2 小时前
干货分享|分布式数据科学工具 Xorbits 的使用
分布式
tatasix2 小时前
MySQL UPDATE语句执行链路解析
数据库·mysql
南城花随雪。2 小时前
硬盘(HDD)与固态硬盘(SSD)详细解读
数据库
儿时可乖了2 小时前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
懒是一种态度2 小时前
Golang 调用 mongodb 的函数
数据库·mongodb·golang
天海华兮2 小时前
mysql 去重 补全 取出重复 变量 函数 和存储过程
数据库·mysql