從零搭建精準(zhǔn)運(yùn)營(yíng)系統(tǒng)

2018剛過(guò)去,趁著春節(jié)放假對(duì)過(guò)去一年主導(dǎo)開發(fā)的項(xiàng)目做個(gè)梳理和總結(jié)

項(xiàng)目背景

平臺(tái)運(yùn)營(yíng)到一定階段屎慢,一定會(huì)累積大批量的用戶數(shù)據(jù)蒿往,這些用戶數(shù)據(jù)是運(yùn)營(yíng)人員的黃金財(cái)產(chǎn)。而如何利用用戶的數(shù)據(jù)來(lái)做運(yùn)營(yíng)(消息推送氯庆、觸達(dá)消息、優(yōu)惠券發(fā)送扰付、廣告位等)堤撵,正是精準(zhǔn)運(yùn)營(yíng)系統(tǒng)需要解決的問(wèn)題。本文是基于信貸業(yè)務(wù)實(shí)踐后寫出來(lái)的羽莺,其它行業(yè)如保險(xiǎn)实昨、電商、航旅盐固、游戲等也可以參考荒给。

業(yè)務(wù)場(chǎng)景

先看幾個(gè)具有代表性的需求

用戶可用額度在20000~50000元,而且有借款記錄刁卜,未還本金為0志电,性別為“男”
用戶發(fā)生了A行為且未還本金大于5000
用戶在1天內(nèi)發(fā)生A行為次數(shù)大于等于3次
用戶在A行為前24小時(shí)內(nèi)未發(fā)生B行為
用戶在A行為后一個(gè)月內(nèi)未發(fā)生B行為

業(yè)務(wù)上有兩種消息類型

  • 日常消息:由業(yè)務(wù)人員通過(guò)條件篩選鎖定用戶群,定時(shí)或即時(shí)給批量用戶發(fā)送消息或者優(yōu)惠券
  • 觸達(dá)消息:主要由用戶自身的行為觸發(fā)蛔趴,比如登陸挑辆、進(jìn)件申請(qǐng)、還款等孝情,滿足一定篩選條件實(shí)時(shí)給用戶發(fā)送消息或優(yōu)惠券

對(duì)于用戶篩選條件鱼蝉,也主要有兩種類型

  • 用戶狀態(tài):包括用戶自身屬性如性別、年齡箫荡、學(xué)歷魁亦、收入等,還有用戶相關(guān)聯(lián)實(shí)體如進(jìn)件訂單羔挡、賬戶信息洁奈、還款計(jì)劃、優(yōu)惠券等的屬性婉弹,以及用戶畫像數(shù)據(jù)如行為偏好睬魂、進(jìn)件概率等
  • 用戶行為:即用戶的動(dòng)作,包括登陸镀赌、進(jìn)件申請(qǐng)氯哮、還款,甚至前端點(diǎn)擊某個(gè)按鈕、在某個(gè)文本框輸入都算

早期方案

早期方案.png

早期方案存在以下痛點(diǎn)

  1. 至少兩次跨部門溝通配合成本喉钢,周期被拉長(zhǎng)
  2. 非實(shí)時(shí)消息推送姆打,無(wú)法實(shí)現(xiàn)基于用戶行為的實(shí)時(shí)推送場(chǎng)景
  3. 非實(shí)時(shí)效果驗(yàn)證,無(wú)法及時(shí)調(diào)整運(yùn)營(yíng)策略

系統(tǒng)搭建的目標(biāo)

  • 需要定義規(guī)則肠虽,提供可視化界面給業(yè)務(wù)人員動(dòng)態(tài)配置幔戏,無(wú)需重啟系統(tǒng)即使生效,減少溝通成本和避免重復(fù)開發(fā)税课,總之就是要更加 自動(dòng)化易配置
  • 采集實(shí)時(shí)數(shù)據(jù)闲延,根據(jù)實(shí)時(shí)事件做實(shí)時(shí)推送,總之就是要 實(shí)時(shí)

技術(shù)選型

