從零開始仿寫一個抖音App——日誌和埋點以及後端初步架構

本文首發於微信公衆號——世界上有意思的事,搬運轉載請註明出處,不然將追究版權責任。微信號:a1018998632,交流qq羣:859640274html

連載文章

本項目的 github 地址:MyTikTok

這兩週實在是太忙了,第一個需求即將上線加了一週的班,而後第二週又團建了三天致使此次的文章滯後了兩週,估計你們都覺得我要棄坑了。可是其實我在團建的時候都在趕文章,讓你們久等了。本週的文章將會討論下面幾個問題,你們能夠按需跳章查看以節省寶貴的時間,本文預計閱讀時間10分鐘java

  • 1.討論——總結前兩週評論中有意義的討論並給予個人解答
  • 2.日誌和埋點——討論一下日誌和埋點如何設計以及實現方案
  • 3.後端架構初步設想——討論一下將來的 app 的後端須要怎麼架構以及如何實現
  • 4.ubuntu環境初始化——將雲上的環境初始化成我所熟悉的 mac 環境(讀者若是是 windows 也能夠了解一下,到後期的話文章會涉及到比較多的 linux 下的操做)

1、討論

討論1:項目會不會使用 kotlin?python

  • 1.目前個人計劃是在基礎模塊上面使用 java ,在業務模塊中看狀況選擇幾個模塊使用 kotlin。

討論2:本系列文章是標題黨,蹭抖音的熱度linux

  • 1.首先明確一點爲何我要以抖音爲例子,緣由就是個人公司就是開發短視頻的,技術上有相似的地方,而本公司的產品是不可能做爲例子開發的,因此我就以抖音爲例但願能過一遍大公司的項目開發流程和架構,不只僅是給讀者帶來好處,對我來講也是一個很好的提高。
  • 2.固然不能否認的是抖音這個 title 給我帶來了必定的流量,也吸引了一部分人的眼球,可是我心安理得。由於每一篇文章的內容都是我花費兩週以上的業餘時間撰寫的,內容的質量上我敢說比通常的文章要好上很多。
  • 3.有句話說得好:人紅是非多,放在文章上也是同樣。我不但願打無謂的口水仗因此:之後若是文章中有與技術和文章無關的攻擊或者詆譭的評論我會直接刪除,而且不作回覆。

2、日誌和埋點

日誌在一個項目中起着很是重要的輔助做用,它可讓開發人員方便的定位 bug。它能夠在系統上線以後讓後臺監控 app 的性能以及穩定性。他還能夠收集用戶的行爲數據以方便對用戶的需求進行分析。在這一節中我會分析5種不一樣的日誌,並講解其中幾種日誌的實現方式。android

首先我先列舉一下五種不一樣的 log 吧。git

  • 1.debug 日誌:用於開發人員本地 debug
  • 2.aop debug 日誌:用於開發人員本地 debug, 使用了 aop 能夠經過簡單的註釋,對方法和類進行切片打日誌。用於打一些須要統一執行的日誌。
  • 3.網絡請求 日誌:用於開發人員在本地對網絡請求 debug
  • 4.本地文件 日誌:用於記錄在 app 上線以後出現的bug,將日誌打到文件中,能夠經過一個入口讓用戶手動點擊上傳日誌。
  • 5.埋點 日誌:用於記錄用戶使用 app 的數據、app 性能等等的埋點日誌,數據結構由先後端協商定義,最後會存入後端的數據庫以便進行一些數據分析。埋點的方式能夠是手動的,能夠是自動的。

一、debug日誌

圖1:debug日誌.png

  • 1.debug 日誌比較簡單,如圖一就是將 android 自身提供的 Log 類進行一些封裝,添加一些本身須要的特性和擴展,這裏就很少贅述了具體實現能夠看項目中的代碼。

二、aop日誌

圖2:aop日誌.png

  • 1.不少人在寫一些重複性的日誌的時候就會想到 aop,這種技術能夠在註解的方法先後注入須要的模板代碼。我在上一篇文章中講到了這個技術,有興趣的同窗能夠去看看,這裏我就簡單說一下。
  • 2.首先咱們得先定義一個註解類,其能夠用於註解類或者方法。註解類中能夠被填入一些信息,好比是否須要打印方法的初入參等等。
  • 3.在註解類使用了以後,咱們須要用到 gradle transform。這種技術可讓咱們在編譯期間掃描全部的類,從而找被註解類所註解的方法和類。
  • 4.最後咱們能夠用上javassist來給找到的方法先後注入咱們須要的代碼。注意這裏的日誌能夠是本地的 debug日誌,也能夠是本地文件日誌,還能夠是埋點日誌。能夠說 aop 日誌只是一種對另外幾種日誌的自動化封裝。

