• 海量用户使用电子邮箱或者用户名登陆-解决方案


    百度、QQ、360等大公司都拥有上亿的用户量。不仅所有子网站都通过一个账号登录,而且还开放用户平台,提供给其他网站使用。这种级别的数据量和访问量如果不做优化,估计很快就会宕机。这些公司都是一个专门的团队,维护一个注册登录,细节设计的非常优秀。现在粗略谈下他们的设计方案。
    大数据的时候,压力不在PHP,主要在MySQL。
    PHP可以做负载均衡,10台机器抗不住就用20台或者100台,这都不是瓶颈。
    但是MySQL是单点的,无论做多少从库,都是优化查询,更新数据就无法只是简单的通过加机器解决了。
    而且查询也可以通过Memcache缓存减轻压力,所以不必要做多少从库的,一般1主4从就可以了。
    下面主要介绍下数据库的解决方案:
    假设用户可以通过“登录名”、“邮箱”或“手机号”登录。
    表结构如下:
    登录名与ID表,根据login_hash分100张表
    CREATE TABLE user_login(
      login_name VARCHAR() 用户登录名,可以是“登录名”、“邮箱”或“手机号”登录
      login_hash BIGINT 用户登录名的HASH码
      user_id BIGINT 用户ID
    );
    CREATE TABLE user_login0 LIKE user_login;
    CREATE TABLE user_login1 LIKE user_login;
    ... ...
    CREATE TABLE user_login100 LIKE user_login;

    ID与用户信息表,根据user_id分100张表
    CREATE TABLE user_info(
      user_id BIGINT 用户ID
      login_pwd CHAR() 用户登录密码
      ... ... 其他信息,家庭住址、手机号、性别等等
    );

    CREATE TABLE user_info0 LIKE user_info;
    CREATE TABLE user_info1 LIKE user_info;
    ... ...
    CREATE TABLE user_info2 LIKE user_info;

    业务实现逻辑:
    依赖服务器:实现一个自增ID的服务(相当于oracle的sequence),也可以自己实现(用PHP+MySQL或者用C实现都可以)。目的是可以从这个服务中取ID,每次取的ID数都是在上次基础上+1,和MySQL的autoincrement很像,只是不能在表内部自增。

    注册流程
    1)验证用户名、邮箱、手机号、密码等格式。省略...
    2)从服务中取一个ID,假设是115。
    3)如果用户的登录类型是邮箱(如:$loginName='songhuan@zixue.it'),则在登录名前加上前缀登录名结果(如:$loginName='mail_songhuan@zixue.it')
    4)求登录名的HASH值:$loginHash=md5($loginName); 对md5值hash,可以求asc码,或者用自己的算法,最后得出$loginHash=16位或32位的整数
    5)$tableName  = 'user_login' . ($loginHash%100),如果获取user_login表名,假如结果为user_login88。
    $tableName  = 'user_info' . (115%100),如果获取user_info表名。
    6)执行SQL:
    INSERT INTO user_login88 (login_name, login_hash, user_id) VALUES ('songhuan@zixue.it', 183239324323, 1);
    INSERT INTO user_info15 (user_id, login_pwd) VALUES (115, 'afieflefiefladifadfadfe');

    登录流程
    1)如果用户的登录类型是邮箱(如:$loginName='songhuan@zixue.it'),则在登录名前加上前缀登录名结果(如:$loginName='mail_songhuan@zixue.it')
    2)$loginHash=ord(md5($loginName));
    3)$tableName  = 'user_login' . ($loginHash%100); 假如结果为user_login88
    4)执行SQL:SELECT id FROM user_login88 WHERE login_hash = $loginHash;
    如果查询不到数据,则登录名不存在
    5)如果能获取到,id=115,则$tableName  = 'user_info' . (115%100);
    SELECT id, pwd ... FROM user_info15 WHERE id = 115;
    6)匹配密码,如果密码不相等,返回false
    7)如果密码相等,将用户ID加密放入COOKIE,将用户信息存入Memcache

    不能的字符串生成的hash值有可能相同,特别是当数据量巨大的时候,重复的概率更高。
    这时候通过一个hash从user_login表中获取的记录可能是多条。
    这时可以做一个性能和业务之间的权衡,就是当hash存在的时候,用户用就已经被使用了。
    假如:'songhuan'和'宋欢'对应的hash码相同,这时如果有用户注册了'songhuan',那么注册'宋欢'的时候也只能提示用户,该用户名已经被注册了。
    所以建表的时候,在login_hash上加上唯一索引

  • 相关阅读:
    使用Linq 更新数据库时遇到的一些问题及解决办法
    Asp.net 初级面试(转)
    jQuery设计思想
    WinCE BSP的BIB文件介绍
    团队管理经验(转)
    35岁以前成功的9大好习惯
    早起的十个好处,以及如何做到早起
    男人魅力的九个方面
    SQL优化34条(转)
    深入理解Javascript闭包(closure)
  • 原文地址:https://www.cnblogs.com/chenqionghe/p/4293370.html
Copyright © 2020-2023  润新知