1. 程式人生 > >Reddit 如何統計每個帖子的瀏覽量

Reddit 如何統計每個帖子的瀏覽量

我們想要更好地向用戶展示 Reddit 的規模。為了這一點,投票和評論數是一個帖子最重要的指標。然而,在 Reddit 上有相當多的使用者只瀏覽內容,既不投票也不評論。所以我們想要建立一個能夠計算一個帖子瀏覽數的系統。這一數字會被展示給帖子的創作者和版主,以便他們更好的瞭解某個帖子的活躍程度。

在這篇部落格中,我們將討論我們是如何實現超大資料量的計數。

計數機制

對於計數系統我們主要有四種需求:

  • 帖子瀏覽數必須是實時或者近實時的,而不是每天或者每小時彙總。
  • 同一使用者在短時間內多次訪問帖子,只算一個瀏覽量
  • 顯示的瀏覽量與真實瀏覽量間允許有小百分之幾的誤差
  • Reddit 是全球訪問量第八的網站,系統要能在生產環境的規模上正常執行,僅允許幾秒的延遲

要全部滿足以上四個需求的困難遠遠比聽上去大的多。為了實時精準計數,我們需要知道某個使用者是否曾經訪問過這篇帖子。想要知道這個資訊,我們就要為每篇帖子維護一個訪問使用者的集合,然後在每次計算瀏覽量時檢查集合。一個 naive 的實現方式就是將訪問使用者的集合儲存在記憶體的 hashMap 中,以帖子 Id 為 key。

這種實現方式對於訪問量低的帖子是可行的,但一旦一個帖子變得流行,訪問量劇增時就很難控制了。甚至有的帖子有超過 100 萬的獨立訪客! 對於這樣的帖子,儲存獨立訪客的 ID 並且頻繁查詢某個使用者是否之前曾訪問過會給記憶體和 CPU 造成很大的負擔。

因為我們不能提供準確的計數,我們查看了幾種不同的

基數估計演算法。有兩個符合我們需求的選擇:

  • 一是線性概率計數法,很準確,但當計數集合變大時所需記憶體會線性變大。
  • 二是基於 HyperLogLog (以下簡稱 HLL )的計數法。 HLL 空間複雜度較低,但是精確度不如線性計數。

下面看下 HLL 會節省多少記憶體。如果我們需要儲存 100 萬個獨立訪客的 ID, 每個使用者 ID 8 位元組長,那麼為了儲存一篇帖子的獨立訪客我們就需要 8 M的記憶體。反之,如果採用 HLL 會顯著減少記憶體佔用。不同的 HLL 實現方式消耗的記憶體不同。如果採用這篇文章的實現方法,那麼儲存 100 萬個 ID 僅需 12 KB,是原來的 0.15%!!

許多 HLL 的實現都是結合了上面兩種演算法。在集合小的時候採用線性計數,當集合大小到達一定的閾值後切換到 HLL。前者通常被成為 ”稀疏“(sparse) HLL,後者被稱為”稠密“(dense) HLL。這種結合了兩種演算法的實現有很大的好處,因為它對於小集合和大集合都能夠保證精確度,同時保證了適度的記憶體增長。可以在 google 的這篇

論文中瞭解這種實現的詳細內容。

現在我們已經確定要採用 HLL 演算法了,不過在選擇具體的實現時,我們考慮了以下三種不同的實現。因為我們的資料工程團隊使用 Java 和 Scala,所以我們只考慮 Java 和 Scala 的實現。

  • Twitter 提供的 Algebird,採用 Scala 實現。Algebird 有很好的文件,但他們對於 sparse 和 dense HLL 的實現細節不是很容易理解。
  • stream-lib中提供的 HyperLogLog++, 採用 Java 實現。stream-lib 中的程式碼文件齊全,但有些難理解如何合適的使用並且改造的符合我們的需求。
  • Redis HLL 實現,這是我們最終選擇的。我們認為 Redis 中 HLLs 的實現文件齊全、容易配置,提供的相關 API 也很容易整合。還有一個好處是,我們可以用一臺專門的伺服器部署,從而減輕效能上的壓力。

Reddit 的資料管道依賴於 Kafka。當一個使用者訪問了一篇部落格,會觸發一個事件,事件會被髮送到事件收集伺服器,並被持久化在 Kafka 中。