數(shù)據(jù)采集韩玩、轉(zhuǎn)換垒玲、存儲(chǔ)

  • 采集:狀態(tài)類的數(shù)據(jù)主要放在各個(gè)業(yè)務(wù)系統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)中,由于歷史原因有postgres和mysql找颓,需要實(shí)時(shí)采集表的數(shù)據(jù)變更合愈,這里使用kafka connector讀取mysql的binlog或postgres的xlog,另外還有標(biāo)簽系統(tǒng)計(jì)算出來(lái)的標(biāo)簽击狮,在kafka中佛析;而事件類數(shù)據(jù)主要來(lái)源于前端上報(bào)事件(有專門的服務(wù)接收再丟到kafka),關(guān)系型數(shù)據(jù)庫(kù)里面也可以提取一些事件彪蓬。
  • 轉(zhuǎn)換:采集出來(lái)的數(shù)據(jù)需要做一些格式統(tǒng)一等操作寸莫,用kafka connector。
  • 存儲(chǔ):采用Elasticsearch存儲(chǔ)用戶數(shù)據(jù)档冬,ES查詢不像mysql或mongoDB用B-tree 或B+tree實(shí)現(xiàn)索引储狭,而是使用bitset和skip list來(lái)處理聯(lián)合索引,特別適合多字段的復(fù)雜查詢條件捣郊。

下面重點(diǎn)看下kafka connector和Elasticsearch如何使用

kafka connector

kafka connector有Source和Sink兩種組件,Source的作用是讀取數(shù)據(jù)到kafka慈参,這里用開源實(shí)現(xiàn)debezium來(lái)采集mysql的binlog和postgres的xlog呛牲。Sink的作用是從kafka讀數(shù)據(jù)寫到目標(biāo)系統(tǒng),這里自己研發(fā)一套組件驮配,根據(jù)配置的規(guī)則將數(shù)據(jù)格式化再同步到ES娘扩。
kafka connector有以下優(yōu)點(diǎn):

  • 提供大量開箱即用的插件,比如我們直接用debezium就能解決讀取mysql和pg數(shù)據(jù)變更的問(wèn)題
  • 伸縮性強(qiáng)壮锻,對(duì)于不同的connector可以配置不同數(shù)量的task琐旁,分配給不同的worker,猜绣,我們可以根據(jù)不同topic的流量大小來(lái)調(diào)節(jié)配置灰殴。
  • 容錯(cuò)性強(qiáng),worker失敗會(huì)把task遷移到其它worker上面
  • 使用rest接口進(jìn)行配置掰邢,我們可以對(duì)其進(jìn)行包裝很方便地實(shí)現(xiàn)一套管理界面

Elasticsearch

對(duì)于狀態(tài)數(shù)據(jù)牺陶,由于狀態(tài)的寫操作相對(duì)較少伟阔,我們采取嵌套文檔的方式,將同個(gè)用戶的相關(guān)實(shí)體數(shù)據(jù)都同步寫入到同個(gè)文檔掰伸,具體實(shí)現(xiàn)用painless腳本做局部更新操作皱炉。效果類似這樣:

{
   "id":123,
   "age":30,
   "credit_line":20000,
   "education":"bachelor",
   ...
   "last_loan_applications":{
         "loan_id":1234,
         "status":"reject",
          ...
    }
  ...
}

事件數(shù)據(jù)寫入比較頻繁,數(shù)據(jù)量比較多狮鸭,我們使用父子文檔的方式做關(guān)聯(lián)合搅,效果類似這樣:

{
  "e_uid":123,
  "e_name":"loan_application",
  "e_timestamp":"2019-01-01 10:10:00"
  ...
}

(e_前綴是為了防止同個(gè)index下同名字段沖突)
ES這樣存儲(chǔ)一方面是方便做統(tǒng)計(jì)報(bào)表,另一方面跟用戶篩選和觸達(dá)有關(guān)歧蕉。

規(guī)則引擎

在設(shè)計(jì)規(guī)則引擎前灾部,我們對(duì)業(yè)界已有的規(guī)則引擎,主要包括Esper, Drools, Flink CEP廊谓,進(jìn)行了初步調(diào)研梳猪。

Esper

Esper設(shè)計(jì)目標(biāo)為CEP的輕量級(jí)解決方案,可以方便的嵌入服務(wù)中蒸痹,提供CEP功能春弥。
優(yōu)勢(shì):

  • 輕量級(jí)可嵌入開發(fā),常用的CEP功能簡(jiǎn)單好用叠荠。
  • EPL語(yǔ)法與SQL類似匿沛,學(xué)習(xí)成本較低。