三、網絡請求日誌

圖3:網絡請求日誌.png

  • 1.咱們在調試網絡請求的時候,除了抓包還會打印出網絡請求。這個時候就若是有一種統一的形式來打印日誌的話就會方便許多。
  • 2.如今絕大部分的廠商使用的網絡請求庫都是 okhttp ,因此我就直接在其上面進行日誌的定製就好了。由於項目的 http 模塊尚未進行開發,因此尚未實現代碼,這裏就講一講大體方案。以後在開發 http 模塊的時候會順便講解具體實現。
  • 3.在講解方案以前咱們須要知道,okhttp 的工做方式。如圖3中所示,在一個 okhttp 請求的過程當中會通過一個個攔截器,從本地向網絡請求的時候會通過一次,網絡請求回來的時候又會通過一次。
  • 4.因此咱們就能夠添加一個日誌攔截器在兩次通過攔截器的時候打印請求的 head 和按需打印 請求的 body。注意,這裏打印能夠是向 debug 日誌、本地文件日誌、埋點日誌這三個地方打印。分別用於本地 debug、線上 debug和網絡性能監控。

四、本地文件日誌

圖4:本地文件日誌.png

  • 1.當咱們在線上碰見 bug 的時候咋辦呢?有些 crash 的日誌能夠經過 bugly 這種平臺來進行回撈。可是有些奇葩的 bug 只在某些機型甚至某些用戶的手機上發生。這個時候本地文件日誌就派上用場了。
  • 2.咱們能夠在開發的時候在一些關鍵的功能上手動添加上本地文件日誌。當某個用戶報了 bug 以後咱們就可讓其經過一個入口將文件日誌發送到後臺,最後由開發人員進行日誌分析找到問題。
  • 3.接下來我就來經過代碼結合上面的圖4來說解本地文件日誌的實現方式。
  • 4.咱們先來看看圖4:
    • 1.LocalFileLogger負責提供本模塊對外的 api,主要功能有兩個:
      • 1.初始化和綁定LocalFileLoggerService(這是一個 service,能夠經過 binder 來與外部交互)
      • 2.經過 binder 將外部的添加日誌的請求交給LocalFileLoggerService
    • 2.LocalFileLoggerService中會初始化一個 HandlerThread,本 Service 會經過 Handler 向其不斷的拋入通過高性能拼接的日誌的添加請求。
    • 3.FileLogger是負責將日誌寫入本地的類,其也初始化了一個 HandlerThread,而且自定義了一個 LoggerHandler。這個 Handler 會將 LocalFileLoggerService 拋過來的一條條日誌進行累積,當積累到了必定量的時候。發出寫入日誌的請求交給 HandlerThread執行。

圖5:LocalFileLogger代碼1.png
圖6:LocalFileLoggerService代碼1.png
圖7:FileLogger代碼1.png
圖8:LoggerHandler代碼1.png

  • 5.再來看看代碼,咱們跟着代碼走一遍流程:
    • 1.首先在圖5中咱們能夠看見在 addLog 中通過一系列的調用,最終交給了 sLogInterface.log 這個對象是一個 Binder 對象,用於操做 LocalFileLoggerService 。
    • 2.進入到圖6,能夠看見 Service 初始化了一個 HandlerThread 而後定義了一個 Handler 用於向其中拋送請求。而後在看 mBinder 的實現就是經過 Handler 向 HandlerThread 中拋送 FileLogger.addLog 的執行請求。
    • 3.進入到圖7,能夠看見在 FileLogger 初始化的時候也初始化了一個 HandlerThread ,而後定義了一個 LoggerHandler 來向其中拋日誌寫入請求。FileLogger.addLog 方法中是直接發送一個請求。
    • 4.再看圖8,LoggerHandler.add 中並不會當即向本地寫入日誌,而是會有一 LOG_CACHE_COUNT 閾值,只有超過了這個閾值纔會向文件系統中寫入日誌。

五、埋點日誌

