首页
美图
服务
付费
树洞
云主机
推荐
邻居
支付
开发
书单
更多
我的足迹
罗盘时钟
圈小猫
工作打分
给我留言
本站统计
推荐
M商城
欣悦云店
txt阅读器
VPS监控
证书监控
网址导航
在线工具
Search
1
docker和docker-compose一键安装脚本
9,273 阅读
2
采用Prometheus+Grafana 监控H3C交换机状态
8,216 阅读
3
WooCommerce对接第三方支付插件开发
6,532 阅读
4
docker下运行grafana和grafana Image Renderer
5,605 阅读
5
服务器(vps)性能测试脚本汇总
5,382 阅读
大模型
虚拟化
数据库
运维
基础知识
监控预警
数据展示
运维工具
web安全
系统服务
开发
python
php
java
shell
go
项目
博客
电商
工具
娱乐
综合
VPS相关
规范文档
知识总结
经验分享
读书笔记
关于
Search
标签搜索
django
python
支付对接
运维工具
电商平台
Joe主题
docker
wordpress
woocommerce
支付通道
zabbix
蓝鲸智云
运维
grafana
监控
运维知识
typecho
php
mysql
nginx
行云流水
累计撰写
332
篇文章
累计收到
385
条评论
首页
栏目
大模型
虚拟化
数据库
运维
基础知识
监控预警
数据展示
运维工具
web安全
系统服务
开发
python
php
java
shell
go
项目
博客
电商
工具
娱乐
综合
VPS相关
规范文档
知识总结
经验分享
读书笔记
关于
页面
美图
服务
树洞
云主机
邻居
支付
书单
给我留言
本站统计
推荐
M商城
txt阅读器
网址导航
搜索到
1
篇与
的结果
2026-02-27
手机号黑名单库查询逻辑与性能优化分享
在高并发场景下,如何实现毫秒级的手机号黑名单校验?本文将深入剖析一个生产级黑名单系统的核心架构与技术实现。一、总体介绍在短信通道、语音呼叫、风控审核等业务场景中,手机号黑名单校验是一项高频且关键的能力。想象一下,当用户发起呼叫或发送短信时,系统需要在毫秒级时间内判断目标号码是否在黑名单中——这直接关系到业务合规性和用户体验。本文介绍的手机号黑名单库是一个面向运营/风控场景的完整解决方案,具备以下核心特性:双通道架构:Django 管理后台 + Go 高性能 API 服务毫秒级响应:依托 Redis 缓存实现单次查询 < 5ms百万级数据支持:轻松支撑千万级黑名单数据量灵活接入方式:支持单号查询、批量查询(最多 500 个)二、技术要点1. Redis Set 数据结构:空间换时间的极致实践是什么:使用 Redis 的 Set(集合)数据结构存储黑名单手机号,而非传统的 Hash 或 String。为什么这么做:Set 的 SISMEMBER 命令时间复杂度为 O(1),无论数据量多大,查询性能恒定内存占用优化:存储 1000 万个 11 位手机号仅需约 400MB 内存天然去重:Set 自动处理重复号码,简化业务逻辑核心价值:单机 Redis 可支撑 10 万+ QPS 的查询压力,满足绝大多数业务场景。2. 冷热分离架构:PostgreSQL + Redis 双层存储是什么:PostgreSQL 作为持久化存储(冷数据),Redis 作为查询缓存(热数据)。为什么这么做:数据安全:PostgreSQL 保证数据不丢失,支持事务和备份查询性能:Redis 避免频繁访问数据库,减轻 DB 压力水平扩展:Redis 可部署集群模式,支持数据分片核心价值:兼顾数据可靠性和查询性能,实现"写入慢、读取快"的最优解。3. 原子切换机制:零停机数据更新是什么:使用临时 Set + RENAME 命令实现黑名单数据的无缝切换。为什么这么做:避免更新过程中的数据不一致问题切换操作是原子性的,微秒级完成业务层无感知,零停机时间核心价值:支持百万级数据的全量更新,而不影响线上查询服务。4. Pipeline 批量查询:网络延迟优化是什么:使用 Redis Pipeline 技术批量发送查询命令,减少网络往返次数。为什么这么做:单次网络 RTT 约 1-5ms,批量查询可将 500 个号码的查询时间从 2500ms 降至 10ms减少 Redis 服务器处理开销核心价值:批量查询接口支持 500 个号码一次性校验,响应时间 < 50ms。5. 签名验证机制:API 安全防护是什么:基于 MD5 的参数签名验证,防止接口被恶意调用。为什么这么做:防止请求被篡改(如修改查询号码)防止重放攻击(时间戳有效期 5 分钟)身份认证(AppId + AppSecret 模式)核心价值:确保只有授权用户才能访问黑名单查询服务。三、核心代码片段1. Redis 批量查询实现// BatchIsPhoneInBlacklistSet 使用 Pipeline 批量查询号码是否在黑名单中 func BatchIsPhoneInBlacklistSet(phones []string) (map[string]bool, error) { if len(phones) == 0 { return make(map[string]bool), nil } pipe := RedisClient.Pipeline() cmds := make(map[string]*redis.BoolCmd) // 批量发送 SISMEMBER 命令 for _, phone := range phones { cmds[phone] = pipe.SIsMember(ctx, BlacklistSetKey, phone) } // 执行所有命令(一次网络往返) _, err := pipe.Exec(ctx) if err != nil { return nil, err } // 处理结果 results := make(map[string]bool) for phone, cmd := range cmds { isMember, err := cmd.Result() if err != nil { // 单个查询出错,默认不在黑名单 results[phone] = false } else { results[phone] = isMember } } return results, nil }核心逻辑解读:使用 Pipeline 将多个 SISMEMBER 命令打包发送所有查询共享一次网络往返,大幅降低延迟结果逐个解析,单个失败不影响整体2. 原子切换实现// AtomicSwitchBlacklist 原子切换黑名单数据 func AtomicSwitchBlacklist() error { // 检查临时 Set 是否存在 exists, err := RedisClient.Exists(ctx, BlacklistTempSetKey).Result() if err != nil { return err } if exists == 0 { return fmt.Errorf("temporary blacklist set does not exist") } // 原子操作:重命名临时 Set 为主 Set pipe := RedisClient.Pipeline() pipe.Rename(ctx, BlacklistTempSetKey, BlacklistSetKey) pipe.Incr(ctx, BlacklistVersionKey) _, err = pipe.Exec(ctx) return err }核心逻辑解读:RENAME 命令是原子操作,微秒级完成版本号递增,便于追踪数据更新状态切换期间查询不中断,业务零感知3. 签名验证实现// GenerateSignature 生成请求签名 func GenerateSignature(params SignParams) string { // 构建参数字典 paramMap := make(map[string]string) paramMap["appId"] = params.AppId paramMap["callee"] = params.Callee paramMap["level"] = strconv.Itoa(params.Level) paramMap["timestamp"] = params.Timestamp // 按字典序排序(确保签名一致性) keys := make([]string, 0, len(paramMap)) for k := range paramMap { keys = append(keys, k) } sort.Strings(keys) // 拼接签名字符串 var signStr strings.Builder for i, key := range keys { if i > 0 { signStr.WriteString("&") } signStr.WriteString(key) signStr.WriteString("=") signStr.WriteString(paramMap[key]) } signStr.WriteString("&appSecret=") signStr.WriteString(params.AppSecret) // MD5 加密 hash := md5.Sum([]byte(signStr.String())) return hex.EncodeToString(hash[:]) }核心逻辑解读:参数按字典序排序,确保客户端和服务端生成相同签名AppSecret 仅参与签名计算,不传输,防止泄露MD5 算法兼顾安全性和计算性能4. 批量查询接口处理// ProcessBatchCheck 处理批量号码检查请求 func (s *BlacklistService) ProcessBatchCheck(req *models.BatchCheckRequest, clientIP string) (*models.BatchCheckResponse, error) { // 1. 验证 API 密钥和签名 params := map[string]interface{}{ "appId": req.AppId, "callee": req.Callee, "level": req.Level, "timestamp": req.Timestamp, } apiKey, err := s.ValidateAndGetApiKey(req.AppId, req.Sign, params) if err != nil { return &models.BatchCheckResponse{ Code: 405, // 签名验证失败 Msg: "签名验证失败", }, nil } // 2. 检查访问权限(IP 白名单等) allowed, err := database.ValidateAccess(apiKey.CUserId, req.AppId, apiKey.ID, clientIP) if !allowed { return &models.BatchCheckResponse{ Code: 403, Msg: "访问被拒绝", }, nil } // 3. 解析并去重电话号码 phones := strings.Split(req.Callee, ",") uniquePhones := make(map[string]bool) var validPhones []string for _, phone := range phones { phone = strings.TrimSpace(phone) if phone != "" && utils.IsValidPhoneNumber(phone) { if !uniquePhones[phone] { uniquePhones[phone] = true validPhones = append(validPhones, phone) } } } // 4. 限制批量查询数量 if len(validPhones) > 500 { return &models.BatchCheckResponse{ Code: 400, Msg: "批量查询数量不能超过500个", }, nil } // 5. 执行批量查询(Level 1=黑名单, 2=白名单, 3=混合模式) results, hitCount, err := s.checkBatchNumbersWithResults(validPhones) // 6. 记录访问日志和消费记录(异步) s.recordAccessAndConsumption(apiKey, validPhones, hitCount) return &models.BatchCheckResponse{ Code: 200, Msg: "success", Data: results, }, nil }核心逻辑解读:六层校验:签名验证 → 权限检查 → 参数解析 → 数量限制 → 黑名单查询 → 日志记录支持三种查询模式:黑名单、白名单、混合模式异步记录访问日志,不阻塞查询响应四、总结手机号黑名单库的核心设计思想可以概括为:"冷热分离保安全,Redis 缓存保性能,原子切换保稳定,签名验证保安全"。通过本文介绍的技术方案,我们实现了:单次查询延迟 < 5ms批量 500 个号码查询 < 50ms支持千万级黑名单数据零停机数据更新这套方案已在生产环境稳定运行,日均处理查询请求数百万次。希望本文的技术分享能为你的黑名单系统设计提供参考。本文基于 PBlack 手机号黑名单管理系统(Django + Go + Redis + PostgreSQL)生产实践整理。
2026年02月27日
7 阅读
0 评论
0 点赞