trie树 mysql_trie树 省内存trie树 URL匹配

业务背景:MySQL数据库中有一份十万左右的域名白名单数据。一般不会变动。

业务需求:查询一个URL的域名是否在白名单中。

业务要求:占用内存小,高效,达到1s几百万。

以下性能测试环境均基于:

内存:16G

CPU:8  Intel(R) Xeon(R) CPU E5-14100 @ 2.80GHz

一、直接查询MySQL

没有做性能调查,但是肯定达不到业务的要求。

二、C++ set容器

将白名单数据全部读入set容器中,占用11M左右内存,内存达到性能要求,但是性能呢?

当时我循环遍历MySQL中的白名单数据进行匹配set容器中的数据,没有做记录模糊记得十万左右的数据大约1s中左右,这还没有考虑待查URL中包含二级、三级域名的情况,所以这种直接哈希也达不到业务的性能要求。

三、trie树

以上两种方法不行我就想到了trie树。trie树也称字典树,其效率很高,利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希表高,但是其高效率是以空间为代价的(起初不觉得会占用多大空间,但是......)。我将白名单数据从后往前存储到trie树中,正好符合域名匹配不要考虑二级域名、三级域名的问题,后面我会做一个优化处理。

借用百度的图片来说明一下trie树:

e1a425446fb2cc2c12ed2e2d0cf27d98.png

trie的基本性质:根节点不包含字符,除根节点外每一个节点都只包含一个字符; 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串; 每个节点的所有子节点包含的字符都不相同。都满足业务要求。

先看一下我初始定义的节点结构体:typedef struct _whitelist_tree_node_ {

uint8_t white_type; //是否是白名单,代表下一步执行的动作

struct _whitelist_tree_node_ *childs[128]; //子节点的指针

} whitelist_tree_node;

我这里在节点中没有定义保存节点值char变量,因为本业务用不到,因root节点不存内容,从root节点开始判断是否含有每个字符‘c’,只需判断该节点的childs[c] 是否等于NULL。white_type是我的一个属性,根据他我就可以不用判断二级、三级域名,在初始化树的时候赋值。他的值我用枚举定义的:

enum {

WHITELIST_UNDONE = 0, //该白名单URL未结束

WHITELIST_CONTINUE, //白名单URL第一个字符,需要继续向前查找

WHITELIST_DONE //匹配白名单,不需继续查

};

写好算法之后,开始测试。初始化之后,我一看占用内存,我擦,我惊呆了了,800M左右,这还了得,赶紧优化。

肯定是childs[128]占用的内存。所以首先考虑域名的合法值,域名的合法字符为 '0-9'、'.'、'-'、'A-z',不区分大小写,这个好,因'-'和'z'区间跨度太大,所以将小写转为大写,降低区间跨度,又因最小值为'-'=45,所以这里操作的下标统一减去45操作。OK,整理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值