圖9:埋點日誌.png

  • 1.埋點日誌其實和文件日誌相似,我這裏就結合圖9簡單說一下,具體的代碼你們能夠去翻看項目
  • 2.首先仍是有一個 UploadLogManager 用於給外部提供 api 以及初始化 LocalFileLoggerService。這裏比文件系統複雜的地方就在於多了一個 UploadLogConfiguration 用於裝配一些設置。
  • 3.有了 LocalFileLoggerService 以後這裏分兩個不一樣的埋點日誌添加方式。
    • 1.實時埋點日誌添加:外部須要當即將當前的埋點日誌上報,此時就直接將請求發送給 UploadLogHandler 而後交給 HandlerThread 執行,最終 經過 LogSender執行網絡上報。
    • 2.非實時埋點日誌添加:這種方式是每隔必定的時間,LocalFileLoggerService 會從 UploadLogStorage 中取出必定量的日誌,合併以後再像1中同樣上報埋點。
  • 4.目前由於 Http 模塊和 數據庫模塊都沒有開始寫,因此 UploadLogStorage 和 LogSender 都還只是接口,可是並不影響代碼邏輯。

3、後端架構的初步設想

雖然本項目的着重點是仿抖音 android 端 app 的開發,可是後臺方面也會有所涉及。接下來筆者會介紹一下本項目在後端方面的目標和預期達到的效果。程序員

一、RPC

可能會有客戶端的同窗對 RPC(遠程過程調用) 這個詞不怎麼了解,我這裏就先簡單介紹一下。github

拿 Java 來講:好比咱們有兩個服務 A、B 在兩個服務器上,此時咱們要在 A 上調用 B 的服務獲取其上的數據 Foo。那麼在 A 中能夠寫成 Foo f = b.XXXService();。在這裏 Foo 是 A、B 兩個服務所定義的數據傳輸結構,b 是 B 服務所抽象出來的對象,其內部實現能夠是各類網絡數據交互協議,好比說 http 協議。簡單來講:RPC就是要像調用本地的函數同樣去調遠程函數。算法

現存的 RPC 框架有不少,各個大廠也都開源了本身框架,我這裏就介紹和比較一下幾個框架,最後結合本項目的需求選擇適合的框架。docker

  • 1.Dubbo:這個是阿里開源的一個框架,後來阿里由於種種緣由把他廢棄了,最後被噹噹網維護擴展出了一個 Dubbox。這裏就講一講他的優劣勢吧:
    • 1.優點:
      • 1.Dubbo 是用 java 寫的,對於 android 客戶端的開發者來講比較友好。
      • 2.Dubbo 的生態目前來講仍是比較好的,筆者去年在有贊實習 java 開發的時候,用過半年的 Dubbo,感受各類坑都有人踩過,各類庫也都比較完善。
      • 3.對於服務治理支持的比較到位。
    • 2.劣勢:
      • 1.跨平臺能力差,原生的 Dubbo 基本上沒有跨平臺能力,後面的話集成了 thrift 做爲擴展的話就有了,不過我總感受集成以後用起來不方便。
      • 2.以 java 做爲主開發語言的話,不能快速迭代。咱們項目的時間主要是要向 android 客戶端傾斜,因此須要一個能快速迭代的語言。
      • 3.序列化和反序列化的速度與其餘 RPC 框架相比都不是很拔尖。
      • 4.性能較其餘幾個框架差。
  • 2.Thrift:這個是 FaceBook 開源的一個框架,2007年由facebook貢獻到apache基金,是apache下的頂級項目。
    • 1.優點:
      • 1.跨平臺能力強,支持幾乎全部的主流語言。
      • 2.性能比較好
    • 2.劣勢:
      • 1.跨平臺的語言協議寫起來比較麻煩。
      • 2.不支持服務治理
  • 3.Grpc:由 Google 開源的框架,我司目先後端也在使用這個框架
    • 1.優點:
      • 1.跨平臺能力強、支持大部分主流開發語言
      • 2.跨平臺語言協議用的是 ProtoBuf,與咱們客戶端的技術棧一致。
      • 3.性能比較好
      • 4.有我司的技術支持,固然不是官方的,不過我能夠了解我司在這方面的技術,最後反哺到咱們的項目中。
    • 2.劣勢:
      • 1.不支持服務治理

看了上面的比較我想你們內心已經有了答案,沒錯我決定使用 grpc 作爲本項目後端的 rpc 框架。而後開發的語言是 python 爲主,java 爲輔助,後面若是有時間的話可能會用 go 實現一個小的服務也說不定。使用這些語言的緣由有下面幾點:

  • 1.首先 python 目先後臺的生態也比較成熟,用起來也比較方便快速。
  • 2.其次咱們到了後面會使用 tensorflow 來訓練各類深度學習的模型,這樣的話熟練使用 python 是必須的。
  • 3.有人會問你爲何要用幾種不一樣的語言來實現後端的服務呢?這不是畫蛇添足嗎。的確,從正常開發的角度來說是挺多餘的,可是多語言的環境在大一些的廠來說是再正常不過的事情,個人一部分目的也是爲了模擬這種場景。除此以外,這種多語言的環境在我看來仍是比較有意思的,想試試玩玩看。

