当前位置: 首页 > 科技观察

用uid分库,uname上的查询呢?

时间:2023-03-17 12:30:01 科技观察

用户中心几乎是每家公司必不可少的基础服务。用户注册、登录、信息查询和修改都离不开用户中心。当数据量越来越大时,就需要多用户中心进行水平切分。最常见的水平切分方法是根据uid取模来划分数据库:通过uid取模将数据分布到多个数据库实例中,增加服务实例的数量,减少单个数据库的数据量,实现产能扩张的目的。横向切分后:uid属性的查询可以直接路由到库中,如上图,假设访问uid=124的数据,取模后可以直接定位到db-user1。对于uname上的查询,不能这么幸运:uname上的查询,如上图,假设要访问uname=shenjian的数据,因为你不知道数据落在哪个数据库上,你经常需要遍历所有数据库(sweepthewholedatabasemethod),当分库数量增加时,性能会明显下降。使用uid分库,如何高效实现在线查询是本文要探讨的问题。方案一:索引表法思路:uid可以直接定位到库,uname不能直接定位到库。如果可以通过uname查询到uid,问题就解决了。解决方法:(1)建立索引表,记录uname到uid的映射关系;(2)使用uname访问时,先通过索引表查询uid,然后定位到对应的库;(3)索引表属性少,可以容纳大量数据,一般不需要分库;(4)如果数据量太大,可以使用uname分库;潜在缺点:多一次数据库查询,性能会翻倍。方案二:缓存映射方式的思路:访问索引表性能低,把映射关系放在缓存中性能更好。解决方法:(1)uname查询先查询缓存中的uid,再根据uid定位数据库;(2)假设cachemiss,使用扫描全库的方法获取uname对应的uid,放入缓存;(3)从uname到uid的映射关系不会改变。映射关系一旦放入缓存,就不会改变,不需要淘汰,缓存命中率非常高;(4)如果数据量太大,可以按名称拆分缓存层级;潜在不足:多了一个缓存查询。方案三:uname生成uid思路:不用远程查询,uname直接获取uid。解决方法:(1)用户注册时,设计函数uname生成uid,uid=f(uname),根据uid分库插入数据;(2)使用uname访问时,先通过函数计算uid,即再次uid=f(uname),从uid路由到对应的库;潜在不足:该功能的设计需要非常巧妙,存在uid生成冲突的风险。方案四:遗传法,uname基因整合到uid思路:不能用uname生成uid,但是可以从uname中提取“基因”,整合到uid中。假设有8个数据库,使用uid%8路由,潜台词就是uid的后3位决定了这条数据落在哪个数据库上。这3位就是所谓的“基因”。解决方案:(1)用户注册时,设计函数uname生成一个3位基因,uname_gene=f(uname),如上图粉红色部分;(2)同时生成一个61位的全局唯一id作为用户的标识,如上图部分绿色所示;(3)然后使用3bit的uname_gene作为uid的一部分,如上图黄色部分;(4)生成一个64bit的uid,由id和uname_gene拼装而成,根据uid分库插入数据;(5)使用uname访问时,先通过函数从uname中恢复3bit基因,uname_gene=f(uname),直接通过uname_gene%8定位到文库;总结业务场景:用户中心,数据量大,通过uid分库后,通过uname分库无法路由。解决方法:(1)扫描全库法:遍历所有库;(2)索引表法:记录数据库中uname到uid的映射关系;(3)缓存映射法:记录缓存中uname到uid的映射关系;(4)uname生成uid;(5)遗传法:将uname基因整合到uid中;【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文