劣勢(shì):

  • 單機(jī)全內(nèi)存方案榛鼎,需要整合其他分布式和存儲(chǔ)逃呼。
  • 以內(nèi)存實(shí)現(xiàn)時(shí)間窗功能,無(wú)法支持較長(zhǎng)跨度的時(shí)間窗者娱。
  • 無(wú)法有效支持定時(shí)觸達(dá)(如用戶在瀏覽發(fā)生一段時(shí)間后觸達(dá)條件判斷)抡笼。

Drools Fusion

Drools開始于規(guī)則引擎,后引入Drools Fusion模塊提供CEP的功能黄鳍。
優(yōu)勢(shì):

  • 功能較為完善推姻,具有如系統(tǒng)監(jiān)控、操作平臺(tái)等功能框沟。
  • 規(guī)則支持動(dòng)態(tài)更新

劣勢(shì):

  • 以內(nèi)存實(shí)現(xiàn)時(shí)間窗功能藏古,無(wú)法支持較長(zhǎng)跨度的時(shí)間窗。
  • 無(wú)法有效支持定時(shí)觸達(dá)(如用戶在瀏覽發(fā)生一段時(shí)間后觸達(dá)條件判斷)忍燥。

Flink CEP

Flink 是一個(gè)流式系統(tǒng)拧晕,具有高吞吐低延遲的特點(diǎn),F(xiàn)link CEP是一套極具通用性梅垄、易于使用的實(shí)時(shí)流式事件處理方案厂捞。
優(yōu)勢(shì):

  • 繼承了Flink高吞吐的特點(diǎn)
  • 事件支持存儲(chǔ)到外部,可以支持較長(zhǎng)跨度的時(shí)間窗。
  • 可以支持定時(shí)觸達(dá)(用followedBy+PartternTimeoutFunction實(shí)現(xiàn))

劣勢(shì):

  • 無(wú)法動(dòng)態(tài)更新規(guī)則(痛點(diǎn))

自定義規(guī)則

綜上對(duì)比了幾大開源規(guī)則引擎蔫敲,發(fā)現(xiàn)都無(wú)法滿足業(yè)務(wù)特點(diǎn):

  • 業(yè)務(wù)方要求支持長(zhǎng)時(shí)間窗口(n天甚至n個(gè)月饲嗽,比如放款一個(gè)月后如果沒(méi)產(chǎn)生還款事件就要發(fā)消息)
  • 動(dòng)態(tài)更新規(guī)則,而且要可視化(無(wú)論用哪個(gè)規(guī)則引擎都需要包裝奈嘿,需要考慮二次開發(fā)成本)
  • 除了匹配事件貌虾,還需要匹配用戶狀態(tài)

最終我們選擇自己根據(jù)業(yè)務(wù)需要,開發(fā)基于json的自定義規(guī)則裙犹,規(guī)則類似下面例子:

{
  "batchId": "xxxxxxxx", //流水號(hào)尽狠,創(chuàng)建每條運(yùn)營(yíng)規(guī)則時(shí)生成
  "type": "trigger", //usual
  "triggerEvent": "login",
  "after": "2h", //分鐘m,小時(shí)h,天d,月M
  "pushRules": [//支持同時(shí)推送多條不同類型的消息
    {
      "pushType": "sms", //wx,app,coupon
      "channel": "cl",
      "content": "hello #{userInfo.name}"
    },
    {
      "pushType": "coupon",
      "couponId": 1234
    }
  ],
  "statusConditions": [
    {
      "name": "and", //邏輯條件,支持與(and)或(or)非(not)
      "conditions": [
        {
          "name": "range",
          "field": "credit_line",
          "left": 2000,
          "right": 10000,
          "includeLeft": true,
          "includeRight": false
        },
        {
          "name":"in",
          "filed":"education",
          "values":["bachelor","master"]
        }
      ]
    }
  ],
  "eventConditions": [
    {
      "name": "or",//邏輯條件叶圃,支持與(and)或(or)非(not)
      "conditions": [
        {
          "name": "event",
          "function": "count", //聚合函數(shù),目前只支持count
          "eventName": "xxx_button_click",
          "range": { //聚合結(jié)果做判斷
            "left": 1,
            "includeLeft": true
          },
          "timeWindow": {
            "type": "fixed", //fixed為固定窗口袄膏,sliding為滑動(dòng)窗口
            "start": "2019-01-01 01:01:01",
            "end": "2019-02-01 01:01:01"
          },
          "conditions": [ //event查詢條件繼承and邏輯條件,所以事件也可以過(guò)濾字段
            {
              "name": "equals",
              "field": "f1",
              "value": "v1"
            }
          ]
        }
      ]
    }
  ]
}