2.微服務與服務治理

其實原本在這裏我有不少東西想說的,可是發現本身如今的能力並不能徹底說好這兩個東西,怕最後會誤導你們,因此我這裏就列一下最後本項目須要完成的與這兩個目標相關的東西。

  • 1.在將來筆者預期的是會有10臺服務機器,兩臺爲一組提供一類服務,一共會有五個大類的服務。
  • 2.因此第一個要實現的功能就是:服務發現註冊功能。這個功能主要是和註冊中心進行交互。
    • 1.服務提供者啓動,向註冊中心註冊本身提供的服務
    • 2.消費者啓動,向註冊中心訂閱本身須要的服務
    • 3.註冊中心返回服務提供者的列表給消費者
    • 4.消費者從服務提供者列表中,按照軟負載均衡算法,選擇一臺發起請求
  • 3.爲了瞭解和監控各個服務的狀況,第二個要實現的功能就是:服務監控,即累計計算隨着時間推移各個服務被調用的次數。
  • 4.爲了區份內外網,以及統一鑑權。須要實現的第三個功能就是:服務網關,全部外部請求都會通過這個網關,網關會將請求分發給內部的機器,內部機器調用完成以後會將結果經過網關返回給外部。

4、ubuntu環境初始化

不知道在個人讀者中有多少我的用的是 mac。由於我本人就是 mac 和 win 的雙系統用戶因此我深知。mac 在開發方面的好處。這一節就輕鬆一點,我演示一下如何將本地 mac 命令行環境初始化到雲上的 ubuntu 中。

一、oh my zsh

圖10:oh my zsh.png

  • 1.首先須要在XX雲中買一個機器。我買的是阿里雲,最開始的系統模板選擇 ubuntu16,而後什麼都不要裝。而後在本地用 ssh 登陸雲主機。
  • 2.在本地電腦上 clone 一下個人這個庫,接下來要用到裏面的兩個腳本文件。ubuntu初始化
  • 3.用 scp 命令將2中的兩個文件上傳到服務器上分別是:ubuntu_init.sh 和 ubuntu_init_oh-my-zsh.sh。例如:scp a.jpg root@47.106.145.211:/root/a.jpg,將本地本目錄的 a.jpg 文件上傳爲雲服務器上的/root/a.jpg文件。
  • 4.運行ubuntu_init.sh,中間會讓你輸入密碼,最後會重啓服務器。
  • 5.等4中重啓服務器以後,登陸服務器而後運行ubuntu_init_oh-my-zsh.sh。如此就大功告成了。最終效果如圖10,這個終端比 ubuntu 原生的好用多了,並且還支持各類定製的插件。
  • 6.忘了說了這個命令行是一個開源項目:oh my zsh,英語比較好的同窗能夠看原項目,來拓展本身的配置。

二、vim 配置

圖11:vim.png

  • 1.接下來就是 vim 的配置,其實我到如今也沒徹底成功的把配置徹底成功的把配置完成成功的轉移到 ubuntu 上面,因此你們看看就好。
  • 2.ubuntu初始化,這個倉庫裏 .vimrc 是 vim 的配置文件。vim 插件管理,這個倉庫裏是 vim 插件庫。
  • 3.這裏其實就是爲了 show 一下個人成果,對於初學者來講能學習的方面很少,對於老鳥來講也看不上個人配置。

三、docker配置

這兩週我也抽空學習了一下 docker,個人理解上 docker 就是一個方便打包重用超輕量虛擬機。因此咱們後端也會用上這個技術以方便運維。我也是剛學這東西,因此我就貼幾個我學習的網址吧!

5、尾巴

本篇文章是從零開始仿寫一個抖音App系列文章的第四篇,篇幅比較長能看到這裏的同窗很是感謝大家對個人承認。從決定寫這個系列的文章開始到如今已經兩個多月了,我發現這兩個月個人成長是很是迅速的,因此接下來我還會堅持這樣寫下去。

不販賣焦慮,也不標題黨。分享一些這個世界上有意思的事情。題材包括且不限於:科幻、科學、科技、互聯網、程序員、計算機編程。下面是個人微信公衆號:世界上有意思的事,乾貨多多等你來看。

世界上有意思的事
相關文章
相關標籤/搜索