一.引言

大量 id 场景下经常需要通过 id 进行 AB Test,最常见的就是使用尾号 hash 进行分组,但是由于 id 生成规则以及其他因素,按照尾号分组往往会造成 id 不匀,从而导致 AB Test 效果受影响,所以下文采用 md5 加盐 Hash 的方式,得到更均匀的分组与 AB Test 效果。

二.实现原理

1. id 加盐

id 即为用户 uid 或商品 pid,加盐中盐代表盐值,可以指定为任一质数,id 加盐可以理解:

saltNum: Int + id: String => String 

2.MD5 编码

通过 MD5 编码将上述加盐的 id 进行编码处理,获取加密后的字节形式,md5 包采用 java 自带的:

import java.security.MessageDigestval md5 = MessageDigest.getInstance("MD5")
val encoded = md5.digest(saltNum + id)

3.字节转16进制

将加密后的每个字节转16进制,转换16进制采用 org.apache.commons 自带工具包:

import org.apache.commons.codec.binary.Hexval encodeStr = Hex.encodeHexString(encoded)

也可以直接使用 String 自带的 format 方法实现转换16进制:

val encodeStr = encoded.map("%02x".format(_)).mkString("")

4.16进制转10进制

将16进制数字截取 TopN,然后将16进制转换为10进制

val num = java.lang.Long.parseLong(encodeStr.slice(0, N), 16).toString

直接取 TopN 并通过 parseLong 得到新的 10 进制数字。

5.Hash 获取新分组

通过新的十进制数字取尾号 hash,获取新的分组,上面得到 10 进制数字 num,可以再使用尾号划分,例如对倒数两位取 mod,即可得到 100 个分组,对倒数三位取 mod,即可得到 1000 个分组,依次类推。

6.完整实现