之後,計數系統會依次順序執行兩個元件。在我們的計數系統架構中,第一部分是一個 Kafka 的消費者,我們稱之為 Nazar。Nazar 會從 Kafka 中讀取每個事件,並將它通過一系列配置的規則來判斷該事件是否需要被計數。我們取這個名字僅僅是因為 Nazar 是一個眼睛形狀的護身符,而 ”Nazar“ 系統就像眼睛一樣使我們的計數系統遠離不懷好意者的破壞。其中一個我們不將一個事件計算在內的原因就是同一個使用者在很短時間內重複訪問。Nazar 會修改事件,加上個標明是否應該被計數的布林標識,並將事件重新放入 Kafka。

下面就到了系統的第二個部分。我們將第二個 Kafka 的消費者稱作 Abacus,用來進行真正瀏覽量的計算,並且將計算結果顯示在網站或客戶端。Abacus 從 Kafka 中讀取經過 Nazar 處理過的事件,並根據 Nazar 的處理結果決定是跳過這個事件還是將其加入計數。如果 Nazar 中的處理結果是可以加入計數,那麼 Abacus 首先會檢查這個事件所關聯的帖子在 Redis 中是否已經存在了一個 HLL 計數器。如果已經存在,Abacus 會給 Redis 傳送個 PFADD 的請求。如果不存在,那麼 Abacus 會給 Cassandra 叢集傳送個請求(Cassandra 用來持久化 HLL 計數器和 計數值的),然後向 Redis 傳送 SET 請求。這通常會發生在網友訪問較老帖子的時候,這時該帖子的計數器很可能已經在 Redis 中過期了。

為了儲存存在 Redis 中的計數器過期的老帖子的瀏覽量。Abacus 會週期性的將 Redis 中全部的 HLL 和 每篇帖子的瀏覽量寫入到 Cassandra 叢集中。為了避免叢集過載,我們以 10 秒為週期批量寫入。

下圖是事件流的大致流程:

總結

我們希望瀏覽量可以讓發帖者瞭解帖子全部的訪問量,也幫助版主快速定位自己社群中高訪問量的帖子。在未來,我們計劃利用我們資料管道在實時方面的潛力來為 Reddit 的使用者提供更多的有用的反饋。

相關推薦

Reddit 如何統計每個帖子瀏覽

我們想要更好地向用戶展示 Reddit 的規模。為了這一點,投票和評論數是一個帖子最重要的指標。然而,在 Reddit 上有相當多的使用者只瀏覽內容,既不投票也不評論。所以我們想要建立一個能夠計算一個帖子瀏覽數的系統。這一數字會被展示給帖子的創作者和版主,以便他們

使用Spark進行搜狗日誌分析實例——統計每個小時的搜索

