百度、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上加上唯一索引