使用面向?qū)ο笏季S對(duì)過(guò)濾條件做抽象后掺冠,過(guò)濾條件繼承關(guān)系如下:


過(guò)濾條件繼承關(guān)系.png

然后代碼里加一層parser把Condition都轉(zhuǎn)成ES查詢語(yǔ)句沉馆,實(shí)現(xiàn)輕量級(jí)的業(yè)務(wù)規(guī)則配置功能。

整體技術(shù)方案

整體技術(shù)方案

系統(tǒng)組成模塊及功能如下:
mysql binlog:mysql的數(shù)據(jù)變更德崭,由kafka connector插件讀取到kafka斥黑,數(shù)據(jù)源之一
postgres xlog:pg的數(shù)據(jù)變更,由kafka connector插件讀取到kafka眉厨,數(shù)據(jù)源之一
report server:事件上報(bào)服務(wù)锌奴,數(shù)據(jù)源之一
tags:用戶畫像系統(tǒng)計(jì)算出來(lái)的標(biāo)簽,數(shù)據(jù)源之一
觸發(fā)場(chǎng)景路由:分實(shí)時(shí)觸發(fā)和延遲觸發(fā)憾股,實(shí)時(shí)觸發(fā)直接到下一步鹿蜀,延遲觸發(fā)基于 redis的延遲隊(duì)列實(shí)現(xiàn)
用戶篩選處理器:將篩選規(guī)則翻譯為ES查詢語(yǔ)句到ES查詢用戶數(shù)據(jù),可以是批量的和單個(gè)用戶的
冪等處理器:對(duì)數(shù)據(jù)做冪等處理服球,防止重復(fù)消費(fèi)
變量渲染處理器:對(duì)推送內(nèi)容做處理
推送適配器:兼容不同的推送方式
BloomFilter記錄器:將推送用戶和流水號(hào)記錄到redis茴恰,用于冪等處理
推送事件記錄器:將推送事件推入kafka
定時(shí)任務(wù)模塊:基于elastic-job,處理定時(shí)推送任務(wù)
規(guī)則配置控制臺(tái):提供可視化配置界面(運(yùn)營(yíng)規(guī)則配置斩熊、數(shù)據(jù)采集規(guī)則配置琐簇、字段元數(shù)據(jù)配置等)
報(bào)表服務(wù):提供報(bào)表查詢功能
運(yùn)營(yíng)位服務(wù):提供外部接口,根據(jù)條件匹配運(yùn)營(yíng)位(如啟動(dòng)圖座享、首頁(yè)banner圖片等)

總結(jié)與展望

  • 系統(tǒng)基本滿足了目前的業(yè)務(wù)需求,對(duì)轉(zhuǎn)化率等運(yùn)營(yíng)指標(biāo)提升顯著
  • 可以擴(kuò)展其它業(yè)務(wù)似忧,如推薦渣叛、風(fēng)控、業(yè)務(wù)監(jiān)控等
  • 規(guī)則定時(shí)拉取盯捌,實(shí)時(shí)性差淳衙,可以用zk做發(fā)布訂閱實(shí)現(xiàn)即時(shí)更新
  • 目前事件的聚合函數(shù)只支持count,能滿足業(yè)務(wù)需求但是未來(lái)可能還需要支持其它函數(shù)
  • 系統(tǒng)只經(jīng)過(guò)千萬(wàn)級(jí)用戶,日千萬(wàn)級(jí)事件數(shù)據(jù)的生產(chǎn)驗(yàn)證箫攀,再高數(shù)量級(jí)的話可能還有很多性能優(yōu)化的工作,如ES并行查詢(目前用scroll api批量拉取用戶數(shù)據(jù)是串行的)
  • 事件類數(shù)據(jù)越來(lái)越多肠牲,目前采取定時(shí)刪除半年前數(shù)據(jù)的方式,防止持續(xù)增長(zhǎng)過(guò)快不可控靴跛,所以事件類條件不可超過(guò)半年的時(shí)間窗口
  • 雖然系統(tǒng)對(duì)業(yè)務(wù)無(wú)入侵缀雳,但是反過(guò)來(lái)看本系統(tǒng)依賴于上游數(shù)據(jù),上游數(shù)據(jù)發(fā)生變化時(shí)如何做到影響最猩揖Α肥印?