360安全衛士 返回 用戶 sogo user 順序 contex 讀取文件 key 1 package sogolog 2 3 import org.apache.spark.rdd.RDD 4 import org.apache.spark.{SparkCo

git log統計每個作者的程式碼

前言 最近想寫一個指令碼檔案自動統計git裡每個作者分別增加了多少行程式碼,於是上網Google下看別人是怎麼寫的,來來去去都是下圖這種需要提前知道作者名字的 這種指令碼需要提前傳入author引數,

php例項三之網站瀏覽統計

本個例項是通過session統計登陸的次數。 <?php $countfile = "counter.txt"; if(($fp=fopen("counter.txt","r+"))==false) { echo "開啟檔案失敗!"; } else {

統計瀏覽

gin src 方法 設置 pda host clas .com col 每日清0今日瀏覽數 主要是使用了mysql數據庫的過程和事件。 首先需要一個更新數據庫瀏覽數的過程 CREATE DEFINER=`root`@`localhost` PROCEDURE

根據馬甲、應用商店、統計每天的註冊,要求可以根據選擇馬甲和app,馬甲和appstrore和user_login不同表問題

統計 eat create group ror 一次 instr 發現 用戶登錄 這個馬甲屬於一個表,appStore另一張表,用戶登錄表,主要操作的就是這三個表。 我這裏的馬甲和app的id都與用戶登錄表中的channel對應,在channel存放的是majiaId +

C#使用代理Ip刷新csdn文章瀏覽

獲取 center ebr display void ons os x finall set 昨天寫了一篇關於“c#批量抓取免費代理並驗證有效性”的文章,接著昨天的目標繼續完成吧,最終實現的目的就是刷新csdn文章的瀏覽量(實際上很簡單,之前博

題:統計數字出現次數。 隨機生成100個數字,數字範圍從1到10,統計每個數字出現的次數並打印到控制臺。

pre 方向 system 繼續 void pub arr static 遍歷 public static void main(String[] args) { printCount(getNumList());}private static ArrayList&l

自從我這樣擼代碼以後,公司網頁的瀏覽提高了107%!

hybrid master char 2.0 測試表 歷史 .html fir 次數 歡迎大家前往騰訊雲+社區,獲取更多騰訊海量技術實踐幹貨哦~ 本文由騰訊IVWEB團隊發表於雲+社區專欄 作者:yangchunwen HTTP協議是前端性能乃至安全中一個非常重要的

統計每個月兔子總數

數列 star 輸入 ble wid urn bject mon 規律 題目描述 有一只兔子,從出生後第3個月起每個月都生一只兔子,小兔子長到第三個月後每個月又生一只兔子,假如兔子都不死,問每個月的兔子總數為多少? 輸入: 9 輸出: 34 分析 1月大 2月大

Python爬蟲實戰--CSDN部落格爬蟲(附贈瀏覽小工具)

前言: 哈哈,繼續高興一下,通過自己的小手段,讓部落格訪問量過萬啦~怎麼做到的呢? 大家想一想我們近來所學的爬蟲知識,養兵千日用兵一時,在前面的學習,我們已經可以很輕鬆的爬去一些中小型和大型網站了,現在我們一起來思考一下,我們該怎麼去爬蟲CSDN網站,並順便提高一下我們部落格的瀏覽量呢? 問

python3爬取部落格瀏覽

爬取結果 程式碼很簡單: # encoding=utf8 import requests import re import time from bs4 import BeautifulSoup firstUrl = 'http://blog.csdn.

python3 抓取簡書,增加瀏覽

訪問簡書實現重新整理訪問次數,什麼都不說直接上程式碼 (一) # -*- coding:utf-8 -*- import sys import random import requests import pycurl import urllib import json import re i

自從我這樣擼程式碼以後,公司網頁的瀏覽提高了107%!

歡迎大家前往騰訊雲+社群,獲取更多騰訊海量技術實踐乾貨哦~ 作者:yangchunwen HTTP協議是前端效能乃至安全中一個非常重要的話題,最近在看《web效能權威指南(High Performance Browser Networking)》,把其中關於HTTP部分的內容拿出來分享一下,加了一點自己

Python selenium外掛使用 可刷瀏覽

常見selenium 程式碼及含義: Selenium是一個Web的自動化測試工具,最初是為網站自動化測試而開發的,型別像我們玩遊戲用的按鍵精靈,可以按指定的命令自動操作,不同是Selenium 可以直接執行在瀏覽器上,它支援所有主流的瀏覽器(包括Phantom

統計每個母音字母在字串中出現的次數。

CLICK HERE TO HAVE A TRY Time limit1000 ms Memory limit32768 KB 原題: 統計每個母音字母在字串中出現的次數。 Input 輸入資料首先包括一個整數n,表示測試例項的個數,然後是n行長度不超過

統計每個學科最受歡迎的老師前N名

package day02 import java.net.URL import org.apache.spark.rdd.RDD import org.apache.spark.{Partitioner, SparkConf, SparkContext} import scala.colle

C語言 實現讀取檔案,並統計每個字元出現的個數

/***************** 實現讀取檔案,並統計每個字元出現的個數 *****************/ #include <stdio.h> #include <stdlib.h> unsigned long file_size;

Python 編寫程式,生成1000個隨機[20,121)之間的整數,並統計每個元素出現的次數

Python    編寫程式,生成1000個隨機[20,121)之間的整數,並統計每個元素出現的次數 練習題 2018.10.11 import random a = [random.randint(20,121) for i in range(1000)] y = s

編寫MapReduce :統計每個關鍵詞,所在檔案及,第幾行出現了多少次

import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; import org.a