我認(rèn)知中的營(yíng)銷(xiāo)活動(dòng)及其系統(tǒng)
營(yíng)銷(xiāo)活動(dòng)從策劃到落地執(zhí)行,這就需要考慮方方面面的內(nèi)容,有很多細(xì)節(jié)需要注意。那么這篇文章是作者對(duì)上份工作主要內(nèi)容的總結(jié),內(nèi)容包含作者對(duì)營(yíng)銷(xiāo)及營(yíng)銷(xiāo)系統(tǒng)的認(rèn)知方面的相關(guān)積累經(jīng)驗(yàn),涉及產(chǎn)品及技術(shù),希望能給予啟發(fā)。
20年上半年的寫(xiě)的一篇文章,遷移過(guò)來(lái)的,還可以簡(jiǎn)單湊合看,有產(chǎn)品有技術(shù)吧,新的系列正在更新中。
這是一篇大長(zhǎng)文,是對(duì)我上份工作的總結(jié),對(duì)主要工作內(nèi)容的總結(jié)、也是對(duì) “2020技術(shù)驛站” 補(bǔ)交的作業(yè),望前東家前團(tuán)隊(duì)能更好,也祝愿自己在新的環(huán)境中能繼續(xù)滿心歡喜的前行。
18年參加工作,到今年3月底離職,一共歷經(jīng)了1年8個(gè)月的時(shí)間,開(kāi)始的半年做廣告相關(guān)的,之后到離職一直是在做營(yíng)銷(xiāo)活動(dòng)。
第一段工作經(jīng)歷的飛速成長(zhǎng)期就發(fā)生在這段做營(yíng)銷(xiāo)的時(shí)間。運(yùn)氣比較好,遇見(jiàn)了一個(gè)很棒的團(tuán)隊(duì),很棒的leader和師父,也有幸一開(kāi)始就參與了千萬(wàn)峰值的項(xiàng)目,雖然到我們的模塊沒(méi)有那么高,但也是整個(gè)項(xiàng)目的規(guī)模和量級(jí)也是業(yè)內(nèi)很難經(jīng)歷的,也正是這些東西讓我發(fā)現(xiàn)了把一件事做好很難,想做好一件事對(duì)自己技術(shù)底蘊(yùn)、技術(shù)深度;廣度的要求都非常的高。
然后請(qǐng)大家原諒我本文對(duì)營(yíng)銷(xiāo)活動(dòng)類(lèi)系統(tǒng)的以偏概全,內(nèi)容僅僅是我對(duì)營(yíng)銷(xiāo)及營(yíng)銷(xiāo)系統(tǒng)的認(rèn)知及技術(shù)方面的相關(guān)積累。
一、何為營(yíng)銷(xiāo)
入職的第一天,老板就跟我說(shuō),我們是C端的營(yíng)銷(xiāo),但是還挺懵懂的,對(duì)營(yíng)銷(xiāo)基本是一無(wú)所知。在我印象中營(yíng)銷(xiāo)就是銷(xiāo)售人員的各種推銷(xiāo)說(shuō)辭和各種app 上的push,直到現(xiàn)在才有了一點(diǎn)基礎(chǔ)的認(rèn)知,當(dāng)然啦,一年多的經(jīng)歷,我的見(jiàn)解也大概率是片面的,大家就這么一看。
指企業(yè)發(fā)現(xiàn)或發(fā)掘準(zhǔn)消費(fèi)者需求,讓消費(fèi)者了解該產(chǎn)品進(jìn)而購(gòu)買(mǎi)該產(chǎn)品的過(guò)程。
營(yíng)銷(xiāo)學(xué)關(guān)于企業(yè)如何發(fā)現(xiàn)、創(chuàng)造和交付價(jià)值以滿足一定目標(biāo)市場(chǎng)的需求,同時(shí)獲取利潤(rùn)的學(xué)科。
上面是對(duì)營(yíng)銷(xiāo)常見(jiàn)的兩個(gè)定義,個(gè)人而言比較認(rèn)可的是第二種。以市場(chǎng)需求為目標(biāo),發(fā)現(xiàn)、創(chuàng)造和交付價(jià)值,從而獲取利潤(rùn)。市場(chǎng)需求實(shí)際上是公司的業(yè)務(wù)范疇,發(fā)現(xiàn)、創(chuàng)造和交付價(jià)值通常是挖掘用戶需求并刺激使用的過(guò)程。而作為營(yíng)銷(xiāo)人員的我們要做的就是根據(jù)公司業(yè)務(wù)范疇,通過(guò)某些形式進(jìn)行獲客;經(jīng)營(yíng),刺激用戶使其發(fā)生交易行為,從而產(chǎn)生利潤(rùn)。
這里的某些形式,也就是我們核心的關(guān)注點(diǎn)了。
二、無(wú)法吃透所有領(lǐng)域的營(yíng)銷(xiāo)
營(yíng)銷(xiāo)的業(yè)務(wù)場(chǎng)景十分的多,某兩大手機(jī)廠商門(mén)前兩個(gè)卡通人物的互動(dòng)、電視上插播的洗發(fā)水廣告、春晚的搖一搖、朋友圈的明星推廣、購(gòu)物支付時(shí)的返現(xiàn)和優(yōu)惠券,這些都是在不同領(lǐng)域下的不同形式的營(yíng)銷(xiāo)手段。
而每個(gè)領(lǐng)域都有自己專(zhuān)屬的特點(diǎn),我們無(wú)法照搬或者復(fù)制方案,需要具體業(yè)務(wù)具體分析。
至于本文要講的線上營(yíng)銷(xiāo),毫不夸張的說(shuō)互聯(lián)網(wǎng)目前涉及到哪些領(lǐng)域,就有哪些領(lǐng)域的營(yíng)銷(xiāo),電商、醫(yī)療、教育、金融、游戲;文娛等等。每個(gè)領(lǐng)域都有自己特有的盈利方式,面向人群的行為屬性差異也非常大,這就導(dǎo)致?tīng)I(yíng)銷(xiāo)的方式都差異較大。
我們需要做的實(shí)際上是:掌握營(yíng)銷(xiāo)的核心思想;本質(zhì),洞察業(yè)務(wù)特點(diǎn)以此構(gòu)建營(yíng)銷(xiāo)模型,對(duì)營(yíng)銷(xiāo)模型進(jìn)行多樣化的落地實(shí)現(xiàn),從而最大力度刺激用戶。
對(duì)我個(gè)人而言,接觸也相對(duì)較窄,除了自己親自實(shí)踐的信貸領(lǐng)域,其他的也都是來(lái)自間接經(jīng)驗(yàn),但不妨礙對(duì)營(yíng)銷(xiāo)有一個(gè)較深刻的理解。
三、線上營(yíng)銷(xiāo)的落地
上面提到了“通過(guò)某些形式進(jìn)行獲客;經(jīng)營(yíng)”、“構(gòu)建營(yíng)銷(xiāo)模型,對(duì)營(yíng)銷(xiāo)模型進(jìn)行多樣化的落地實(shí)現(xiàn)”,對(duì)于互聯(lián)網(wǎng)行業(yè)來(lái)說(shuō)落地的方式有很多,常見(jiàn)的有廣告營(yíng)銷(xiāo)、營(yíng)銷(xiāo)活動(dòng)等,通常來(lái)說(shuō)這些都是柔和在一起進(jìn)行的,比如投放一個(gè)營(yíng)銷(xiāo)活動(dòng)的廣告。
廣告方面就是在信息流中根據(jù)不同的人群屬性投放對(duì)應(yīng)的物料,或者通過(guò)有影響力的事或人代言產(chǎn)品并在高曝光的場(chǎng)合出現(xiàn),對(duì)于信息流來(lái)說(shuō)就是買(mǎi)流量,通過(guò)自己的DSP系統(tǒng)或者第三方流量買(mǎi)賣(mài)系統(tǒng)進(jìn)行競(jìng)價(jià)投放。
營(yíng)銷(xiāo)活動(dòng)通常是結(jié)合產(chǎn)品流程,以“小游戲”、“優(yōu)惠刺激”等方式,利用人們的貪心/好奇心等若干心理來(lái)構(gòu)成的營(yíng)銷(xiāo)方式。大家感觸最深的應(yīng)該是“幫我砍一刀”吧。而這些營(yíng)銷(xiāo)活動(dòng)通常是基于背后的權(quán)益系統(tǒng)(優(yōu)惠券、紅包等)、觸達(dá)系統(tǒng)(push、短信等)、活動(dòng)流程系統(tǒng)(規(guī)則引擎、基礎(chǔ)活動(dòng)單元等)、支撐性組件、算法平臺(tái)等來(lái)共同構(gòu)建出來(lái)的。
而面向活動(dòng)的營(yíng)銷(xiāo)系統(tǒng),就是本文要闡述的重點(diǎn)了。
四、詳細(xì)說(shuō)說(shuō)活動(dòng)
這里的活動(dòng)具體指的就是上面所提到的營(yíng)銷(xiāo)活動(dòng)。
活動(dòng)實(shí)質(zhì)上就是在時(shí)間、場(chǎng)景、成本限制下,對(duì)不同用戶根據(jù)不同規(guī)則進(jìn)行權(quán)益投放,以達(dá)到獲客、經(jīng)營(yíng)、品牌傳播等目的最終構(gòu)成交易的行為。
雖然最終目的都是賺錢(qián),但中間階段的目標(biāo)是不同的(對(duì)于打工仔來(lái)說(shuō)就是KPI不同),也就促成了各種各樣的活動(dòng)形式:
通常有離線觸達(dá)類(lèi)刺激復(fù)購(gòu)和獲客、常規(guī)流程內(nèi)補(bǔ)貼提高交易欲望、周期性“游戲”類(lèi)提升用戶活躍度的經(jīng)營(yíng)or獲客目的、大型營(yíng)銷(xiāo)活動(dòng)的品牌宣傳獲客。
2. 常規(guī)離線觸達(dá)活動(dòng)
對(duì)于常規(guī)的離線觸達(dá)類(lèi)活動(dòng),目的基本是刺激復(fù)購(gòu)或獲客。
這種活動(dòng)通常分為兩類(lèi):
(1)干巴巴的文字游戲
這種活動(dòng)形式較為簡(jiǎn)單,一般通過(guò)“誘惑性“、”誤導(dǎo)性“,利用人們的”貪心“心理玩文字游戲,進(jìn)行獲客和經(jīng)營(yíng)行為,說(shuō)實(shí)話就是一種合法的”短信詐騙“,通常是廣撒網(wǎng)的形式。
隨著各種營(yíng)銷(xiāo)短信的爆炸式增長(zhǎng),這種方式基本沒(méi)有太大的效果,但礙于成本低基數(shù)大,也是一種常規(guī)存在的形式。
(2)濕漉漉的文字游戲
這部分通常是真正的結(jié)合一些優(yōu)惠活動(dòng),直接給予用戶一些優(yōu)惠券,或者引導(dǎo)用戶參與活動(dòng)。這種形式通常為流程內(nèi)補(bǔ)貼或者游戲類(lèi)活動(dòng)的附屬子活動(dòng),作為宣傳的推銷(xiāo)的作用。
這種活動(dòng)其中涉及的到的技術(shù):(后面會(huì)詳細(xì)的進(jìn)行介紹)
- 觸達(dá)平臺(tái):通常包含文案模版的配置管理、內(nèi)容發(fā)送控制等(主要為對(duì)接各大電信運(yùn)營(yíng)商平臺(tái)、內(nèi)部push平臺(tái)、公眾號(hào)平臺(tái)等)
- 算法平臺(tái):稍微高級(jí)一點(diǎn)的觸達(dá)平臺(tái)定義好模版后,有一些關(guān)鍵字和語(yǔ)句是可以通用戶喜好進(jìn)行填充的,效果更佳。
- 短鏈服務(wù):一個(gè)1k的鏈接毫無(wú)疑問(wèn)是不適合進(jìn)行投放的,大多是通過(guò)短鏈服務(wù)進(jìn)行鏈接的精簡(jiǎn)來(lái)進(jìn)行投放。
3. 常規(guī)產(chǎn)品流程內(nèi)補(bǔ)貼
我們的產(chǎn)品,從用戶遇見(jiàn),到開(kāi)始使用,再到發(fā)生交易通常是擁有一個(gè)漫長(zhǎng)的流程的。
拿購(gòu)物來(lái)講:
看到某app的廣告,不小心點(diǎn)擊去,下載、注冊(cè)登陸、點(diǎn)擊產(chǎn)品、加入購(gòu)物車(chē)、提交訂單、綁定銀行卡、喚起收銀臺(tái)、完成支付、點(diǎn)擊評(píng)價(jià)、后期查看。
每一個(gè)環(huán)節(jié)都可能面臨用戶的流失,尤其是前幾步代價(jià)較高的;用戶不熟悉的階段,毫無(wú)疑問(wèn)在獲客之后,如何推進(jìn)流程、如何促使復(fù)購(gòu),每一個(gè)環(huán)節(jié)都是不可忽略的,所以我們通常需要對(duì)每個(gè)節(jié)點(diǎn)進(jìn)行刺激,刺激的大了成本不夠、刺激的小沒(méi)有用、不對(duì)口味沒(méi)有用。
這就要求我們需要建立在每一個(gè)操作環(huán)節(jié)建立營(yíng)銷(xiāo)行為,并且根據(jù)環(huán)節(jié)特點(diǎn)和不同人群定制營(yíng)銷(xiāo)手段和激勵(lì)措施。比如說(shuō)“綁卡返現(xiàn)”、“購(gòu)物給券”、“登陸有禮”、“再購(gòu)更便宜”等很多惡心的措施。
對(duì)于我們系統(tǒng)而言,產(chǎn)品流程高度業(yè)務(wù)可配變的十分的重要,對(duì)應(yīng)背后的流程編排引擎要求較高。
對(duì)營(yíng)銷(xiāo)系統(tǒng)而言,需要能簡(jiǎn)單配置可上線的簡(jiǎn)單激勵(lì)活動(dòng),背后需要更多的活動(dòng)單元、更靈活的規(guī)則引擎。
4. 周期性“游戲”類(lèi)活動(dòng)
這類(lèi)活動(dòng)較前幾種而言,活動(dòng)的存在感更強(qiáng)了,有用戶感知更深刻的活動(dòng)形式,比如說(shuō)邀請(qǐng)得獎(jiǎng)勵(lì)、購(gòu)物得抽獎(jiǎng)機(jī)會(huì)、集卡贏大獎(jiǎng)等等。
這類(lèi)活動(dòng)一般有一整套的活動(dòng)規(guī)則,也會(huì)有大部分用戶樂(lè)在其中“薅羊毛”(這類(lèi)活動(dòng)有羊毛,但是實(shí)際上不多),通常是小恩小惠用于提升產(chǎn)品活躍度的,像是分享、邀請(qǐng)等功能通常也會(huì)有一定的獲客效果。
這類(lèi)活動(dòng)的活動(dòng)形式:
闖關(guān)小游戲、搖一搖、紅包雨抽獎(jiǎng)、集卡、戰(zhàn)隊(duì)比拼等,對(duì)于我們的系統(tǒng)而言對(duì)應(yīng)的通常是:任務(wù)系統(tǒng)、簽到系統(tǒng)、抽獎(jiǎng)系統(tǒng)、邀請(qǐng)關(guān)系系統(tǒng)、用戶代幣系統(tǒng)、價(jià)值交換系統(tǒng)等基礎(chǔ)活動(dòng)單元。偶爾會(huì)加上活動(dòng)編排引擎涉及1-2個(gè)基礎(chǔ)單元等。
5. 大型營(yíng)銷(xiāo)活動(dòng)
這種活動(dòng)重在品牌推廣和新業(yè)務(wù)獲客,最常見(jiàn)的有央視春晚歷年的活動(dòng)、某熱播節(jié)日活動(dòng)、自造節(jié)大促活動(dòng)等,這個(gè)大家應(yīng)該都有所感知,也都沒(méi)少剁手也沒(méi)少轉(zhuǎn)發(fā)。當(dāng)然啦,這類(lèi)活動(dòng)是最適合薅羊毛的,通常來(lái)說(shuō)是真有東西的,有一點(diǎn)技術(shù)基礎(chǔ)的同學(xué)現(xiàn)在就可以動(dòng)手啦,馬甲號(hào)用起來(lái)積少成多~
從技術(shù)角度來(lái)看,這類(lèi)活動(dòng)都較為復(fù)雜,針對(duì)預(yù)熱期、白熱期、冷卻器都有不同的活動(dòng)形式存在,但這些形式是作為一個(gè)活動(dòng)整體存在的。通常能把我們現(xiàn)有組件的能力都給用上,所以就不一一列舉可能用到的系統(tǒng)啦。
在技術(shù)特點(diǎn)上具有:活動(dòng)邏輯復(fù)雜、性能要求較高、資損風(fēng)險(xiǎn)較大、數(shù)據(jù)分析困難等特點(diǎn)。
這類(lèi)活動(dòng)是對(duì)于營(yíng)銷(xiāo)系統(tǒng)最大的挑戰(zhàn),很多的降級(jí)措施、應(yīng)急預(yù)案、性能調(diào)優(yōu)其實(shí)都是對(duì)這類(lèi)活動(dòng)特殊準(zhǔn)備的。
五、營(yíng)銷(xiāo)系統(tǒng)設(shè)計(jì)的問(wèn)題域
1. 需求特點(diǎn)
上面著重說(shuō)了常見(jiàn)的營(yíng)銷(xiāo)活動(dòng)類(lèi)型,粗略介紹了面向的場(chǎng)景。如果大家經(jīng)常使用一個(gè)產(chǎn)品或者關(guān)注一個(gè)產(chǎn)品,就會(huì)發(fā)現(xiàn)各類(lèi)營(yíng)銷(xiāo)活動(dòng)層出不窮,每個(gè)細(xì)節(jié)都是營(yíng)銷(xiāo)的樣子,幾乎每天看都會(huì)有新的不同。
這種直觀感受側(cè)面反映出營(yíng)銷(xiāo)活動(dòng)相關(guān)需求的特點(diǎn):
- 需求量無(wú)比巨大,且多變
- 時(shí)間緊急,倒排需求通常占80%以上
面對(duì)這樣的情況,增加人力;臨時(shí)借調(diào),是一種解決方案,但也只能算是下策,不可能為營(yíng)銷(xiāo)投入50%以上的人力(但是我感覺(jué)pdd可能是50%以上,也可能是營(yíng)銷(xiāo)系統(tǒng)已經(jīng)非常成熟),臨時(shí)借調(diào)研發(fā)效率、質(zhì)量等都有不小的風(fēng)險(xiǎn)。
作為一個(gè)技術(shù)人員,我們要做的就是“以技術(shù)手段解決工程效率問(wèn)題”,這就要求我們能需要做一種功能豐富且更加靈活易用營(yíng)銷(xiāo)系統(tǒng),來(lái)達(dá)到小需求簡(jiǎn)單配置可上線,大活動(dòng)釋放降低80%以上的人力成本的目的。
2. 技術(shù)特點(diǎn)
(1)性能要求較高(成敗往往就在峰值)
營(yíng)銷(xiāo)活動(dòng)的訪問(wèn)量通常較大,而且峰值突出。拿春晚活動(dòng)、娛樂(lè)節(jié)目來(lái)說(shuō),通常是伴隨口播等引導(dǎo)動(dòng)作帶領(lǐng)用戶參與的,80%的用戶都會(huì)集中在那一分鐘左右涌入,而只是依賴(lài)于加機(jī)器是不現(xiàn)實(shí)的,降級(jí)限流等只會(huì)白白浪費(fèi)流量并且造成負(fù)面營(yíng)銷(xiāo),營(yíng)銷(xiāo)大促場(chǎng)景下,我們需要的就是抗。
3. 安全及風(fēng)險(xiǎn)
上面頻頻提到了薅羊毛,這其實(shí)就是營(yíng)銷(xiāo)系統(tǒng)面臨的非常重要的一個(gè)問(wèn)題:資損。
資損的來(lái)源通常有活動(dòng)設(shè)計(jì)、代碼實(shí)現(xiàn)、羊毛黨的大量存在等多方面的原因,尤其是在這樣的需求特點(diǎn)及大環(huán)境因素下,營(yíng)銷(xiāo)系統(tǒng)是一個(gè)極易發(fā)生資損的點(diǎn)。
下面就來(lái)看一下是如何用技術(shù)的手段解決上述問(wèn)題,及其中核心系統(tǒng);組件的實(shí)現(xiàn)原理。
六、我認(rèn)為營(yíng)銷(xiāo)系統(tǒng)的樣子
先看一下上面提到的兩個(gè)概念或者說(shuō)實(shí)體:
- 營(yíng)銷(xiāo):營(yíng)銷(xiāo)學(xué)關(guān)于企業(yè)如何發(fā)現(xiàn)、創(chuàng)造和交付價(jià)值以滿足一定目標(biāo)市場(chǎng)的需求,同時(shí)獲取利潤(rùn)的學(xué)科。
- 活動(dòng):在時(shí)間、場(chǎng)景、成本限制下,對(duì)不同用戶根據(jù)不同規(guī)則進(jìn)行權(quán)益投放,以達(dá)到獲客、經(jīng)營(yíng)、品牌傳播等目的最終構(gòu)成交易的行為。
然后結(jié)合業(yè)務(wù)領(lǐng)域,根據(jù)營(yíng)銷(xiāo)場(chǎng)景下的問(wèn)題域(現(xiàn)在;將來(lái)),通過(guò)技術(shù)手段解決效率;質(zhì)量問(wèn)題,以此最終確定系統(tǒng)的職責(zé)、定位及內(nèi)部架構(gòu)。
這一板塊的內(nèi)容十分龐大。
1. 聊一下方案選擇
對(duì)于方案的選擇通常有這么幾個(gè)標(biāo)準(zhǔn):人力成本、研發(fā)質(zhì)量成本、研發(fā)效率成本、機(jī)器成本。
一個(gè)系統(tǒng)方案的實(shí)現(xiàn),最優(yōu)的是人力、機(jī)器投入較少的情況下,能夠確保質(zhì)量的最快支持需求。
對(duì)于營(yíng)銷(xiāo)類(lèi)系統(tǒng)來(lái)說(shuō)就是:
建設(shè)非常通用且高性能的基礎(chǔ)設(shè)施組件,實(shí)現(xiàn)相對(duì)通用的系統(tǒng)支持常規(guī)迭代,緊急且重大的需求依賴(lài)基礎(chǔ)設(shè)施進(jìn)行特化實(shí)現(xiàn)。
像支付域、廣告域的這些系統(tǒng),面對(duì)的需求雖然也不少但是主要邏輯是確定的,一般都是對(duì)鏈路、功能進(jìn)行豐富和優(yōu)化。而營(yíng)銷(xiāo)場(chǎng)景下的需求講真的,千奇百怪,除了上述所說(shuō)的一些固定類(lèi)型的活動(dòng)形式及基礎(chǔ)的活動(dòng)單元,很多時(shí)候伴隨運(yùn)營(yíng)的臨時(shí)且全新的想法,我們需要面臨決策,全新臨時(shí)方案 or 通用解決方案的抉擇。
通用的系統(tǒng)這個(gè)大家都能接受,但對(duì)于當(dāng)前所要實(shí)現(xiàn)的邏輯顯然不能復(fù)用的情況,我的建議是采用全新的臨時(shí)方案僅依賴(lài)基礎(chǔ)組件,新的數(shù)據(jù)存儲(chǔ)、新的server,一切只為解決當(dāng)前臨時(shí)需求。因?yàn)榫惋L(fēng)險(xiǎn)和成本來(lái)說(shuō),實(shí)現(xiàn)一個(gè)臨時(shí)方案相對(duì)于改一個(gè)相對(duì)復(fù)雜的系統(tǒng)要簡(jiǎn)單的多,并且風(fēng)險(xiǎn)完全收斂,我們也能集中精力解決當(dāng)前問(wèn)題,而不是竭盡所能把系統(tǒng)建設(shè)的啥都可配制化,看似系統(tǒng)牛逼,但為了暫時(shí)的需求,投入產(chǎn)出比太低。
營(yíng)銷(xiāo)場(chǎng)景下永遠(yuǎn)都有臨時(shí)且重大的需求,我們要做的是成本投入較小的情況下快速迭代。
2. 營(yíng)銷(xiāo)系統(tǒng)架構(gòu)
系統(tǒng)功能:
- 對(duì)業(yè)務(wù)系統(tǒng)或直接對(duì)用戶提供營(yíng)銷(xiāo)能力輸出
- 向業(yè)務(wù)方提供營(yíng)銷(xiāo)業(yè)務(wù)的配置化能力
- 提供效果洞察、成本、資損監(jiān)控能力
理想目標(biāo):
常規(guī)活動(dòng)配置化可上線,大型活動(dòng)節(jié)省80%以上成本。
活動(dòng)效果可洞察,資損及故障易發(fā)現(xiàn)。
系統(tǒng)架構(gòu):
活動(dòng)流程層主要為構(gòu)建實(shí)現(xiàn)營(yíng)銷(xiāo)活動(dòng)流程實(shí)現(xiàn)能力的標(biāo)準(zhǔn)化輸出,以活動(dòng)單元能力或活動(dòng)組件基礎(chǔ)能力為原子單位,進(jìn)行活動(dòng)流程編排。
- 活動(dòng)單元層:提供常用營(yíng)銷(xiāo)活動(dòng)的能力(比如抽獎(jiǎng)、秒殺、邀請(qǐng)),每個(gè)單元面向一類(lèi)營(yíng)銷(xiāo)形式,對(duì)外暴露標(biāo)準(zhǔn)接口。內(nèi)部依賴(lài)于活動(dòng)組件。
- 活動(dòng)組件:提供標(biāo)準(zhǔn)的單一的營(yíng)銷(xiāo)功能(簽到、分享)或業(yè)務(wù)能力(價(jià)值交換、標(biāo)簽輸出)或系統(tǒng)能力(調(diào)度組件、權(quán)益高效發(fā)放)等。
- 權(quán)益系統(tǒng):主要包含業(yè)務(wù)場(chǎng)景下內(nèi)部權(quán)益、現(xiàn)金權(quán)益、外部權(quán)益,提供權(quán)益的實(shí)際發(fā)放、核銷(xiāo)能力。
- 數(shù)據(jù)處理:主要針對(duì)數(shù)據(jù)庫(kù)(mysql、redis)、日志數(shù)據(jù)等數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化處理,為監(jiān)控、數(shù)據(jù)一致性提供數(shù)據(jù)源
- 監(jiān)控方面:對(duì)業(yè)務(wù)方提供可視化、標(biāo)準(zhǔn)化的效果展示,及資損監(jiān)控;系統(tǒng)監(jiān)控等能力。
- 對(duì)賬補(bǔ)單:提供數(shù)據(jù)一致性的最后一層保障。
3. 常用組件
要開(kāi)始深入技術(shù)細(xì)節(jié)啦,這塊內(nèi)容背后的知識(shí)體系基本就是我這1年8個(gè)月的基礎(chǔ)技術(shù)能力的成長(zhǎng)了,選幾個(gè)具有代表性的組件來(lái)說(shuō)。
(1)唯一單號(hào)服務(wù)
這個(gè)組件非常非常重要,所以會(huì)說(shuō)的相對(duì)仔細(xì)。
在繁多的業(yè)務(wù)場(chǎng)景下n多系統(tǒng)的交互場(chǎng)景下,我們通常需要一個(gè)唯一id來(lái)作冪等處理,同時(shí)海量的數(shù)據(jù)(DB、log等)我們也需要一個(gè)唯一單號(hào)作為線索完成高效的數(shù)據(jù)分析工作,所以說(shuō)每個(gè)請(qǐng)求、每個(gè)環(huán)節(jié)我們都是需要唯一id的。
看到上述背景,不難想到唯一單號(hào)服務(wù)所面臨的核心問(wèn)題
功能性要求:
- 唯一性保障
- 業(yè)務(wù)相關(guān)性且安全
系統(tǒng)要求:
- 高性能
- 高可用
這四點(diǎn)即是難點(diǎn),也是唯一單號(hào)的特征。
唯一單號(hào)服務(wù)的實(shí)現(xiàn)方案有很多種,最常見(jiàn)的有自增鍵、UUID、雪花算法、Leaf-segment三種方案。
(2)自增鍵
利用自增鍵是最容易想到的一種方式,實(shí)現(xiàn)方式通常有mysql主鍵自增、redis incr。但這兩種方式很顯然都會(huì)存在單點(diǎn)的問(wèn)題,而且自增主鍵性能受限、redis 易發(fā)生數(shù)據(jù)丟失(性能只是相對(duì)mysql更好),但實(shí)現(xiàn)大學(xué)作業(yè)的時(shí)候還是可以用的,真實(shí)生產(chǎn)環(huán)境是肯定不會(huì)選用的。
(3)uuid
UUID(Universally Unique Identifier)的標(biāo)準(zhǔn)型式包含32個(gè)16進(jìn)制數(shù)字,以連字號(hào)分為五段,形式為xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx的36個(gè)字符,具體標(biāo)準(zhǔn)可見(jiàn):http://www.ietf.org/rfc/rfc4122.txt(墻),目前業(yè)界有5種常用的生成uuid的方式。
這種方式優(yōu)點(diǎn)是性能高,純本地生成,無(wú)網(wǎng)絡(luò)IO發(fā)生。
缺點(diǎn)也很突出:
存儲(chǔ)方面:
- 不易存儲(chǔ)(實(shí)在太長(zhǎng)了)
- 這類(lèi)id由于通常要落庫(kù)并掛索引,對(duì)于mysql來(lái)講,UUID的無(wú)序性會(huì)使數(shù)據(jù)位置頻繁變動(dòng),嚴(yán)重影響性能,尤其是作為主鍵的情況下(主鍵越短越好)
業(yè)務(wù)相關(guān)安全性:
- 最常用的基于mac地址生成的方式會(huì)暴露mac。
- 無(wú)任何業(yè)務(wù)標(biāo)示,排查問(wèn)題和統(tǒng)計(jì)時(shí)十分不便。
(4)雪花算法
雪花算法最初是推特用于標(biāo)記消息的,跟uuid結(jié)構(gòu)類(lèi)似,通過(guò)劃分命名空間實(shí)現(xiàn),基于時(shí)間戳+機(jī)器碼+業(yè)務(wù)標(biāo)示實(shí)現(xiàn),這種方式極易橫向擴(kuò)展,由于是本地生成,且每臺(tái)機(jī)器碼值都不同,可用性和性能都得到了保證。并且靈活的結(jié)構(gòu)添加業(yè)務(wù)標(biāo)示也變的輕松了許多。
實(shí)現(xiàn)方式與uuid相似,雖然相對(duì)提及會(huì)小一些,存儲(chǔ)方面的問(wèn)題稍微得到緩解。
但是有一個(gè)很?chē)?yán)重的風(fēng)險(xiǎn)點(diǎn),一旦發(fā)生時(shí)鐘回?fù)?,那就很慘了,mongoDB使用的就是這樣方式。
(5)Leaf-segment
這種方式是我除雪花算法外最看好的實(shí)現(xiàn)方式,依賴(lài)于mysql存儲(chǔ)保證數(shù)據(jù)不丟,并且利用行鎖保證單調(diào)遞增,一張表維護(hù)多個(gè)活動(dòng)的id,通過(guò)異步化的方式批量批發(fā)單號(hào)對(duì)外提供服務(wù)保證性能,多個(gè)單號(hào)批發(fā)商對(duì)外提供服務(wù)并容忍單號(hào)浪費(fèi)以此保證可用性。
這段話可能說(shuō)不明白直接看代碼和圖:
`activity_id` bigint(20) NOT NULL AUTO_INCREMENT,
`activity_name` varchar(512) NOT NULL,
`sn` bigint(20) NOT NULL DEFAULT ‘0’,
`step` bigint(20) NOT NULL DEFAULT ‘10000’,
/**
* 每次批發(fā)時(shí):
* 1、返回sn ~ maxSn(sn + step) (就是所批發(fā)走的號(hào)段)
* 2、sn = sn + step + 1
* 提供服務(wù)時(shí):
* 內(nèi)存中輸出小于maxSn的sn,并對(duì)sn++即可
**/
mysql可以只用一個(gè),通常來(lái)說(shuō)內(nèi)存中大量的號(hào)段足以支撐mysql恢復(fù),如果想用多個(gè)mysql同樣需要進(jìn)行劃分命名空間。
(6)規(guī)則引擎
在任何配置化的場(chǎng)景下規(guī)則引擎都是核心的存在,通常來(lái)說(shuō)表達(dá)式在可視化的配置化后臺(tái),結(jié)合配置模版+配置元數(shù)據(jù)編譯成“規(guī)則”,規(guī)則在執(zhí)行時(shí)被翻譯成表達(dá)式或者執(zhí)行從而達(dá)到業(yè)務(wù)邏輯可編排,決策邏輯可配制的作用。
規(guī)則引擎一抓一大把,大家自行百度即可。
基礎(chǔ)的規(guī)則引擎中表達(dá)式的生成與解釋也是營(yíng)銷(xiāo)場(chǎng)景非常常用的,比如波蘭表達(dá)式等,涉及標(biāo)簽的地方就大概率涉及波蘭表達(dá)式。
(7)價(jià)值交換組件
這里的價(jià)值交換組件指的是營(yíng)銷(xiāo)場(chǎng)景下,營(yíng)銷(xiāo)活動(dòng)系統(tǒng)中各種“積分”、“代幣”、“機(jī)會(huì)”等價(jià)值載體的交換體系,不同的活動(dòng)單元中所使用的價(jià)值載體是不同的,要串聯(lián)幾個(gè)組件完成整個(gè)“大活動(dòng)”的正常運(yùn)作,出上層的規(guī)則引擎外,更重要的就是不同價(jià)值載體之間的轉(zhuǎn)換,比如說(shuō)“抽獎(jiǎng)機(jī)會(huì)”<——>”任務(wù)積分”<——>”權(quán)益”。
價(jià)值交換組件的場(chǎng)景更像是一種存在匯率的轉(zhuǎn)賬系統(tǒng)(但是相對(duì)轉(zhuǎn)賬來(lái)說(shuō),要簡(jiǎn)單的多,通常是單向并不可退的,僅僅作為系統(tǒng)邏輯轉(zhuǎn)換的內(nèi)部存在)。
可以簡(jiǎn)單看一下價(jià)值交換組件的內(nèi)部實(shí)現(xiàn):
cache、異步記賬等存粹為了性能,其中最核心的點(diǎn)就是數(shù)據(jù)一致性問(wèn)題,這個(gè)點(diǎn)會(huì)在后面單獨(dú)介紹。
(8)用戶標(biāo)簽體系
用戶標(biāo)簽通常分為用戶實(shí)時(shí)業(yè)務(wù)狀態(tài)標(biāo)簽、用戶畫(huà)像特征標(biāo)簽兩種。實(shí)時(shí)業(yè)務(wù)特征通常來(lái)源于實(shí)時(shí)業(yè)務(wù)系統(tǒng)的接口或者DB,而用戶畫(huà)像特征標(biāo)簽這個(gè)通常是算法平臺(tái)提供,用戶標(biāo)簽所要承受的qps數(shù)是除唯一單號(hào)服務(wù)外最大的,所以通常性能要求高(承載qps量大、耗時(shí)短),但可用性要求倒是沒(méi)那么高。(一個(gè)合理的系統(tǒng),在不知道用戶信息的情況下也應(yīng)該能正常作出兜底反應(yīng)的)
通常來(lái)說(shuō),我認(rèn)為一個(gè)合理的在線標(biāo)簽系統(tǒng)是這樣的:
單獨(dú)具有流量控制功能,保證大部分流量可用,降級(jí)掉一部分請(qǐng)求,對(duì)常用的標(biāo)簽進(jìn)行緩存控制<標(biāo)簽key,用戶id,統(tǒng)一有效時(shí)間>,根據(jù)需要獲取可接受時(shí)間范圍內(nèi)用戶標(biāo)簽。
未命中緩存的標(biāo)簽,交由標(biāo)簽任務(wù)管理器進(jìn)行處理,決定單個(gè)標(biāo)簽處理最大時(shí)長(zhǎng)、標(biāo)簽并行;串行處理機(jī)制及處理順序、處理任務(wù)調(diào)度等,底層維護(hù)并發(fā)模型。(線程數(shù)、任務(wù)存放機(jī)制等)
再下一層,維護(hù)對(duì)外部接口、業(yè)務(wù)數(shù)據(jù)或接口、用戶畫(huà)像數(shù)據(jù)的處理單元。
(9)短鏈服務(wù)
上文在觸達(dá)單元中就提到了短鏈服務(wù),首先業(yè)務(wù)常見(jiàn)、技術(shù)特點(diǎn)鮮明,所以單獨(dú)拿出來(lái)說(shuō)了。
短鏈服務(wù)的應(yīng)用場(chǎng)景非常多,除了短信中的鏈接,平日里的鏈接分享、網(wǎng)頁(yè)分享、二維碼分享其實(shí)斗志這種方式,只是表現(xiàn)形式不同而已。
短鏈接實(shí)現(xiàn)思路很簡(jiǎn)單:
找一個(gè)短鏈接試試看:3.cn/j/10nd-pE9
至于這里為什么用的是302而不是301,是因?yàn)榕R時(shí)重定向時(shí)能夠統(tǒng)計(jì)到短鏈接點(diǎn)擊次數(shù),通常也會(huì)被用作效果分析。用301永久重定向也是可以的。
至于后面“10nd-pE9”這個(gè)碼,通常被稱(chēng)為短碼,生成方式有很多種,比如上面提到的唯一單號(hào),還有就是摘要法(存在小概率重復(fù)的可能性,但能夠保證鏈接夠短)。
如果是小型企業(yè)大可以利用現(xiàn)成的短鏈服務(wù)提供商,比如百度的:https://dwz.cn/
4. 基礎(chǔ)活動(dòng)單元
抽獎(jiǎng)活動(dòng)單元將常見(jiàn)的活動(dòng)形式進(jìn)行了一定程度上的抽象,做了通用化處理,以應(yīng)對(duì)其高頻的需求。這里拿幾個(gè)經(jīng)典的活動(dòng)形式進(jìn)行闡述。
活動(dòng)單元的建立,可以根據(jù)具體的業(yè)務(wù)場(chǎng)景下的各種運(yùn)營(yíng)的需求來(lái)進(jìn)行拆分抽象。
(1)談?wù)劤楠?jiǎng)
拿抽獎(jiǎng)來(lái)說(shuō),搖一搖是抽獎(jiǎng),九宮格轉(zhuǎn)盤(pán)是抽獎(jiǎng),n選一砸金蛋也是抽獎(jiǎng),大家點(diǎn)的火熱朝天的紅包雨其實(shí)也是抽獎(jiǎng),這類(lèi)抽獎(jiǎng)活動(dòng)對(duì)用戶活躍度非常有幫助,用戶分享意愿也很強(qiáng),基本是大型活動(dòng)每次必選的組成部分。所以就完全可以對(duì)其進(jìn)行抽獎(jiǎng)建立一個(gè)通用的抽獎(jiǎng)模型。
整體看下來(lái)一個(gè)抽獎(jiǎng)系統(tǒng)是這樣的:
其中的核心組件有:
1、概率模型
用戶控制用戶中獎(jiǎng)的概率,實(shí)現(xiàn)方式很簡(jiǎn)單:
(1)確定可抽獎(jiǎng)總區(qū)間,確定獎(jiǎng)品區(qū)間段,一次性進(jìn)行抽獎(jiǎng)。
(2)Alias Method
可以直接看這一篇實(shí)現(xiàn):http://www.keithschwarz.com/darts-dice-coins/
大致意思:把N種可能性拼裝成一個(gè)方形(整體),分成N列,每列高度為1且最多兩種可能性,可能性抽象為某種顏色,即每列最多有兩種顏色,且第n列中必有第n種可能性,這里將第n種可能性稱(chēng)為原色。 想象拋出一個(gè)硬幣,會(huì)落在其中一列,并且是落在列上的一種顏色。這樣就得到兩個(gè)數(shù)組:一個(gè)記錄落在原色的概率是多少,記為Prob數(shù)組,另一個(gè)記錄列上非原色的顏色名稱(chēng),記為Alias數(shù)組,若該列只有原色則記為null。
2、抽獎(jiǎng)機(jī)會(huì)控制
提供用戶可抽獎(jiǎng)機(jī)會(huì)的控制,是一種價(jià)值的載體。抽獎(jiǎng)系統(tǒng)對(duì)外暴露次數(shù)增加接口,內(nèi)部抽獎(jiǎng)行為消耗抽獎(jiǎng)次數(shù)。
3、獎(jiǎng)池控制
每個(gè)用戶群面向自己的獎(jiǎng)品集合,高價(jià)值的用戶或者潛在用戶面向價(jià)值較高的獎(jiǎng)品,風(fēng)險(xiǎn)用戶或者下沉用戶面向低價(jià)值的優(yōu)惠券等,就是這么黑。
這里通常依賴(lài)于表達(dá)式引擎,根據(jù)標(biāo)簽計(jì)算用戶所選獎(jiǎng)池。
4、中獎(jiǎng)限制
曾經(jīng)的我也以為獎(jiǎng)可以隨便中,除了面向獎(jiǎng)品集合之外,通常對(duì)用戶會(huì)額外加n多限制條件。
比如說(shuō),a獎(jiǎng)品最多中2次,b獎(jiǎng)品最價(jià)值不能超過(guò)2元,命中iphone大獎(jiǎng)后其他不能再中大獎(jiǎng)并且其他獎(jiǎng)品概率下降。
5、庫(kù)存控制
所有的獎(jiǎng)品都是有成本預(yù)算的,不能無(wú)限制發(fā)放,這就要求對(duì)獎(jiǎng)品進(jìn)行庫(kù)存控制。
這里有一個(gè)設(shè)計(jì)的思路,分別設(shè)置庫(kù)存供應(yīng)量、庫(kù)存消耗量,剩余庫(kù)存=庫(kù)存供應(yīng)量-庫(kù)存消耗量,這樣相對(duì)于拿一個(gè)數(shù)值表示庫(kù)存進(jìn)行增減操作要靈活的多并且安全很多,尤其適合在庫(kù)存增加時(shí)。
另外,庫(kù)存的消耗操作很顯然是一個(gè)存在競(jìng)態(tài)條件的復(fù)合操作,我們需要保證其原子性,可以利用上鎖等措施串行化,也可以利用現(xiàn)有工具的原子能力(比如reids 操作的原子性:incrby、lua等。
(2)裂變營(yíng)銷(xiāo)
這里還有一個(gè)值得提的是列表營(yíng)銷(xiāo),當(dāng)下正火的營(yíng)銷(xiāo)方式,最經(jīng)典的莫過(guò)于“幫我砍一刀”。
分開(kāi)來(lái)看,營(yíng)銷(xiāo)上面說(shuō)過(guò)了,裂變概括來(lái)說(shuō),按生物學(xué)來(lái)說(shuō)是細(xì)胞核的裂變,由一個(gè)裂變成2個(gè),2個(gè)裂變成4個(gè)。換作人來(lái)說(shuō),就是當(dāng)前用戶是否能夠幫忙獲客。
對(duì)于裂變營(yíng)銷(xiāo)而言,通常包含三個(gè)環(huán)節(jié),設(shè)計(jì)裂變流程,裂變流程變?yōu)檗D(zhuǎn)化漏斗,漏斗分析。
裂變營(yíng)銷(xiāo)重在邏輯,性能等要求一般不會(huì)很高。
對(duì)于系統(tǒng)設(shè)計(jì)而言有幾塊格外的重要:
1、底層邀請(qǐng)關(guān)系組件
裂變營(yíng)銷(xiāo)往往是從人出發(fā),以人結(jié)束,造出一顆顆龐大的樹(shù),所以我們需要維護(hù)整個(gè)樹(shù)的結(jié)構(gòu),不僅僅是為了存儲(chǔ)活動(dòng)的邀請(qǐng)記錄供激勵(lì)使用,對(duì)后期判斷“散點(diǎn)”也是尤為重要的。
2、標(biāo)簽組件
活動(dòng)的重心在于拉人,什么樣的人能拉人,是相當(dāng)重要的,要建立與裂變營(yíng)銷(xiāo)關(guān)聯(lián)性很強(qiáng)的人群畫(huà)像標(biāo)簽十分重要。
這塊了解的不多,暫時(shí)就這些~
七、數(shù)據(jù)的一致性處理
數(shù)據(jù)一致性一直是各種系統(tǒng)很頭痛的點(diǎn),尤其是分布式系統(tǒng)越來(lái)越昌盛的今天。數(shù)據(jù)一致性也存在cap、base這樣的著名的理論,實(shí)際上平衡一致性與性能、可用性等特性是需要根據(jù)產(chǎn)品特點(diǎn)來(lái)做的,像跟錢(qián)相關(guān)的一致性要求會(huì)非常的高(不能出錯(cuò)),積分?jǐn)?shù)量這種虛擬權(quán)益類(lèi)其次,簽到記錄等用戶就不太關(guān)心了。
1. 營(yíng)銷(xiāo)場(chǎng)景下的一致性要求
營(yíng)銷(xiāo)場(chǎng)景的數(shù)據(jù)一致性要求其實(shí)是相對(duì)寬松的,只需要在較短的時(shí)間內(nèi)保證最終一致就可以了。
拿抽獎(jiǎng)活動(dòng)舉例,一次抽獎(jiǎng)行為的發(fā)生,涉及到次數(shù)減扣、庫(kù)存減扣、抽獎(jiǎng)記錄更新、獎(jiǎng)品發(fā)放等一系列的操作,很有可能會(huì)發(fā)生部分失敗,按照常理來(lái)說(shuō)像獎(jiǎng)品發(fā)放失敗這樣的情況,短時(shí)間未到賬用戶大概率也是無(wú)感知的,通常需要繞道卡券包等,所以這種情況我們只需要一定時(shí)間段內(nèi)給用戶補(bǔ)上即可,需要保證的主要是和成本密切相關(guān)的次數(shù)、庫(kù)存等。
當(dāng)然啦,一致性要求雖然沒(méi)有那么高,但是還是要盡可能照顧到的,沒(méi)有數(shù)據(jù)一致性的保證,性能、可能性再高的系統(tǒng)可能都是一堆垃圾。
2. 常見(jiàn)的一致性實(shí)現(xiàn)方案
先來(lái)看一下什么是數(shù)據(jù)一致性:數(shù)據(jù)的變更,與現(xiàn)實(shí)世界變更的預(yù)期結(jié)果保持一致。
后來(lái)在這個(gè)基礎(chǔ)上延伸出:
(1)各種一致性4
- 強(qiáng)一致性(也稱(chēng)線性一致性): 任何一次讀都能讀到某個(gè)數(shù)據(jù)的最近一次寫(xiě)的數(shù)據(jù),系統(tǒng)中的所有進(jìn)程,看到的操作順序,都和全局時(shí)鐘下的順序一致。
- 弱一致性:用戶讀到某一操作對(duì)系統(tǒng)特定數(shù)據(jù)的更新需要一段時(shí)間,我們稱(chēng)這段時(shí)間為“不一致性窗口”。
- 最終一致性:是弱一致性的一種特例,保證用戶最終能夠讀取到某操作對(duì)系統(tǒng)特定數(shù)據(jù)的更新。
- 順序一致性:任何一次讀都能讀到某個(gè)數(shù)據(jù)的最近一次寫(xiě)的數(shù)據(jù),系統(tǒng)的所有進(jìn)程的順序一致,而且是合理的。(相對(duì)于強(qiáng)一致性少了系統(tǒng)時(shí)鐘)
事務(wù)的誕生,很大程度上就是為了保證數(shù)據(jù)的一致性。
(2)基礎(chǔ)理論
- cap:指的是在一個(gè)分布式系統(tǒng)中,一致性(Consistency)、可用性(Availability)、分區(qū)容錯(cuò)性(Partition tolerance)只能滿足兩其中兩點(diǎn)。
- base:BASE 是 Basically Available(基本可用)、Soft state(軟狀態(tài))和 Eventually consistent (最終一致性)三個(gè)短語(yǔ)的縮
- 寫(xiě)。BASE理論是對(duì)CAP中AP的一個(gè)擴(kuò)展,保證可用性和分區(qū)容錯(cuò)的情況下,允許存在軟狀態(tài),但會(huì)保證最終一致性。
(3)兩階段提交
這部分理論知識(shí)蠻陳舊的就不展開(kāi)說(shuō)了,大體能懂就好:二階段提交的算法思路可以概括為:
參與者將操作成敗通知協(xié)調(diào)者,再由協(xié)調(diào)者根據(jù)所有參與者的反饋情報(bào)決定各參與者是否要提交操作還是中止操作。
兩階段的缺點(diǎn):
- 同步阻塞問(wèn)題。
- 協(xié)調(diào)者的單點(diǎn)故障問(wèn)題。
- 第二階段執(zhí)行中,協(xié)調(diào)者與參與者共同掛掉的場(chǎng)景導(dǎo)致不一致。
(4)三階段提交
三階段提交協(xié)議在協(xié)調(diào)者和參與者中都引入超時(shí)機(jī)制,并且把兩階段提交協(xié)議的第一個(gè)階段分成了兩步,引入了中間狀態(tài): 詢問(wèn),然后再鎖資源,最后真正提交。
解決了“同步阻塞”、”單點(diǎn)故障“等小缺點(diǎn),及二階段無(wú)法解決的“協(xié)調(diào)者與參與者共同掛掉的場(chǎng)景導(dǎo)致不一致”這個(gè)很重要的問(wèn)題。
說(shuō)實(shí)話不管是兩階段或者三階段,都無(wú)法徹底解決一致性問(wèn)題。
(5)剛性及柔性事務(wù)
- 剛性事務(wù):具備我們熟知的的ACID的特性的事務(wù),通常的實(shí)現(xiàn)有WAL(white ahead log)(這是目前市面上幾乎所有數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方式),還有一種是影子分頁(yè)。
- 柔性事務(wù):基于base理論實(shí)現(xiàn)的追求最終一致性的事務(wù)模型,通常實(shí)現(xiàn)方式包括TCC補(bǔ)償性事務(wù)、異步確保型、最大努力型。
tcc分布式事務(wù)是一種二階段的變種,將操作分為嘗試、提交、撤銷(xiāo),是一種實(shí)時(shí)鏈路上的的操作行為。大致模型是這樣的:事務(wù)發(fā)起者發(fā)起一個(gè)事務(wù),參與者進(jìn)行事務(wù)的提交操作,如果其中幾個(gè)參與者本地事務(wù)失敗,會(huì)告知失敗,其他已提交的參與者事務(wù)進(jìn)行補(bǔ)償操作進(jìn)行回滾。
異步確保型事務(wù)則為將同步阻塞的事務(wù)操作變?yōu)橐徊讲僮鳎苊鈱?duì)數(shù)據(jù)庫(kù)事務(wù)的爭(zhēng)用,對(duì)操作進(jìn)行匯總處理,通常對(duì)于熱點(diǎn)資源的操作采用這種方式。
最大努力型事務(wù),依賴(lài)于補(bǔ)單消息的補(bǔ)償機(jī)制或者重試機(jī)制,對(duì)事務(wù)進(jìn)行最大程度的推進(jìn),以此保證最終一致性。
(6)營(yíng)銷(xiāo)場(chǎng)景下的數(shù)據(jù)一致性設(shè)計(jì)
首先看完上述的上面各種的一致性定義和分布式事務(wù)實(shí)現(xiàn)可以發(fā)現(xiàn),數(shù)據(jù)的一致性實(shí)現(xiàn)是比較困難的,也是業(yè)界一直在尋求最優(yōu)解的問(wèn)題之一,但就目前而言,實(shí)時(shí)鏈路上的各種分布式事務(wù)能保證一定程度上的數(shù)據(jù)一致性,而且通常來(lái)說(shuō)只是局部某個(gè)環(huán)節(jié)(不可能把所有事情都扔進(jìn)事務(wù)里面),并且還會(huì)有一定的瑕疵。
對(duì)于整個(gè)業(yè)務(wù)邏輯推進(jìn)中數(shù)據(jù)一致性的根本保證,還是最原始的:“建立業(yè)務(wù)流轉(zhuǎn)的狀態(tài)機(jī),依賴(lài)于唯一單號(hào),異步對(duì)賬補(bǔ)單,達(dá)到最終一致性”。
對(duì)于營(yíng)銷(xiāo)場(chǎng)景下,性能要求較高,但一致性要求沒(méi)有那么強(qiáng)。
建議的實(shí)現(xiàn)方式有兩種:
- 核心操作采用TCC事務(wù)模型實(shí)現(xiàn),保證核心鏈路上核心數(shù)據(jù)的一致性,對(duì)于附屬操作可通過(guò)異步對(duì)賬補(bǔ)單保證最終的一致性。
- 實(shí)時(shí)鏈路不做分布式事務(wù)處理,完全依賴(lài)于對(duì)賬補(bǔ)單實(shí)現(xiàn)。
每種方式都有自己的優(yōu)缺點(diǎn),第一種方式所需的對(duì)賬補(bǔ)單量級(jí)較小,常見(jiàn)的掉單失敗等在實(shí)時(shí)主鏈路上就給干掉了,對(duì)于數(shù)據(jù)不一致引發(fā)的問(wèn)題的影響時(shí)長(zhǎng)會(huì)減少,但是引入了TCC事務(wù),增加了三方協(xié)調(diào)和更多的網(wǎng)絡(luò)IO,數(shù)據(jù)操作邏輯的復(fù)雜度會(huì)直線上升,性能會(huì)有一定程度的下降,可能會(huì)產(chǎn)生新的風(fēng)險(xiǎn)和問(wèn)題。
而第二種方案,主鏈路代碼精煉,性能會(huì)很好,但對(duì)于數(shù)據(jù)不一致引發(fā)的問(wèn)題的影響時(shí)長(zhǎng)會(huì)較長(zhǎng),并且對(duì)賬補(bǔ)單系統(tǒng)規(guī)模會(huì)變的龐大,要處理的任務(wù)也會(huì)變多。
既然各有優(yōu)缺點(diǎn),我們就需要根據(jù)不同營(yíng)銷(xiāo)場(chǎng)景來(lái)選擇,像是營(yíng)銷(xiāo)組件完全是組件內(nèi)操作本地事務(wù)或者不需要事務(wù)即可解決,對(duì)于常規(guī)活動(dòng)依賴(lài)于活動(dòng)單元組件這些建議使用第一種方案,直接建立較為完備的措施,一勞永逸。而像是性能要求非常高并且邏輯相對(duì)簡(jiǎn)單的臨時(shí)活動(dòng),第二種方案就足夠了,釋放出人力處理性能優(yōu)化。像是非常大型的營(yíng)銷(xiāo)活動(dòng),就需要根據(jù)具體場(chǎng)景來(lái)衡量了,數(shù)據(jù)一致性可能產(chǎn)生的影響面,性能、可用性、一致性的折中。
這塊內(nèi)容沒(méi)有標(biāo)準(zhǔn)答案,包括了解的各種業(yè)務(wù)場(chǎng)景都是這樣的,數(shù)據(jù)一致性通常需要根據(jù)場(chǎng)景定制化開(kāi)發(fā),并不存在通用解決方案。而我們需要做的就是積累一致性處理經(jīng)驗(yàn)和數(shù)據(jù)一致性保證的可選方案(除了TCC這些,業(yè)界存在很多解決方案,除了TCC這種還有事務(wù)型消息、本地消息表等,但是都逃不出上面的那一堆概念的基礎(chǔ)理論知識(shí))。
八、我所接觸過(guò)的性能優(yōu)化
營(yíng)銷(xiāo)場(chǎng)景下性能要求通常是比較高的,尤其是非常規(guī)的面對(duì)大促的營(yíng)銷(xiāo)活動(dòng),而且性能優(yōu)化中涉及到的技術(shù)相關(guān)的點(diǎn)會(huì)非常之多,常用的軟件研發(fā)工具的選擇、高性能系統(tǒng)的架構(gòu)模型、語(yǔ)言的選擇、底層的網(wǎng)絡(luò)原理、代碼編寫(xiě)上比如并發(fā)模型的優(yōu)化、語(yǔ)言底層的優(yōu)化等等。
除了優(yōu)化的具體行為,我們還需要有科學(xué)的性能衡量標(biāo)準(zhǔn),高效的檢驗(yàn)?zāi)芰Α?/p>
總結(jié)來(lái)說(shuō)性能優(yōu)化的策略:
在最開(kāi)始的時(shí)候先說(shuō)結(jié)論,給出一個(gè)性能優(yōu)化的順序:
- 確定合理的架構(gòu)方案(最大程度上決定了我們的系統(tǒng)能扛多少)
- 確定技術(shù)選型(包括語(yǔ)言、工具,對(duì)內(nèi)存、epoll的高效利用幾乎是現(xiàn)在性能工具選型的根本)
- 代碼邏輯優(yōu)化(很多時(shí)候性能優(yōu)化就是砍IO,少計(jì)算,上緩存,異步化,減少鎖,還有工具的正確使用)
- 最后才是工具、語(yǔ)言的底層調(diào)優(yōu)(這一步很多時(shí)候根本不需要,但是咱們得知道)
技術(shù)不是炫技,最小成本把事做成就好。
1. 什么是高性能
衡量性的性能的標(biāo)準(zhǔn)通常有很多,比如常見(jiàn)的平均響應(yīng)時(shí)間、最大并發(fā)數(shù)等,其實(shí)最核心的就是吞吐量,單位時(shí)間、單位資源內(nèi),系統(tǒng)所能支持的請(qǐng)求處理數(shù)或者事務(wù)處理數(shù)。優(yōu)化最大并發(fā)數(shù)、縮短響應(yīng)時(shí)間最終目標(biāo)都是吞吐量。
高性能mysql一書(shū)在第二、三章一開(kāi)始的位置,就先說(shuō)的衡量標(biāo)準(zhǔn)和測(cè)試方式,這點(diǎn)是非常贊同的,因?yàn)橹挥忻鞔_了什么是高性能,才能進(jìn)行合理的設(shè)計(jì)系統(tǒng),進(jìn)行調(diào)優(yōu)及壓測(cè),非常推薦大家去看一下那兩章。
2. 如何合理的壓測(cè)
除了評(píng)定標(biāo)準(zhǔn),在優(yōu)化的具體行為之前最應(yīng)該熟悉的就是如何壓測(cè),如何高效的壓測(cè)。
對(duì)于壓測(cè)而言重要的有這么幾點(diǎn):
(1)重中之重,要有合理的壓測(cè)方案和周知下游、qa、op,也就是下面的說(shuō)的幾點(diǎn),切勿啥都不準(zhǔn)備上來(lái)就開(kāi)干。
(2)數(shù)據(jù)完全隔離
如果想切實(shí)的了解系統(tǒng)在生產(chǎn)環(huán)境的抗壓能力,那就必須要在生產(chǎn)環(huán)境進(jìn)行壓測(cè),那么數(shù)據(jù)隔離是首要的,不能影響線上不能因?yàn)閴簻y(cè)產(chǎn)生故障或者資損,隔離的方式很簡(jiǎn)單:用戶id區(qū)分。
我們可以使用現(xiàn)在沒(méi)有在用及近一段時(shí)間也不會(huì)有的用戶賬號(hào)進(jìn)行壓測(cè),但是這樣需要面臨清理數(shù)據(jù)(一個(gè)相當(dāng)頭疼的活)打壓測(cè)表示,這需要我們?cè)谙到y(tǒng)設(shè)計(jì)時(shí)就需要做到的,每個(gè)系統(tǒng)都要天然的支持壓測(cè)。
第二種方式無(wú)疑是日常壓測(cè)中最合適的,也是系統(tǒng)設(shè)計(jì)時(shí)需要考慮的。
(3)靈活高效的壓測(cè)系統(tǒng),需要qps實(shí)時(shí)可控,要有紅線觸發(fā)機(jī)制,比如說(shuō)壓測(cè)前確定最大值,壓測(cè)qps調(diào)節(jié)過(guò)程無(wú)論如何都不能超過(guò)預(yù)值。
對(duì)于流量控制,也就是qps的調(diào)控所依賴(lài)的算法其實(shí)很簡(jiǎn)單,就是限流算法的變相使用,常見(jiàn)的有計(jì)數(shù)器控制法、令牌通控制法、漏桶控制,并且基于滑動(dòng)窗口對(duì)于流量進(jìn)行整形,保證均勻,不出現(xiàn)過(guò)高的瞬發(fā)峰值,這部分內(nèi)容之前單獨(dú)寫(xiě)過(guò),可以看一下Go系列文章中限流算法實(shí)戰(zhàn),還有高性能系統(tǒng)中的限流算法原理。
(4)壓測(cè)的核心關(guān)注點(diǎn)
壓測(cè)過(guò)程中需要有合理的指標(biāo):
關(guān)于你的服務(wù):cpu(cpu idel、user、cpu.load)、內(nèi)存(這個(gè)通常來(lái)說(shuō)問(wèn)題不大),剩下的你需要看下游系統(tǒng)的壓力,切勿把下游打掛。
除此之外,壓測(cè)的目的是發(fā)現(xiàn)問(wèn)題解決問(wèn)題,而不是僅僅是測(cè)試系統(tǒng)能扛多少,所以一定要關(guān)注核心依賴(lài),比如說(shuō)mysql、redis等,發(fā)現(xiàn)各種問(wèn)題才能避免線上掛的慘,大多時(shí)候通常是代碼寫(xiě)的有問(wèn)題,但是在三方應(yīng)用上暴露出來(lái),比如說(shuō)hgetall。但是有時(shí)候線上機(jī)器也是可能存在問(wèn)題的,需要壓測(cè)來(lái)檢驗(yàn)。
(5)合理的壓測(cè)過(guò)程
壓測(cè)需要循序漸進(jìn)的來(lái),有問(wèn)題能及時(shí)發(fā)現(xiàn),并且一上來(lái)流量太大高估了自己的系統(tǒng),可能瞬間打掛。
壓測(cè)的流量規(guī)律需要根據(jù)線上真實(shí)流量的變化趨勢(shì),或者預(yù)測(cè)趨勢(shì)來(lái)進(jìn)行壓測(cè),不能想當(dāng)然。建議對(duì)線上流量進(jìn)行復(fù)制,以供壓測(cè)使用,這樣壓測(cè)的鏈路才是真實(shí)的。
(6)完整的留存
壓測(cè)數(shù)據(jù)完整留存、壓測(cè)日志完整留存、火焰圖記錄完整留存。
這一塊兒是關(guān)鍵也是我們壓測(cè)的最終產(chǎn)出,發(fā)現(xiàn)那些地方存在問(wèn)題或風(fēng)險(xiǎn)之后,我們需要根據(jù)這些來(lái)具體分析,以此得出優(yōu)化結(jié)論。
3. 高性能技術(shù)選型
曾經(jīng)見(jiàn)到這樣一句話,大概是這樣的don’t do it,cache it,asyn it,pipline it。其實(shí)性能優(yōu)化就是這樣,尤其是對(duì)于高性能業(yè)務(wù)系統(tǒng)的設(shè)計(jì)而言。
(1)don’t do it
對(duì)于主鏈路而言,是否存在可以不做的的事情,如果有那就砍掉,額外的IO和計(jì)算只會(huì)導(dǎo)致性能的下降。
(2)cache it ; asyn it
如果沒(méi)辦法不做是否可以直接緩存結(jié)果及異步處理。但是如果使用緩存和異步處理,會(huì)面臨非常的大的數(shù)據(jù)一致性問(wèn)題,尤其是緩存。
(3)pipline it
對(duì)于無(wú)法異步化和緩存的IO處理,直接建議同一個(gè)鏈接pipline批量處理。
通常來(lái)說(shuō),高性能系統(tǒng)其實(shí)就是基于上面的幾個(gè)思想,結(jié)合業(yè)務(wù)場(chǎng)景給出解決方案。
(4)高性能工具的最大化利用
我們開(kāi)發(fā)時(shí)毫無(wú)疑問(wèn)會(huì)依賴(lài)于一些開(kāi)源的或者內(nèi)部的工具,比如說(shuō)redis、nginx、mysql、kafka等,想要提升性能要做的第一件事兒就是結(jié)合業(yè)務(wù)場(chǎng)景對(duì)這些工具充分利用,下面詳細(xì)來(lái)看。(由于篇幅過(guò)長(zhǎng),就僅僅只說(shuō)一下nginx和redis吧)
nginx + lua5:
對(duì)于營(yíng)銷(xiāo)系統(tǒng)而言,很多時(shí)候性能要求苛刻,但是邏輯相對(duì)簡(jiǎn)單,這種時(shí)候就完全可以采用nginx+lua構(gòu)建openresty應(yīng)用,迅速解決問(wèn)題。還有邏輯不太變的接入層,也非常適合這種方式。
nginx作為一個(gè)高性能的http和反向代理web服務(wù)器,不同于 Apache的一點(diǎn)就是,Nginx采用單線程,非阻塞,異步IO的工作模型。整體來(lái)說(shuō)就是對(duì)epoll的充分使用,用它來(lái)作為第一層承接流量再合適不過(guò)。
這里要說(shuō)的不僅是nginnx,更多的是配合lua的使用模式,Lua是一種輕量級(jí)、可嵌入式的腳本語(yǔ)言,在nginx之上運(yùn)行l(wèi)ua腳本來(lái)實(shí)現(xiàn)相對(duì)簡(jiǎn)單的接入層邏輯或者部分業(yè)務(wù)邏輯。
市面上常見(jiàn)的方式是由章亦春將Lua和Nginx粘合的ngx_lua模塊,并且將Nginx核心、LuaJIT、ngx_lua模塊、許多有用的Lua庫(kù)和常用的第三方Nginx模塊組合在一起成為OpenResty,使用Lua編寫(xiě)腳本,然后部署到Nginx Web容器中運(yùn)行。從而非常輕松就能開(kāi)發(fā)出高性能的Web服務(wù)。
其中ngx_lua是Nginx的一個(gè)模塊,將Lua嵌入到Nginx中,從而可以使用Lua來(lái)編寫(xiě)腳本,部署到Nginx中運(yùn)行,即Nginx變成了一個(gè)Web容器。
常見(jiàn)的lua工具庫(kù)有:
lua–resty–memcached
lua–resty–mysql
lua–resty–redis
lua–resty–dns
lua–resty–limit–traffic
lua–resty–template
對(duì)于nginx+lua的使用方式通常有:
- 最基礎(chǔ)的負(fù)載均衡
- 單機(jī)閉環(huán),利用lua實(shí)現(xiàn)nginx-lua-static-merger,直接在接入層進(jìn)行本機(jī)靜態(tài)資源讀取完成靜態(tài)資源合并。
- 分布式閉環(huán),解決單機(jī)閉環(huán)中數(shù)據(jù)不一致問(wèn)題(分布式集中存儲(chǔ))、存儲(chǔ)瓶頸(實(shí)現(xiàn)分片邏輯)
- 作為接入網(wǎng)關(guān)使用,比如說(shuō)過(guò)濾請(qǐng)求、防DDOS、Nginx Proxy Cache完成緩存、更細(xì)粒度的限流、降級(jí)預(yù)案等
在極端的性能場(chǎng)景下,nginx+lua完全可以實(shí)現(xiàn)業(yè)務(wù)邏輯,插入數(shù)據(jù)到redis中后續(xù)異步處理,性能非常之高。
至于其中的原理可以看下,我之前的一篇文章《高并發(fā) Nginx + lua是如何抗住的》,其核心就是基于epoll實(shí)現(xiàn)的單線程處理多鏈接的思路。
Redis + lua:
上面說(shuō)的是nginx+lua,這一篇幅要講的是redis+lua,但是需要注意的一點(diǎn)是,redis+lua的性能其實(shí)一般,這一點(diǎn)要格外謹(jǐn)慎,我們要利用的是其操作的原子性。
我們想要進(jìn)行高性能的數(shù)據(jù)操作時(shí),很多時(shí)候都會(huì)直接選用redis做存儲(chǔ)或者緩存,但是依賴(lài)于redis數(shù)據(jù)做操作但涉及具有競(jìng)態(tài)條件的復(fù)合操作時(shí)就會(huì)比較麻煩,大概率會(huì)涉及分布式鎖,其實(shí)redis+lua就是一種變通的方式,將密集的redis操作更裝成lua腳本,這樣既解決了原子性問(wèn)題,又把這部分邏輯變的可插拔(據(jù)說(shuō)游戲領(lǐng)域經(jīng)常會(huì)存在這樣的動(dòng)態(tài)邏輯替換)
但是切記不要在lua中實(shí)現(xiàn)過(guò)多復(fù)雜的邏輯,尤其像是各種json處理,會(huì)導(dǎo)致redis性能急劇下降。
redis+pipline:
對(duì)于redis性能的充分利用,正確的打開(kāi)方式是redis+pipline,一次性灌命令的方式實(shí)現(xiàn)redis若干邏輯處理,其他工具也是一樣的。
在redis+pipline編碼時(shí)需要注意,pipeline 期間將“獨(dú)占”鏈接,此期間將不能進(jìn)行非“管道”類(lèi)型的其他操作,直到 pipeline 關(guān)閉;如果你的 pipeline的指令集通常比較龐大,為了不干擾鏈接中的其他操作,可以為pipeline操作新建鏈接,讓pipeline和其他正常操作分離。還要注意pipeline所能容忍的操作個(gè)數(shù),也就是socket-output緩沖區(qū)大小/返回結(jié)果的數(shù)據(jù)尺寸,這些是受限于server的物理內(nèi)存或網(wǎng)絡(luò)接口的緩沖能力。
這一塊說(shuō)白了就是網(wǎng)絡(luò)連接的高效利用,最基礎(chǔ)的手段是使用短鏈接一個(gè)請(qǐng)求一個(gè)鏈接干到底或者使用連接池+長(zhǎng)鏈接,而pipline就是在這基礎(chǔ)上,進(jìn)一步利用緩沖隊(duì)列,對(duì)命令進(jìn)行一次性傳輸和結(jié)果的一次性返回,kafka所謂的微批處理其實(shí)也是這種實(shí)現(xiàn)思路。如果仔細(xì)看各種工具對(duì)于網(wǎng)絡(luò)IO的優(yōu)化思路,幾乎都是這樣的策略–減少網(wǎng)絡(luò)IO的產(chǎn)生并且充分利用epoll,我們業(yè)務(wù)系統(tǒng)優(yōu)化的思路毫無(wú)疑問(wèn)也是這樣的。
redis的集群方案:
對(duì)于redis的充分利用還有很重要的一點(diǎn)是其集群方案,一般就是兩種類(lèi)codis方案、官方的cluster方案,這些都是從單點(diǎn)到主從再到主動(dòng)+哨兵一步步演變過(guò)來(lái)的,主要一步步解決了單點(diǎn)、可用性、吞吐量等問(wèn)題。
簡(jiǎn)單的看一下這兩種方案的實(shí)現(xiàn)思路:
codis方案(中心化配置存儲(chǔ)):
cluster方案(去中心化實(shí)現(xiàn)思路):
推薦這一篇博客,說(shuō)的很清楚:https://www.cnblogs.com/pingyeaa/p/11294773.html
看完集群方案,其中一點(diǎn)非常明顯,為了提高系統(tǒng)的吞吐量,數(shù)據(jù)是分片存儲(chǔ)的,而分片的核心就是hashtag,hashtag是一種在我們知道redis主庫(kù)選擇的hash規(guī)則后,支持自主定義所存儲(chǔ)的redis服務(wù)器的能力。
關(guān)于hashtag的使用有兩點(diǎn)需要注意:
1、保證分片的均勻
通常來(lái)說(shuō)后我們需要讓每個(gè)服務(wù)器承擔(dān)基本一致的流量壓力,最合適的方式就是根據(jù)用戶id求余(針對(duì)分片數(shù)量求余)來(lái)做分片處理,這個(gè)結(jié)論是在假設(shè)用戶id是均勻的基礎(chǔ)上成立的,如果用戶id不均勻那就在id的基礎(chǔ)上加一層hash值再做處理。
2、使用lua時(shí)的坑
在使用lua時(shí),是根據(jù)第一個(gè)key值進(jìn)行分片選擇的,所以說(shuō)獨(dú)立原子操作時(shí)根據(jù)key值hash后選擇的分片,使用lua操作會(huì)找不到,或者lua操作的key值獨(dú)立的原子操作會(huì)找不到,這一點(diǎn)一定要注意。
分布式鎖實(shí)現(xiàn):
這一塊按理說(shuō)是一致性部分的內(nèi)容,但是因?yàn)槊芮泻托阅芟嚓P(guān),所以就在這里說(shuō)吧。
分布式鎖是用來(lái)保證分布式環(huán)境下數(shù)據(jù)操作的原子性的,和我們常用的鎖的使用方式一樣,加鎖+邏輯處理+解鎖。(主動(dòng)解鎖、超時(shí)釋放)
常見(jiàn)的分布式鎖的實(shí)現(xiàn)方式有三種:
- 基于redis的紅鎖實(shí)現(xiàn)及其簡(jiǎn)化版本
- 利用 Zookeeper 的順序臨時(shí)節(jié)點(diǎn),來(lái)實(shí)現(xiàn)分布式鎖和等待隊(duì)列。
- Google 公司實(shí)現(xiàn)的粗粒度分布式鎖服務(wù),底層利用了 Paxos 一致性算法。
后面兩種實(shí)現(xiàn)方式通常適用于較粗的鎖粒度,并且具有等待隊(duì)列,看起來(lái)更像是一把鎖,但不太適用于高性能場(chǎng)景。而對(duì)于營(yíng)銷(xiāo)這樣的場(chǎng)景來(lái)看,基于redis的分布式鎖更適合。
分布式鎖通常會(huì)存在以下幾個(gè)問(wèn)題:
- 鎖超時(shí)后,其他請(qǐng)求加鎖后的誤釋放問(wèn)題。通常可以利用唯一單號(hào)來(lái)鑒別加鎖者解決。
- 鎖的可用性問(wèn)題,這個(gè)問(wèn)題通常發(fā)生在單點(diǎn)的redis服務(wù)上,紅鎖已經(jīng)給了完整的解決方案(超過(guò)半數(shù)加鎖成功),但是這種方式一定程度上損耗了性能。
需要注意的是分布式鎖的實(shí)現(xiàn),像分布式事務(wù)一樣,不管哪種方式都存在一定的問(wèn)題,比如redis的紅鎖,redis本人也是說(shuō)存在瑕疵的,我們最需要的是根據(jù)場(chǎng)景來(lái)進(jìn)行鑒別選擇,解決痛點(diǎn)問(wèn)題,容忍帶來(lái)的其他問(wèn)題。
3 關(guān)于存儲(chǔ)
(1)存儲(chǔ)的選擇
數(shù)據(jù)的存儲(chǔ)對(duì)所有的系統(tǒng)都是非常的重要,而且是重中之重,在寫(xiě)這塊內(nèi)容的十分鐘之前恰巧看到了剛看了oceanbase的發(fā)展之路,頗為震撼。
對(duì)于營(yíng)銷(xiāo)場(chǎng)景下的存儲(chǔ),很顯然沒(méi)有金融領(lǐng)域那么的苛刻,但是數(shù)據(jù)的可靠存儲(chǔ)依然十分重要,但是相對(duì)多了一些選擇。
對(duì)于常規(guī)場(chǎng)景而言,使用基于磁盤(pán)的關(guān)系型數(shù)據(jù)庫(kù)mysql就足夠了,特性十分豐富,也經(jīng)過(guò)了大環(huán)境的檢驗(yàn),但不要覺(jué)著所有的存儲(chǔ)只能拿mysql來(lái)做。
在極端的性能場(chǎng)景下,我們可以稍微激進(jìn)點(diǎn),拿redis做存儲(chǔ),雖然有過(guò)redis掛掉瘋狂補(bǔ)數(shù)據(jù)的經(jīng)歷,但是依然覺(jué)著在某些場(chǎng)景下是可行的,至少比mysql提升了近一個(gè)數(shù)量級(jí),如果想用redis做存儲(chǔ),首先必須要要有預(yù)案措施也就是redis掛了怎么辦,其次要有數(shù)據(jù)的落盤(pán)行為必須保證可恢復(fù),這里比較好用的有日志留存用戶相關(guān)數(shù)據(jù)快照、異步落庫(kù),在建立恢復(fù)機(jī)制后,我們就可以依賴(lài)于redis快照數(shù)據(jù)+掛掉這部分時(shí)間的日志或者數(shù)據(jù)庫(kù)數(shù)據(jù)來(lái)推演出當(dāng)前redis中的數(shù)據(jù)了。切記需要根據(jù)具體的業(yè)務(wù)場(chǎng)景來(lái)定制化選擇,最痛的點(diǎn)及其他方面的容忍度,就算是激進(jìn)也得有個(gè)度。
(2)數(shù)據(jù)拆分
在性能場(chǎng)景下,單mysql或者redis存儲(chǔ)完全滿足不了(查詢性能(cpu瓶頸)+IO瓶頸),這適合就要面對(duì)數(shù)據(jù)的拆分,來(lái)應(yīng)對(duì)CPU+IO兩大問(wèn)題。
而數(shù)據(jù)拆分無(wú)外乎垂直拆分、水平拆分,對(duì)于redis字典型非關(guān)系數(shù)據(jù)庫(kù)而言,使用hashtag+散列的key值很顯然同時(shí)做到了。
對(duì)于mysql而言其實(shí)就是分庫(kù)分表。(水平+垂直)
但是在拆分過(guò)程中非常重要的幾點(diǎn):
- 分庫(kù)分表,需要了解瓶頸在哪,然后才能合理地拆分,不能為了分庫(kù)分表而拆分。
- 選key很重要,既要考慮到拆分均勻,也要考慮到非partition key的查詢,可以利用上面提到的用戶id或者訂單id進(jìn)行拆分。
另外,分褲分表會(huì)帶來(lái)大量的問(wèn)題,為了問(wèn)題盡可能的少、系統(tǒng)易維護(hù)拆分規(guī)則越簡(jiǎn)單越好。
相關(guān)工具:
- redis:codis、cluster等方式自帶hashtag功能。
- mysql:sharding-sphere、或者自定義實(shí)現(xiàn)。
4. 若干的語(yǔ)言
確定完架構(gòu)方案、工具選擇,剩下的就是語(yǔ)言和相關(guān)的優(yōu)化了,在選擇語(yǔ)言時(shí)依然是上面提到的幾個(gè)標(biāo)準(zhǔn):人力成本、研發(fā)質(zhì)量成本、研發(fā)效率成本、機(jī)器成本,具體來(lái)說(shuō):
- 從語(yǔ)言的特性出發(fā),衡量各種成本的變化情況
- 從當(dāng)前人員構(gòu)成和公司內(nèi)基礎(chǔ)設(shè)施出發(fā),衡量各種成本的變化情況
兩者結(jié)合考慮,并根據(jù)當(dāng)前項(xiàng)目的緊急程度確定方案的選擇。如果是基礎(chǔ)設(shè)施的建設(shè),直接從第一點(diǎn)考慮就OK了。
然后下面仔細(xì)的說(shuō)一下各種語(yǔ)言及其擅長(zhǎng)的領(lǐng)域,大家準(zhǔn)備好,可以開(kāi)噴了,本章不涉及語(yǔ)言的開(kāi)發(fā)細(xì)節(jié),只說(shuō)特性和適用程度。
(1)Java
這是我的第一門(mén)編程語(yǔ)言,大概是大二的時(shí)候開(kāi)始接觸,對(duì)于語(yǔ)言的熟悉發(fā)生在大三下學(xué)期和實(shí)習(xí)之后。
Java的優(yōu)勢(shì)很明顯,生態(tài)十分龐大,性能相對(duì)優(yōu)良,但極端性能場(chǎng)景下還是需要c系,研發(fā)效率處于中等位置,研發(fā)質(zhì)量較高,并且Java相關(guān)人才比較好招。由于它的生態(tài)Java看起來(lái)適合非常多的場(chǎng)景:Hadoop、spring等,語(yǔ)言特性很多,工具庫(kù)異常豐富。
對(duì)于營(yíng)銷(xiāo)系統(tǒng)而言,Java非常適合開(kāi)發(fā)重業(yè)務(wù)的系統(tǒng),比如活動(dòng)單元及活動(dòng)流程層,在Java的基礎(chǔ)上我們能夠把業(yè)務(wù)邏輯盡可能的抽象,對(duì)于底層細(xì)節(jié)而言,像垃圾回收(適合各種場(chǎng)景的垃圾回收器:G1、cms、ZGC)網(wǎng)絡(luò)IO的處理(官方庫(kù)中基于水平觸發(fā)epoll的IO處理,netty中給予邊緣觸發(fā))等等一切都是非常完備的,對(duì)于中規(guī)中矩的系統(tǒng)非常適合。
(2)Go
這是我的第二門(mén)編程語(yǔ)言,19年幾乎一年都在寫(xiě)go,go是一門(mén)非常年輕的語(yǔ)言,看現(xiàn)在的發(fā)展也迅猛無(wú)比。
優(yōu)點(diǎn):(網(wǎng)上通常有各種各樣的介紹,對(duì)于營(yíng)銷(xiāo)而言主要是以下兩點(diǎn))
- 天然的并發(fā)性
- 相對(duì)較高的開(kāi)發(fā)效率
缺點(diǎn)也十分的明顯:
- 生態(tài)較差,你用Java可輕松找到的工具,如果用go恐怕要自己實(shí)現(xiàn)了。
- 相對(duì)Java較為垃圾的垃圾回收,以至于性能沒(méi)有那么極致。
- if err != nil
對(duì)于營(yíng)銷(xiāo)場(chǎng)景而言:
go由于天然的并發(fā)性和對(duì)epoll的高效支持,對(duì)于網(wǎng)絡(luò)IO處理非常的擅長(zhǎng),最經(jīng)典的應(yīng)用莫過(guò)于前東家開(kāi)源的bfe。落地到營(yíng)銷(xiāo)場(chǎng)景而言,go很適合做流量調(diào)度型基礎(chǔ)組件。
其他的話,go適合做系統(tǒng)級(jí)應(yīng)用開(kāi)發(fā),docker、k8s這些都是基于go來(lái)實(shí)現(xiàn)的,如果做基礎(chǔ)架構(gòu),go是一個(gè)非常不錯(cuò)的選擇。
下面要說(shuō)的PHP和C++ 沒(méi)有真正的實(shí)戰(zhàn)過(guò),沒(méi)有太多的發(fā)言權(quán),只是簡(jiǎn)單的說(shuō)幾句,像python這種只寫(xiě)過(guò)兩個(gè)時(shí)間的,就不拿出來(lái)獻(xiàn)丑了。
(3)PHP
世界上最好的語(yǔ)言的PHP,簡(jiǎn)直就是為web場(chǎng)景而生的,極致的開(kāi)發(fā)效率,對(duì)于最原始的營(yíng)銷(xiāo)場(chǎng)景更是如此。由于前東家的PHP做了很大程度上的優(yōu)化,所以已經(jīng)不僅僅是原生的PHP了,這點(diǎn)需要考慮進(jìn)去,如果是原生的PHP性能場(chǎng)景可以排除掉了。
(4)C++
c++比較適合極端的場(chǎng)景,比如說(shuō)需要內(nèi)存精確控制的場(chǎng)景像是搜索領(lǐng)域,對(duì)于營(yíng)銷(xiāo)場(chǎng)景而言,C++使用程度其實(shí)一般。如果存在老的C++營(yíng)銷(xiāo)系統(tǒng),拿go或者Java來(lái)重構(gòu)掉是一個(gè)不錯(cuò)的選擇。
對(duì)于語(yǔ)言和工具方面,工作一年多的時(shí)間里也做了一些積累,大家可以參考一下之前的博客:《redis系列》《kafka系列》《go語(yǔ)言開(kāi)發(fā)系列》《Java concurrent 系列》《高性能系統(tǒng)構(gòu)建系列》,后面這些內(nèi)容也都會(huì)持續(xù)更新的~
https://www.jianshu.com/u/636e09dd8775
(5)單獨(dú)提一下epoll
在重IO的業(yè)務(wù)系統(tǒng)中,一個(gè)工具或者語(yǔ)言對(duì)于epoll的支持程度大概率決定了是否用它,它是IO中性能的基礎(chǔ)。
Java對(duì)epoll的支持相對(duì)較好,原生網(wǎng)絡(luò)包中提供了基于水平觸發(fā)的epoll,netty補(bǔ)充實(shí)現(xiàn)了基于邊緣觸發(fā)的epoll(Dubbo就是基于它實(shí)現(xiàn)的)
Go,采用協(xié)程+epoll的方式進(jìn)行網(wǎng)絡(luò)編程,效率十分之高,這也是go適合做流量調(diào)度的根本原因。
nginx最大的性能來(lái)源其實(shí)就是epoll,同時(shí)支持邊緣觸發(fā)和水平觸發(fā)兩種模式,再加上精確的內(nèi)存操作所以性能炸裂。
redis的單線程處理多鏈接的模式底層也是基于epoll實(shí)現(xiàn)的,可以看一下redis ae庫(kù)中的實(shí)現(xiàn)。
如果想看一下互聯(lián)網(wǎng)時(shí)代網(wǎng)絡(luò)的發(fā)展史,可以從C10k問(wèn)題起再到如何高效的進(jìn)行并發(fā)編程。
并發(fā)編程是充分利用cpu高效處理的一種手段,如果涉及并發(fā)有兩點(diǎn)是無(wú)法忽略的:
- 并發(fā)編程模型
- 鎖的處理。
(6)并發(fā)編程模型
對(duì)于并發(fā)編程模型通常來(lái)說(shuō)是伴隨著語(yǔ)言的,比如go實(shí)現(xiàn)的基于協(xié)程和管道的CSP模型,Java基于內(nèi)存共享的線程模型,在我們選擇語(yǔ)言的時(shí)候就已經(jīng)確定了。這兩者有著非常大的區(qū)別:CSP
并發(fā)模型的核心概念是:“不要通過(guò)共享內(nèi)存來(lái)通信,而應(yīng)該通過(guò)通信來(lái)共享內(nèi)存”。兩種方式各有各的好處,根據(jù)場(chǎng)景選擇即可,這也是語(yǔ)言選擇的一個(gè)重要的點(diǎn)。
我們需要根據(jù)具體場(chǎng)景來(lái)選擇,即使語(yǔ)言有限制,go使用內(nèi)存共享,Java來(lái)實(shí)現(xiàn)基于管道通信也未嘗不可。
(7)鎖的使用
這是這一篇章的核心內(nèi)容,對(duì)于鎖的使用。對(duì)于優(yōu)化來(lái)說(shuō)通常有下面幾點(diǎn):
1、避免加鎖
一些能夠犧牲空間來(lái)進(jìn)行線程或者協(xié)程私有數(shù)據(jù)空間,就沒(méi)必要使用鎖了,加鎖完全是為了并發(fā)下邏輯的正確,如果有更好的解決方式,請(qǐng)避免使用鎖。
2、鎖選擇
拿Java舉例,就synchronized、ReentrantLock來(lái)分析比較的話,看到網(wǎng)上有好多博客都在說(shuō)sychronized 在爭(zhēng)用頻次非常高的情況下性能會(huì)急劇下降,這種觀點(diǎn)是存在時(shí)效性的,就當(dāng)前1.8版本使用體驗(yàn)而言,sychronized在大量爭(zhēng)用的情況性能其實(shí)還好并不會(huì)出現(xiàn)所謂的急劇下降,倒是在激烈爭(zhēng)用時(shí)sychronized的性能要好一些,這個(gè)問(wèn)題去官網(wǎng)確認(rèn)了下,官方是建議使用sychronized的,這次的體驗(yàn)也是sychronized更好。因?yàn)楫?dāng)前JVM是對(duì)于sychronized做出了優(yōu)化了,借鑒ReentrantLock的CAS加鎖方式,并且引入了偏向鎖、輕量級(jí)鎖等特性后,常規(guī)情況下兩者比較相似,實(shí)踐中得到的體驗(yàn)是sychronized性能更好一點(diǎn)。
3、鎖粒度
如果非得需要鎖,粒度要盡可能的控制到小,避免不必要的加鎖。因?yàn)橥綁K越長(zhǎng),線程持有鎖的時(shí)間就越長(zhǎng),其他線程等待的時(shí)間就越長(zhǎng),如果整個(gè)都是加鎖的,那么整個(gè)程序就變成串行處理了。
但是要主要不要頻繁加解鎖。
4、相關(guān)并發(fā)工具的選擇
最簡(jiǎn)單的方式其實(shí)就是盡可能使用原生經(jīng)過(guò)反復(fù)驗(yàn)證的官方工具(concurrenthashmap、waitgroup等),不要嘗試使用自己編寫(xiě)工具,大概率出問(wèn)題,但是為了學(xué)習(xí),就很有必要了。
5. 代碼優(yōu)化
(1)代碼邏輯優(yōu)化
其他的代碼優(yōu)化語(yǔ)言層面感受到的有CPU使用減少、IO減少、語(yǔ)言底層優(yōu)化三方面:
對(duì)于cpu來(lái)說(shuō):
- md5、Json序列化反序列化等這些都是非常耗性能的,如非必要,建議砍掉。
- 充分回憶起大學(xué)時(shí)的《數(shù)據(jù)結(jié)構(gòu)和算法》,例如可以用Hash O(1)打表解決的,請(qǐng)不要幾層for一通干。
- 謹(jǐn)慎使用明確存在性能風(fēng)險(xiǎn)的工具,比如go中的定時(shí)器,踩坑之深,至今難忘。
- 不要覺(jué)著起協(xié)程或者線程效率高,很多時(shí)候無(wú)端的起協(xié)程和線程得到的收益是很小的。
對(duì)于IO來(lái)說(shuō):
還是上面提到的那個(gè)思想,基于epoll的基礎(chǔ)上,砍IO、pipline。
最主要的是在IO操作評(píng)估時(shí),要根據(jù)具體的日志來(lái)量化分析統(tǒng)計(jì),而不是看代碼,拍腦門(mén)決定。
(1)語(yǔ)言底層優(yōu)化及其他
對(duì)于語(yǔ)言底層的優(yōu)化,在日常開(kāi)發(fā)中其實(shí)接觸的不會(huì)很多,很多的是出現(xiàn)在面試中,哈哈哈哈哈哈。實(shí)際操作過(guò)程中,也偶爾會(huì)涉及到,主要是對(duì)于GC相關(guān)的內(nèi)存分配。
對(duì)于GC而言,垃圾回收器的選擇還有代碼精減(減少臨時(shí)對(duì)象等)要比瞎折騰調(diào)參數(shù)強(qiáng)的多,如果選擇了合適的垃圾回收器,然后才是具體參數(shù)的調(diào)優(yōu),這一塊要充分利用語(yǔ)言的原生工具,比如說(shuō)jmap、jstack、火焰圖工具等,確定問(wèn)題的根源,再動(dòng)手。
再其次,才是即時(shí)編譯等參數(shù)。
九、可怕的資損
營(yíng)銷(xiāo)場(chǎng)景下最大的問(wèn)題其實(shí)是資損,營(yíng)銷(xiāo)場(chǎng)景下因?yàn)槠溥壿嫸嘧兦遗R時(shí),rd的開(kāi)發(fā)周期極短,并且方案往往很難有時(shí)間反復(fù)推敲,不管是運(yùn)營(yíng)邏輯還是很代碼代碼實(shí)現(xiàn)都存在較大的風(fēng)險(xiǎn),是極易發(fā)生資損的。而面對(duì)這些問(wèn)題,也是建立一個(gè)較為完善的營(yíng)銷(xiāo)系統(tǒng)的目的所在。
1. 經(jīng)典案例
(1)某東
京東無(wú)門(mén)檻優(yōu)惠券被大量羊毛黨領(lǐng)取,在優(yōu)惠疊加后可以用極低價(jià)格(接近0元)購(gòu)買(mǎi)數(shù)百元的小家電,涉及資損金額數(shù)千萬(wàn)。
(2)某多
騰訊視頻“0.2元開(kāi)通VIP”處理、東航0.4折白菜機(jī)票bug。
2. 如何可防可控
對(duì)于資損問(wèn)題,最重要的有幾個(gè)方案:
(1)嚴(yán)控流程問(wèn)題
保證運(yùn)營(yíng)方案、技術(shù)設(shè)計(jì)、代碼cr等主要環(huán)節(jié)發(fā)現(xiàn)問(wèn)題,并及時(shí)解決。
(2)完善資損監(jiān)控
這時(shí)候資損的發(fā)現(xiàn)環(huán)境,很多時(shí)候資損總是不經(jīng)意間發(fā)生,我們最需要的是在資損發(fā)生的第一時(shí)間能夠發(fā)現(xiàn),而不是等幾小時(shí)、幾天后鑄成大錯(cuò)才意識(shí)到。資損監(jiān)控需要針對(duì)活動(dòng)流程定制化開(kāi)發(fā),資損監(jiān)控最好是在設(shè)計(jì)階段就要考慮進(jìn)來(lái)的,根據(jù)運(yùn)營(yíng)邏輯、系統(tǒng)設(shè)計(jì)來(lái)確定資損點(diǎn)從而定制化開(kāi)發(fā),這樣不光完善了資損監(jiān)控,更加后悔使rd同學(xué)方案設(shè)計(jì)及代碼開(kāi)發(fā)時(shí)更謹(jǐn)慎。一般來(lái)說(shuō)圍繞以下四點(diǎn)進(jìn)行監(jiān)控能發(fā)現(xiàn)絕大部分的資損問(wèn)題:
- 單個(gè)權(quán)益是否超標(biāo)
- 單個(gè)用戶領(lǐng)到的權(quán)益量是否超標(biāo)
- 是否存在不符合條件的用戶領(lǐng)取到對(duì)應(yīng)權(quán)益
- 是否存在異常峰值流量進(jìn)行刷單
- 監(jiān)控止損
對(duì)于止損問(wèn)題,是一個(gè)比較難處理的環(huán)節(jié),通常需要在保證活動(dòng)正常運(yùn)行的情況下進(jìn)行止損,比較重大的問(wèn)題可以直接活動(dòng)下線。(會(huì)存在監(jiān)管合規(guī)風(fēng)險(xiǎn))
在活動(dòng)設(shè)計(jì)時(shí)應(yīng)具有專(zhuān)門(mén)針對(duì)資損的預(yù)案處理,比如:
權(quán)益方面:
- 權(quán)益的回收機(jī)制(降低資損程度)
- 權(quán)益迅速降級(jí)機(jī)制(原本發(fā)紅包,改為優(yōu)惠券)
活動(dòng)流程方案:
- 一鍵不中獎(jiǎng)
- 活動(dòng)規(guī)則范圍內(nèi)增加門(mén)檻
- 接入專(zhuān)業(yè)風(fēng)控;反欺詐能力
這里主要是針對(duì)專(zhuān)業(yè)羊毛黨用戶的,防止作弊流量刷單,杜絕黑名單用戶參與活動(dòng)。
十、總結(jié)
整篇文章到這里就很急促的結(jié)束啦,想寫(xiě)的業(yè)務(wù)內(nèi)容還有技術(shù)內(nèi)容還有很多,受限于篇幅和時(shí)間原因就先寫(xiě)這么多吧,文章寫(xiě)的越長(zhǎng),對(duì)它的整體控制能力稍微有點(diǎn)開(kāi)始下降了。
整體來(lái)看一個(gè)營(yíng)銷(xiāo)系統(tǒng)的核心就是:以技術(shù)能力解決營(yíng)銷(xiāo)場(chǎng)景下的效率、質(zhì)量、風(fēng)險(xiǎn)等問(wèn)題,高效穩(wěn)定的提供營(yíng)銷(xiāo)能力輸出。
系統(tǒng)實(shí)線時(shí)的關(guān)注點(diǎn):
- 性能
- 數(shù)據(jù)一致性
- 高度配置化能力
- 完備的效果洞察及監(jiān)控能力
- 系統(tǒng)的可擴(kuò)展性
本文由 @鄒志全 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載。
題圖來(lái)自Unsplash,基于CC0協(xié)議。
該文觀點(diǎn)僅代表作者本人,人人都是產(chǎn)品經(jīng)理平臺(tái)僅提供信息存儲(chǔ)空間服務(wù)。
學(xué)習(xí)了,看了2小時(shí)
單元和組件區(qū)別是什么?
預(yù)計(jì)閱讀時(shí)間 81分鐘, 寫(xiě)的真詳細(xì)
專(zhuān)業(yè)
這篇文章干貨滿滿,結(jié)構(gòu)清晰,感謝作者的分享,愛(ài)了愛(ài)了