假设当前的场景是这样的,用户量会很大,有一个注册接口,用户在注册时会输入一系列信息,好比用户名(主要想表示它为冷数据)等等。要求:1.能承受必定的并发访问。2.即便是并发调用,要必需要保证用户名不能重复。3.单次注册耗时尽量短。只考虑单个mysql,单个redis。mysql
第一个想到的是,为了使得系统承受必定的并发,那么须要在注册接口进行限流,而限流算法就再也不这里赘述了。redis
那么,可能有这么些解决方案:算法
1. 利用redis set结构来进行存在性判断。优势:速度快,无需进行额外的并发控制。缺点:因为认为用户名为冷数据,浪费了大量内存。sql
2. 利用redis boolFilter结构来进行存在性判断。优势:速度快,无需进行额外的并发控制,占用内存较小。缺点:因为用户量很大,若是只使用较小的内存,那么极可能会存在不少误判。并发
3. 直接使用mysql。优势:速度较快,无需进行额外的并发控制,不占用内存。优化
如今来考虑如何来mysql这一层,用户名通常存在于用户表中,而因为用户量会很大,那么一定涉及分表,但通常用户表的水平拆分依靠的变量为用户id,好比分为10张,那么用户id%10,方便查询用户id时能够锁定到某张表,或者某个区间。那么这跟用户名是不要紧的,也就是说,当咱们要判断一个用户是否存在,依然要遍历全部表才能获得结果,而此时,假设咱们有在用户表中,对用户名(对应Java String类型)创建了索引,它依然是很耗时的。索引
再次确认需求,存在性判断。接口
一样是分表,那能不能依靠用户名来分呢?原来的依靠用户id来分也确实是有它的须要的,那么咱们能够把用户名作成一张大表(将它冗余出来),如今对这张用户名大表来拆分。那么怎样分才能使得咱们在获得一个用户名时能够锁定到某张或者某个区间呢?这里不难想到使用hash,也就是每一个用户名都会对应着一个hash值,参照用户表的拆分,咱们也能够简单地hash值%10,固然也可使用别的策略。总之,如今当用户注册时,输入用户名,能够对它进行计算获得一个hash值,最后锁定到某张表,只需遍历那张表就能够知道答案,从速度上来讲,这相比以前要遍历全部表要快不少。内存
再考虑单张表遍历的优化。咱们能够再利用一下hash值,假设这个hash值的字节数大小为8,咱们在用户名表上,增长一列字段名为hash,意为用户名的hash值,咱们对其创建索引,那么咱们在判断时,遍历的就是索引key为bigint的 B+树,数字的比较确定要比字符串的比较快。固然,一样可能会存在误判,这能够依据用户量适当调整hash值字节数大小,理论上,字节数越大,hash冲突越低。字符串
再次确认需求,存在性判断。
set结构能够O(1)时间判断存在。当前咱们是O(logn)地遍历B+树,等值判断,那么天然就想到了hash索引。遗憾的是,在innodb引擎下,咱们做为用户,是没法创建hash索引。因此,这里可能会想到使用别的引擎。但其实,innodb在优化的时候,会创建自适应hash索引,因此,咱们能够认为最后也是会创建hash索引。那既然会创建hash索引,那是否是用户名表就用不着这个hash值,直接对用户名这个字符串创建索引就行了,反正最后会被优化成hash索引。但优化老是不稳定的,我以为仍是创建的好。(惟一索引,这样就不会重复了)
须要说明的是,以上尚未通过验证,只是分享一下这些想法!