轉載請註明出處:http://blog.csdn.net/smartbetter/article/details/53933096html
作App作的久了,就想研究一下與之相關的App後臺,發現也是蠻有趣的。App後臺的兩個重要做用就是 遠程存儲數據 和 消息中轉。這裏面的知識體系也是至關複雜,作好一個App後臺也是須要長期錘鍊的。本篇文章從 App 後臺架構 的角度介紹。好了,下面進入正題:sql
提及架構,咱們先看一下何爲架構,百度百科是這樣說的:架構,又名軟件架構,是有關軟件總體結構與組件的抽象描述,用於指導大型軟件系統各個方面的設計。那麼咱們也能夠看出,架構是和業務緊密相關的,是由業務驅動的。數據庫
因爲App客戶端的特性,所以App後臺對技術實現和通常的Web後臺是有區別的。首先看一個適合App開發的開發模式:編程
這裏推薦Scrum這個敏捷開發框架,具體能夠查看Scrum官網學習使用,這裏只是引入。json
Scrum流程以下圖:緩存
數據庫產品衆多,這裏我就針對Redis、MongoDB、MySQL還有MySQL的分支MariaDB展開說明:安全
數據庫 | 數據存放位置 | 查找數據的區別 |
---|---|---|
Redis | 內存 | 基於鍵值對存儲,讀寫速度快 |
MongoDB | 同時使用了硬盤和內存 | 每一個數據有一個id(索引),知道id(索引)查詢速度快,不知道id(索引)效率低 |
MySQL(MongoDB) | 硬盤 | 每一個數據有一個id(索引),知道id(索引)查詢速度快,不知道id(索引)效率低 |
而後根據不一樣的產品需求選擇恰當的數據庫產品,若是沒有特殊的需求,Redis作緩存系統,MySQL 或 MariaDB 作數據庫(常見的設置是 數據庫默認字符集utf8,默認排序utf8_general_ci) 將會是很好的選擇。服務器
軟件優化:markdown
硬件優化:網絡
架構優化:
CentOS 則是一個不錯的選擇。關於服務器的部署,我在以前已經介紹過了,地址以下:
Nginx + Tomcat 反向代理 負載均衡 集羣 部署指南
http://blog.csdn.net/smartbetter/article/details/53535435
Nginx + Tomcat 反向代理 如何在高效的在一臺服務器部署多個站點
http://blog.csdn.net/smartbetter/article/details/53615313
下面補充兩個常見的Linux命令:
當後臺系統發現完成某些小任務須要花費不少時間,並且遲點晚成也不影響整個任務的完成進度時,就會把這些小任務交給消息隊列。例如發送郵件、短信、推送消息等任務都很是適合在消息隊列中處理。
把這些任務放在消息隊列中,可加快App後臺請求都響應時間。同時消息隊列也能把大量的併發請求變成串行的請求,來減輕服務器的負擔。
常見的消息隊列軟件有:
消息隊列軟件 | 說明 |
---|---|
RabbitMQ | 重量級,適合企業級的開發,自帶Web監控界面,方便監控隊列的狀況 |
Redis | 輕量級,是一個key-value系統,可是也支持消息隊列這種數據結構,App後臺中Redis被普遍使用 |
ZeroMQ | 號稱最快,尤爲針對大吞吐量的需求場景 |
ActiveMQ | Apache的一個子項目,可以以代理人和點對點的技術實現隊列 |
隨着業務不斷增長,後臺系統由一個單一應用膨脹爲一個巨無霸系統,系統中聚合了大量的應用和服務,各個模塊之間有不少功能重複實現(例如登陸模塊),形成了開發、運維、部署的麻煩。
大量應用中的重複模塊會帶來大量的訪問,而每一個應用與數據庫的鏈接,通常是使用數據庫的鏈接池,這個鏈接池的資源通常是不釋放且一直保留着。假設鏈接池中有10個鏈接,中一個數百的服務器集羣中,就佔用了數據庫1000個鏈接。數據庫中的每一個鏈接都是十分珍貴的資源,在資源有限的狀況下,這裏被佔用了,其餘能用的資源就少了。
解決這些問題的方法就是把重複實現的模塊獨立部署爲遠程服務,新增的業務調用遠程服務所提供的功能實現相關的業務,不依賴於裏面具體的代碼實現。
實現遠程服務能夠 參考 REST設計原則 和 RPC遠程調用協議。
開源的RPC庫有:
開源的RPC庫 | 說明 |
---|---|
Hprose | 輕量級、跨語言、跨平臺、無侵入式、高性能動態遠程對象調用引擎庫 |
Dubbo | 分佈式服務框架,致力於提供高性能和透明化的RPC遠程調用服務和SOA服務治理方案 |
App操做中常常涉及用戶登陸操做,登陸就須要使用到用戶名和密碼,爲了安全起見,在登陸過程當中暴漏密碼的次數越少越好。
HTTPS協議是 HTTP協議 和 SSL/TLS協議 的組合。其是一個安全通訊通道,基於HTTP開發,用於在客戶計算機和App後臺之間交換信息。其使用安全套接字層(SSL)進行信息交換,簡單來講就是HTTP的安全版。
HTTPS實際上應用了安全套接字層(SSL)做爲HTTP應用層的子層。
HTTPS的模型:
HTTP |
---|
SSL/TLS(安全套接字層/傳輸層安全協議) |
TCP |
IP |
網絡傳輸 |
避免信息的泄漏,最基本的方案是全部涉及安全性的API請求都必須使用HTTPS協議。
JSON是一種輕量級的數據交換格式,採用徹底獨立於語言的文本格式,易於編寫,也易於機器解析和生成,並且對比XML更省流量,這些特性使得JSON成爲理想的數據交換語言。
傳統Web網站使用Cookie+Session保持用戶的登陸狀態,App後臺則使用token進行驗證,流程以下:
此時App已經獲取到了token值,爲了安全,咱們不在網絡上傳輸token,而使用簽名校驗(這裏使用URL簽名)的方式,API請求加上URL簽名sign和用戶id後以下:
test.com/user/update?uid=2&sign=3f1e736bc4ae958ae7e8500b45aefdbb&age=22
這樣,token就不須要附在URL上了。App後臺簽名校驗流程以下:
還有的童鞋喜歡設置時間戳,這樣時間一長,URL就失效了,也是一種不錯的進一步的優化方案。
建議:爲了保障數據安全,這裏建議 同時使用 HTTPS 和 簽名校驗。
App後臺的架構是由業務規模驅動而演進的,App後臺是爲業務服務的,App後臺的價值在於能爲業務提供其所須要的功能,不該過分設計。
從項目的角度,當App訪問量不大時,應該快速搭建App後臺,讓App儘快上線給用戶提供服務,驗證商業模式的正確性,同時快速迭代產品。
當App訪問量不斷上升,這時要在保證快速迭代的前提下,同時兼顧高性能和高可用。
當App訪問量達到必定階段後,增加曲線就會放緩,但業務變得更加複雜,對高性能和高可用的要求也更高,性能問題、模塊間的耦合、代碼的複雜性會更加突出和明顯,這時要使用業務拆分、分佈式服務調用,甚至是技術轉型等問題。
咱們看一個App後臺極簡化的架構:
一開始就使用Redis的好處:
既能用做緩存,又能充當隊列服務,並且併發性能高,能在長時間內應對業務壓力,很是適合初期的項目。
這裏使用Redis驗證用戶信息,充當消息隊列。
而文件服務初期能夠選擇 文件雲存儲服務,或者本身搭建一個資源服務器。
咱們看一個百萬級到千萬級的架構:
這裏新增了專門用於鏈接內部服務器的SSH服務的外網通道,保證SSH操做隨時可用,同時加入了服務器集羣,提供負載能力。
隨着業務的發展,某些數據表的規模會以幾何級增加,當數據達到必定規模時,查詢讀取性能就降低的厲害,數據庫主從的架構不能應對業務上的讀寫壓力,這時架構上要考慮分表(水平拆分/垂直拆分)。
當業務繼續不斷髮展,數據庫分表後的讀寫性能也可能無法知足業務上的需求,這時只能採用進一步的拆分策略——分庫。用 Cobar 或者 MyCat 等關係型數據等分佈式處理系統後,分庫後的架構以下:
下來看一個真實社交App項目所採用的後臺架構方案:
場景:相似 微博,用戶與用戶之間存在關注/粉絲兩種關係,一個用戶發表了新內容,關注他的用戶也能在我的主頁上收到最新的動態。相似 微博 這種場景:
社交核心功能是 Feed(指用戶經過關注,聚合了被關注用戶的最新的內容,也包含本身的內容,以供本身瀏覽的信息服務)。
常見的Feed架構是把數據存儲在MySQL,熱點數據存儲(通常最近3天)在緩存(Redis/Memcached),保證絕大多數請求經過緩存直接返回,只有少許請求穿透緩存落到數據庫。
下面看一下最簡單的Feed表結構:
send_content:發送內容表,存儲用戶發表的內容:
字段 | 說明 |
---|---|
feed_id | 發表的feed的id,主鍵自增 |
author_id | 發表該feed的用戶id |
content | feed的內容 |
reveive_content:接收內容表,用於推模式時存儲用戶接收的內容:
字段 | 說明 |
---|---|
feed_id | 發表的feed的id,主鍵自增 |
author_id | 發表該feed的用戶id |
reveive_id | 接收該feed的用戶id |
content | feed的內容 |
followings:關注表,存儲用戶關注的人:
字段 | 說明 |
---|---|
id | 主鍵自增 |
uid | 用戶id |
following_id | 該用戶關注的其餘用戶id |
followers:粉絲表,存儲用戶的粉絲:
字段 | 說明 |
---|---|
id | 主鍵自增 |
uid | 用戶id |
follower_id | 關注該用戶的用戶id |
1)uid爲1的用戶發表一條內容 「HelloWorld」 信息。
2)這條內容寫入發送內容表 「send_content」 後內容以下:
feed_id | author_id | content |
---|---|---|
1 | 1 | HelloWorld |
3)在粉絲表 「followers」 查找uid爲1用戶的粉絲,粉絲表 「followers」 的內容以下:
id | uid | follower_id |
---|---|---|
1 | 1 | 2 |
可知,id爲1用戶的粉絲是id爲2的用戶。
4)由於id爲2的用戶的feed中須要顯示這條內容,所以把內容寫入接收內容表 「reveive_content」,寫入後接受內容表 「reveive_content」 內容以下:
feed_id | author_id | reveive_id | content |
---|---|---|---|
1 | 1 | 2 | HelloWorld |
5)當id爲2的用戶顯示feed時,經過sql語句 「select * from reveive_content where reveive_id=2」 就能查詢該用戶須要顯示的數據了。
推模式的缺點是:
1)uid爲5的用戶發表一條內容 「Thinks」 信息。
2)這條內容寫入發送內容表 「send_content」 後內容以下:
feed_id | author_id | content |
---|---|---|
1 | 1 | HelloWorld |
2 | 5 | Thinks |
3)當uid爲10的用戶顯示feed時,在關注表 「followings」 查找uid爲10所關注的用戶,關注表以下:
id | uid | following_id |
---|---|---|
1 | 10 | 5 |
可知,uid爲10的用戶關注了uid爲5的用戶,所以須要獲取uid爲5的用戶發表的內容。
4)uid爲5的用戶經過sql語句 「select * from send_content where author_id in (5)」 查詢因此須要顯示的內容。
由上述可知,拉模式採用了時間換空間的策略,用戶推送內容時效率很高,但當用戶顯示feed時,須要花費大量的時間在聚合運算上。
總結:
- | 發表內容 | 顯示feed | 變動通知 |
---|---|---|---|
推模式 | 推送給全部粉絲 | 一個sql語句就能完成 | 變動成本高 |
拉模式 | 不推送 | 須要大量的聚合運算 | 無變動成本 |
像 「微博」 中公開的微博採用拉模式,私密性的微博採用推模式。
拉模式最大的問題就是大量的聚合運算,請求的響應時間可能較長,能夠經過緩存策略讓大部分的請求的響應時間達到2到3毫秒。
日常App設計中,若是App須要知道首頁是否有內容更新,經過一個輪詢機制訪問獲取數據API,從API是否返回更新的數據得知是否有內容更新,輪詢上很典型的拉模式,可是耗電、耗流量。
怎麼減小輪詢呢? 這裏給出解決方案是推模式,以下圖:
固然不能只用推模式,由於手機環境的複雜性,不能保證數據更新的通知必定可以到達App,因此也要採用輪詢的方式按期拉數據,時間間隔設置能夠相對長一點,經過這種推拉結合的模式,就能大大減小App訪問App後臺的頻率和傳輸的數據量。
表情在MySQL的存儲,表情UTF-8編碼有的是3個字節,有的是4個字節,因此通常的UTF編碼(3個字節)是沒法存儲表情數據的,經常使用的解決方案是:
把MySQL升級到5.5以上,而後把字符編碼改成utf8mb4_general_ci。
功能 | 可供選擇的開源軟件 |
---|---|
項目管理軟件 | Mantis、BugFree |
代碼管理軟件 | SVN、Git |
編程語言 | Java、PHP、Python等 |
服務器系統 | CentOS、Ubuntu |
HTTP/HTTPS服務器 | Nginx、Tomcat、Apache |
負載均衡 | Nginx、LVS、HAProxy |
郵件服務 | Postfix、Sendmail |
消息隊列 | RabbitMQ、ZeroMQ、Redis |
文件系統 | Fastdfs、mogileFS、TFS |
Android推送 | Androidpn、gopush |
IOS推送 | Javapns、Pyapns |
地理位置查詢LBS | MongoDB |
聊天 | Openfire、ejobberd |
監控 | ngiOS、zabbix |
緩存 | Memcache、Redis |
關係型數據庫 | MySQL、MariaDB、PostgreSQL |
NoSQL數據庫 | Redis、MongoDB、Cassandra |
搜索 | Coreseek、Solr、ElasticSearch |
圖片處理 | GraphicsMagick、ImageMagick |
分佈式訪問服務 | dubbo、dubbox |
對於初創公司仍是建議儘量的使用成熟可靠的雲服務和開源軟件,自身只專一於業務邏輯。
功能 | 可供選擇的雲服務 |
---|---|
項目管理工具 | Teambition、Tower |
代碼託管平臺 | GitHub、Gitlab、Bitbucket、CSDN CODE、Coding |
負載均衡 | 阿里雲SLB、騰訊雲CLB |
郵件服務 | SendCloud、MailGun |
消息隊列 | 阿里雲MNS、騰訊雲CMQ |
文件系統、圖片處理 | 七牛雲、阿里雲對象存儲OSS、騰訊雲對象存儲COS |
Android推送 | 極光、個推、百度推送 |
IOS推送 | 極光、個推、百度推送 |
聊天 | 融雲、環信 |
監控 | 監控寶、雲服務器自帶的監控服務 |
緩存 | 阿里雲緩存服務、騰訊雲彈性緩存 |
關係型數據庫 | 阿里雲RDS、騰訊雲CDB |
NoSQL數據庫 | 阿里雲NoSQL產品、騰訊雲NoSQL產品 |
搜索 | 阿里雲開放搜索、騰訊雲搜TCS |
分佈式訪問服務 | 阿里雲EDAS |
防火牆 | 阿里云云盾、騰訊雲安全 |
短信發送 | shareSDK、bmob、Luosimao |
社交登陸分享 | shareSDK |
最後,在移動互聯網項目中,產品的研發講求 小步快走,快速迭代。 架構的設計也能夠遵循一樣的思路,喜歡本文的記得 頂 一下哦!