A.MD5 Hash

  def md5Encode(id: String, saltNum: Int, N: Int): String = {val input = saltNum + id // 加盐val md5 = MessageDigest.getInstance("md5")val encoded = md5.digest(input.getBytes) // md5 编码val encodeStr = Hex.encodeHexString(encoded) // 转16进制val num = java.lang.Long.parseLong(encodeStr.slice(0, N), 16).toString // 转10进制val group = num.slice(num.length - 2, num.length).toInt % 100 // hashgroup.toString}

B.Common Hash

  def commonHash(num: String): String = {val group = num.slice(num.length - 2, num.length).toInt % 100 // hashgroup.toString}

三.效果评估

对 uid、pid 重新分组主要是为了提高 AB Test 的置信度,而且涉及到工程实现即每个 id 都需要获取对应的 group,所以下面从:

-> id 分组均匀程度

-> id 分组AB效果程度

-> 分组速度

三个方面进行评估。

1.分组均匀程度

由于 uid、pid 为系统生成,一定程度上不能做到完美的 hash 均分,所以需要重 hash 解决,下面分别使用 MD5 Hash 与 Common Hash 做 id 数的分析,指标: [分组 id 数 - 分组 id 平均数]

绿线为 MD5,红线为 CommonHash,可以看到 MD5 得到的 100 个分组 id 数相对 CommonHash 分组均匀很多,前者 Std 为 1100+,后者 Std 达到 4000+。

2.分组效果均匀程度

分组均分后,还要验证下效果是否一致,如果 id 数相同但是同组的 id 表现差异很大,对 AB Test 也会造成很大影响,这里采用 Pid 的销售额作图,指标: [pid 销售额 - pid 销售额均值]

绿线为 MD5,红线为 CommonHash,可以看到 pid 在 MD5 hash 后整体表现均匀,而原始的 CommonHash 则存在个别组出现极端坏数据的情况,影响 AB Test。

3.分组速度

构造 10000 个 id 模拟 Pid,打印执行时间比较:

    val random = scala.util.Randomval testId = (0 to 10000).map(x => random.nextLong()).toArrayval st = System.currentTimeMillis()testId.foreach(num => {
//      md5Encode(num.toString, saltNum, N)commonHash(num.toString)})println(s"cost: ${System.currentTimeMillis() - st}")

MD5 耗时 220ms / 10000,CommonHash 耗时 45ms / 10000,前者大约是后者的 5 倍,但是均匀到 id 上 0.022 ms  / id 的耗时也是可以接受的,所以耗时虽然比 CommonHash 慢5倍,但是工业场景下也基本不受影响。

四.总结

经过上面的分析,该使用什么分组 AB Test 不用我说了吧。

Scala / Java - 采用 MD5 加盐 实现 id 均匀分组相关推荐

  1. Java使用MD5加盐对密码进行加密处理,附注册和登录加密解密处理

    前言 在开发的时候,有一些敏感信息是不能直接通过明白直接保存到数据库的.最经典的就是密码了.如果直接把密码以明文的形式入库,不仅会泄露用户的隐私,对系统也是极其的不厉,这样做是非常危险的. 那么我们就 ...

  2. java md5加盐与解密_md5加密,md5加盐加密和解密

    packagecom.java.test;importjava.security.MessageDigest;importjava.security.SecureRandom;importjava.u ...

  3. SpringBoot 系列教程(八十五):Spring Boot使用MD5加盐验签Api接口之前后端分离架构设计

    加密算法参考: 浅谈常见的七种加密算法及实现 加密算法参考: 加密算法(DES,AES,RSA,MD5,SHA1,Base64)比较和项目应用 目的: 通过对API接口请求报文签名,后端进行验签处理, ...

  4. md5加密,md5加盐加密和解密

    package com.java.test;import java.security.MessageDigest; import java.security.SecureRandom; import ...

  5. MD5流程以及安全性分析,MD5加盐,MD6,笔记

    版权归其所有论文作者所有. 并没写原始的地址,因为这是我整合的,作者太多,包括我.太匆忙,原作者可以联系我. 简介 MD5适用于数据完整性校验的.将任意长度的字节串(所以是基于底层的二进制串的),映射 ...

  6. MD5加盐加密工具类(可直接使用)

    MD5加盐加密工具类 在我们做项目时,涉及到用户密码,而正常来说数据库中不会直接存储明文的密码,都是加密之后的密码. 密码加密的方式有很多,比如: ① 3DES.AES.DES:使用对称加密算法,可以 ...

  7. 对于AES和RSA算法的结合使用以及MD5加盐注册登录时的密码加密

    RSA和AES结合使用 接上篇的RSA和AES算法加密之后,AES对称算法对数据量大的加密比较快,而RSA公私钥加密的话会影响加密效率,但是AES的加密与解密的密钥是一致的,导致密钥不能外泄,密钥在网 ...

  8. 一文读懂md5,md5有什么用,什么是md5加盐

    md5是一种密码散列函数,在计算机安全领域得到广泛的应用.本文将带大家了解一些md5的知识点,什么是md5,md5有什么用,什么是md5加盐,为什么md5不可逆,为什么md5可能会被解密?帮助大家快速 ...

  9. 【甄选靶场】Vulnhub百个项目渗透——项目四十二:Moria1.1(MD5加盐爆破)

    Vulnhub百个项目渗透 Vulnhub百个项目渗透--项目四十二:Moria1.1(MD5加盐爆破)

最新文章

  1. getDay()显示的是本周的第几天
  2. 使用 C#/.NET Core 实现单体设计模式
  3. 少儿不宜!这个开源项目能自动画出各种尺寸的...
  4. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)
  5. Atomikos 中文说明文档【转】
  6. python 多进程 循环_python 多进程读取同一个循环处理、可以用multiprocessing
  7. WEB前端 基础知识汇总
  8. QML笔记-自定义控件的2种点击方式(推荐第二种)
  9. mysql建用户之后取消drop库权限
  10. Python数据分析库pandas高级接口dt和str的使用
  11. WhereHows 安装
  12. oracle remap语句格式,impdp 中的remap方式
  13. 鼓励参与计算机考试宣传标语,考试宣传标语34句
  14. 赚任务网APP下载站源码/任务网源码/积分墙/网络任务网站源码
  15. Oracle 创建表空间,创建表、数据增删改
  16. 女朋友撒娇让我教她HashMap
  17. 数据中心100G主流应用技术分析
  18. Android 性能优化(62)---存检测、卡顿优化、耗电优化、APK瘦身——详解篇
  19. 预祝kimi在上海夺冠!
  20. 计算机主机漏电,电脑主机箱漏电六大原因和解决方法

热门文章

  1. 简单的压缩图片的方法,压缩图片大小的步骤
  2. fileitem方法_Common-FileUpload框架中的FileItem对象 | 学步园
  3. C#(仿QQ)聊天窗口
  4. 在window的cmd命令行中通过chcp修改代码页--正确显示utf-8字符
  5. 2.Arcgis Engine(Extending Arcobjects)的各组件介绍
  6. SQL 语法里的逻辑判断
  7. 四国军棋之司令强吃大子
  8. 【AdGuard Home】轻松实现全屋去广告与追踪,AdGuard Home助力更安全浏览体验
  9. Linux文件类型(b、c、d、l、s、-)
  10. linux文件的类型有哪些?