未來(lái)會(huì)繼續(xù)從技術(shù)及業(yè)務(wù)兩方面入手,將系統(tǒng)建設(shè)的更加易用绝葡、高效深碱。

歡迎您掃一掃上面的二維碼關(guān)注個(gè)人微信公眾號(hào)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市藏畅,隨后出現(xiàn)的幾起案子敷硅,更是在濱河造成了極大的恐慌,老刑警劉巖愉阎,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绞蹦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡诫硕,警方通過(guò)查閱死者的電腦和手機(jī)坦辟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)章办,“玉大人锉走,你說(shuō)我怎么就攤上這事∨航欤” “怎么了挪蹭?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)休偶。 經(jīng)常有香客問(wèn)我梁厉,道長(zhǎng),這世上最難降的妖魔是什么踏兜? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任尚胞,我火速辦了婚禮,結(jié)果婚禮上迁霎,老公的妹妹穿的比我還像新娘烹看。我一直安慰自己,他們只是感情好疹尾,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布上忍。 她就那樣靜靜地躺著骤肛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪窍蓝。 梳的紋絲不亂的頭發(fā)上腋颠,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音吓笙,去河邊找鬼淑玫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛观蓄,可吹牛的內(nèi)容都是我干的混移。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼侮穿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼歌径!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起亲茅,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤回铛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后克锣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茵肃,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年袭祟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了验残。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巾乳,死狀恐怖您没,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胆绊,我是刑警寧澤氨鹏,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站压状,受9級(jí)特大地震影響仆抵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜种冬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一镣丑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧娱两,春花似錦传轰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至纪挎,卻和暖如春期贫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背异袄。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工通砍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烤蜕。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓封孙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親讽营。 傳聞我的和親對(duì)象是個(gè)殘疾皇子虎忌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 問(wèn)題導(dǎo)讀: flume和kafka整合需要什么組件? flume-conf.properties需要做哪些修改橱鹏? ...
    大時(shí)代_f479閱讀 1,136評(píng)論 0 3
  • 本周在數(shù)據(jù)庫(kù)研發(fā)和運(yùn)營(yíng)組做了關(guān)于ELK的分享膜蠢,這個(gè)分享主要是居于ES部分做的相關(guān)理論和測(cè)試的結(jié)論。下面是對(duì)此次分享...
    飛鴻無(wú)痕閱讀 5,869評(píng)論 0 8
  • 看完了《悲傷逆流成河》莉兰,本來(lái)沒(méi)報(bào)什么期待挑围,結(jié)果卻給了我意外的驚喜。比較難得的有深度且直射社會(huì)現(xiàn)實(shí)的影片糖荒。說(shuō)說(shuō)感悟吧...
    無(wú)心文先森閱讀 188評(píng)論 0 0
  • 活著杉辙,沒(méi)錯(cuò),這是一本書名捶朵。 第一次看這本書是在大二蜘矢。前兩天同學(xué)問(wèn)我,你好像看過(guò)《活著》吧泉孩,那本書講的是什么芭鸲恕?我懵...
    另七01閱讀 240評(píng)論 0 0
  • “我突然覺(jué)得現(xiàn)在的年輕人好難啊【渑纾”正在自主創(chuàng)業(yè)的老同學(xué)發(fā)來(lái)私信感嘆镣典。 同學(xué)所在的公司正在招應(yīng)屆畢業(yè)生,按照現(xiàn)在的市...
    柏木水閱讀 227評(píng)論 0 1