約翰D洛克斐勒

提起億萬富翁,你想到的可能是比爾蓋茲、馬克祖克柏等等。約翰D洛克斐勒這個名字,很多人不熟悉。他出生於1839年,是美國的實業家和超級資本家,還是世界上第一個億萬富翁、全世界公認的石油大王。

1870年時,洛克斐勒創立標準石油公司,20年後,他的公司就有了10萬名員工。巔峰時期,他曾壟斷全美80%的煉油工業,和90%的油管生意。洛克斐勒非常低調,也很神秘,有人評價說,跟同時代的巨富們相比,他的財富是最不骯髒的。

比爾蓋茲曾說:「我心目中的賺錢英雄只有一個,那就是洛克菲勒。」洛克菲勒不僅是一位成功的商人,還是一位很好的父親。歷經100多年,洛克菲勒家族綿延6代,依舊是世界上最富有的家族之一。

洛克菲勒家族之所以輝煌至今,與家族成員自小受到的家庭教育是分不開的。洛克菲勒曾給兒子寫過很多封信,這些信裡記錄了洛克菲勒創造財富神話的種種業績,也體現出了他優良的品德和卓越的經商才能。

下面是洛克菲勒寫給小兒子的2封信,一起看看吧。

「親愛的約翰:

非常感謝你對我的信任,告訴我你退出銀行董事會的事情。我當然理解你這樣做的原因,你已經無法繼續忍受同仁們的某些做法,更不想繼續屈從於他們。但你的決定是否明智,似乎還有待於時間來證實。理由很簡單,如果你不主動放棄銀行董事的職位,而是選擇留在那裡,或許你會得到更多。

我知道,屈從是思想的大敵,也是自由的獄吏。然而,對於一個胸懷大志的人來說,保持必要的屈從與忍耐,恰恰是一條屢試不爽的成功策略。追溯過往,曾經我忍耐過許多,也因忍耐得到過許多。

我創業之初,由於資金缺乏,合夥人克拉克先生邀請他昔日的同事加德納先生入夥,對此我舉雙手贊成。有了這位富人的加入,意味著我們可以做我們想做、有能力做、只要有足夠資金就能做成的事情。然而,出乎我意料的是,克拉克帶來了一個錢包的同時,也送給了我一份屈辱。

他們要把克拉克洛克菲勒公司更名為克拉克加德納公司,他們將洛克菲勒的姓氏從公司名稱中抹去的理由是:加德納出身名門,他的姓氏能吸引更多的客戶。

這踐踏了我的自尊!我憤怒啊!我同樣是合夥人,加德納帶來的只是他那一份資金而已,難道他出身貴族就可以剝奪我應得的名分嗎?!但是,我忍下了,我告訴自己:你要控制住你自己,你要保持心態平靜,這只是開始,路還長著呢…

我故作鎮靜,裝作若無其事的樣子告訴克拉克:「這沒什麼。」事實上,完全不是這樣。想想看,一個遭受不公平、自尊心受損的人,他怎麼能有如此的寬容大度!但是,我用理性澆滅了我心頭燃燒著的熊熊怒火,因為我知道這會給我帶來好處。忍耐不是毫無原則的容忍,你需要冷靜地考量情勢,要知道你的決定是否會偏離或加害你的目標。

對克拉克大發雷霆不僅有失體面,更重要的是,這會給我們的合作製造裂痕,甚至招致一腳把我踢出去、讓我從頭再來的惡果。而團結則可以形成合力,讓我們的事業越做越大,我的個人力量和利益也必將隨之壯大。

我知道自己要到哪裡去。在這之後我繼續一如既往、不知疲倦地熱情工作。到了第三個年頭,我就成功地把那位極盡奢侈的加德納先生請出了公司,讓克拉克洛克菲勒公司的牌子重新豎立起來!那時人們開始尊稱我為洛克菲勒先生。

在我眼裡忍耐並非忍氣吞聲、也絕非卑躬屈膝,忍耐是一種策略,同時也是一種性格磨練,它所孕育出的是好勝之心。這是我與克拉克先生合作期間得出的心得。

我崇尚平等,厭惡居高臨下發號施令。然而,克拉克先生在我面前卻總要擺出趾高氣揚的架勢,這令我非常反感。他似乎從不把我放在眼裡,把我視為目光短淺的小職員,甚至當面貶低我除了記賬和管錢之外一無所能,沒有他我更一文不值。這是公然的挑釁,我卻裝作充耳不聞,我知道自己尊重自己比什麼都重要,但是我在心裡已經同他開戰,我一遍一遍地叮囑自己:超過他,你的強大是對他最好的羞辱,是打在他臉上最響的耳光。

結果正像你所知道的那樣,克拉克洛克菲勒公司永遠成為了歷史,取代它的是洛克菲勒安德魯斯公司,就此我搭上了成為億萬富翁的特快列車。能忍人所不能忍之忤,才能為人所不能為之事。

任何時候衝動都是我們最大的敵人。如果忍耐能化解不該發生的衝突,這樣的忍耐永遠是值得的。頑固地一意孤行,非但不能化解危機,還會帶來更大的災難。但是安德魯斯先生似乎並不明白這個道理。

安德魯斯先生是一個沒有商業頭腦卻自以為是的人,他缺乏成為偉大商人的雄心卻有著邪惡的偏見。這種人與我發生衝突毫不奇怪。導致我們最終分道揚鑣的那場衝突,緣於公司發放股東的紅利。

那一年我們幹得不錯,賺了很多錢,可是我不想把公司賺到的錢全都讓股東們拿回家,我希望能將其中的一半收益再投入到公司的經營中去。但安德魯斯堅決反對,這個自私自利的傢伙想把賺來的錢全分了,甚至怒氣沖沖地對我說,他不想在公司繼續幹下去了。我不能忍受任何阻止公司強大的想法,我只能向他攤牌,請他為他持有的股票開價,他說一百萬,我說沒問題,第二天我就用一百萬買下了。

錢一到手,安德魯斯興奮極了,他自以為自己交了好運,認為他手裡持有的股票根本不值一百萬。但他沒有想到,我一轉手就賺了三十萬。這事傳到他那裡,他竟然罵我手段卑鄙。

我不想因為區區三十萬就落得個卑鄙的名聲,就派人告訴他可以按原價收回。但懊惱中的安德魯斯拒絕了我的好意。事實上他拒絕的是一次成為全美巨富的機會,如果他能把他價值一百萬的股票保留到今天,就會成為絕對的千萬富翁。但為賭一時之氣,他喪失了終生再也抓不住的機會。

約翰,在這個世界上要我們忍耐的人和事太多太多,而引誘我們感情用事的人和事也太多太多。所以,你要修煉自己管理情緒和控制感情的能力,要注意在做決策時不要受感情左右,而是完全根據需要來做決定,要永遠知道自己想要的是什麼。

你還需要知道,在這個世界上,沒有太多的機會可以爭取。如果你真的想成功,你一定要掌握並保護自己的機會,更要設法爭取機會。記住,要天天把忍耐帶在身上,它會給你帶快樂、機會和成功。

愛你的父親」

「親愛的約翰:

我想你已經覺察到了,你的某些思想和觀念正在發生著變化,因為你的那些朋友。我當然不反對你擴大社交圈,它可以增加你的生活情趣,擴展你的生活領域,甚至幫你找到知己或幫你實現人生理想的人。但有些人顯然不值得你與他交往,比如,那些拘泥於卑微瑣碎的人。

從我年輕的時候開始,我就拒絕同兩種人交往。第一種人,是那些完全投降和安於現狀的人。他們深信自己條件不足,認為創造成就只是幸運兒的專利,他們沒有這個福氣。

這種人寧願守著一個很有保障卻很平凡的職位,年復一年渾渾噩噩。他們也知道自己需要一份更有挑戰性的工作,這樣才能繼續發展與成長,但就因為有無數的阻力,使他們深信自己不適合做大事。

明智的人絕不會為命運坐下來哀號。但這種人只會哀嘆命運不濟,卻從不欣賞自己,把自己看成是更有份量、更有價值的人,他們失去了使自己全力以赴的感覺,和自我鼓勵的功能,反讓消極佔據了自己的內心。

第二種人是不能將挑戰進行到底的人。他們曾經非常向往成就大事,也曾替自己的工作做準備,制訂計劃。但是過去幾年或十幾年後,隨著工作阻力的慢慢增加,為更上一層樓,需要艱苦努力的時候,他們就會覺得這樣下去實在不值得,因而放棄努力,變得自暴自棄。

他們會自我解嘲:『我們比一般人賺得多,生活也比一般人要好,幹嘛不知足,還要冒險呢?』其實這種人已經有了恐懼感,他們害怕失敗,害怕大家不認同,害怕失去已有的東西。他們並不滿足,卻已經投降。

這種人很有才幹,卻因不敢重新冒險,願意平平淡淡地度過一生。這兩種人身上有著共同的思想毒素,極易影響他人,那就是消極。我一直以為,一個人的個性與野心,目前的身分與地位,同與什麼人交往有關。經常跟消極的人來往,他自己也會變得消極;跟小人物交往過密,就會產生許多卑微的習慣。反過來說,經常受到大人物的熏陶,自會提高自己的思想水準。

我喜歡同那些永遠也不屈服的人做朋友。有個聰明人說得好:我要挑戰令人厭惡的逆境,因為智者告訴我,那是通往成功最明智的方向。只是這種人少之又少。這種人絕不讓悲觀來左右一切,絕不屈從各種阻力,更不相信自己只能渾渾噩噩虛度一生。他們活著的目的就是獲得成就。

這種人都很樂觀,因為他們一定要完成自己的心願。這種人很容易成為各個領域的佼佼者。他們能真正的享受人生,也真正了解生命的可貴與價值。他們都盼望每一個新的日子,以及跟別人之間的新接觸,因為他們把這些看成是豐富人生的歷練,因此熱烈地接受。

我相信人人都希望列入其中,因為只有這些人才能成功,也只有這些人才真正做事,並且能得到他們期盼的結果。不幸的是,消極的人隨處可見,也使很多很多的人無法逃脫消極之牆的圍困。

我們周圍的人並非人人相同,有些消極保守,有些則積極進取。曾與我共事的人中,有些想混口飯吃,有些則胸懷大志,野心勃勃,想要有更好的表現,他們也了解,在成為大人物前,必須先做個好的追隨者。

要有所成就,就要避免落入各式各樣的陷阱或圈套。在任何一個地方都有人自知不行,卻硬要擋住你上進的路,阻止你更上層樓。有許多人因為力爭上游,而被人嘲笑甚至被恐嚇。還有些人非常嫉妒,看到你努力上進,力求表現,會想盡辦法來作弄你,要你難堪。我們不能阻止他人成為那些無聊的消極分子,卻可以不被那些消極人士影響,降低我們的思想水準。

你要讓他們自然溜過,就像水鴨背後的水一樣自然滑過。時時跟隨思想積極前進的人,跟著他們一起成長、一起進步。你確實能夠做到這一點,只要你的思想正常,一定可以辦到,而且你最好要這樣做。

有些消極的人心腸很好,另外還有一些消極的人,自己不知上進,還想把別人也拖下水,他們自己沒有什麼作為,所以想使別人也一事無成。記住,約翰,說你辦不到的人,都是無法成功的人,亦即他個人的成就,頂多普普通通而已。因此這種人的意見,對你有害無益。

你要多加防範那些說你辦不到的人,只能把他們的警告看成證明你一定辦得到的挑戰。你還要特別防範消極的人打亂你邁向成功的計劃,這種人隨處可見,他們似乎專門嘲笑別人的進步與努力。千萬要小心,要多多注意那些消極的人,千萬不要讓他們打亂你的計劃。

不要讓那些思想消極、度量狹窄的人妨礙你的進步。那些幸災樂禍、喜歡嫉妒的人都想看你摔跤,不要給他們機會。當你有任何困難時,明智的做法是找一流的人物來幫你。如果向一個失敗者請教,就跟請求庸醫治療絕症一樣可笑。你的前途很重要,千萬不要從長舌婦那裡徵求意見,因為這種人一輩子都沒有出息。

你要重視你的環境。就像食物供應身體一樣,精神活動也會滋潤你的心理健康。要使你的環境為你的工作服務,而不是拖累你。不要讓那些阻力,亦即專門扯你後腿的人使你萎靡不振。讓環境幫助你成功的方法是:多接近積極的人,少同消極的人來往。每一件事都要做得盡善盡美。你付不起貪小失大所累積的種種額外負擔。

愛你的父親」

以下是洛克菲勒家族的10條家訓,對你也許會有幫助:

1.借錢不是件壞事,它不會讓你破產,只要你不把它看成像救生圈一樣,只在危機的時候使用,而把它看成是一種有力的工具,你就可以用它來開創機會。

2.建立在生意上的友誼,遠勝於建立在友誼上的生意。往上爬的時候對別人好一點,因為你下坡的時候會碰到他們。

3.收入只是你工作的副產品,做好你該做的事,出色完成你該完成的工作,理想的薪金必然會來。而更為重要的是,我們勞苦的最高報酬,不在於我們所獲得的,而在於我們會因此成為什麼。

4.熱愛工作是一種信念。懷著這個信念,我們能把絕望的大山鑿成一塊希望的磐石。如果你視工作為一種樂趣,人生就是天堂;如果你視工作為一種義務,人生就是地獄。

5.一旦避免失敗變成你做事的動機,你就走上了怠惰無力的路。

6.藉口,把絕大多數的人擋在了成功的大門外。百分之九十九的失敗,都是因為人們慣於尋找藉口。

7.要管理和運用金錢,你必須樂於親自動手、親自管理數字,不能只是空談管理和策略。上帝表現在細節之中。

8.無論是要贏得財富,還是要贏得人生,優秀的人在競技中想的不是輸了我會怎樣,而是要成為勝利者我應該做什麼。

9.世界上沒有一樣東西可取代毅力。才幹也不可以,懷才不遇者比比皆是,一事無成的天才很普遍。教育也不可以,世界上充滿了學而無用的人。只有毅力和決心無往不利。

10.不靠運氣活著,但靠策劃發達。好的計劃會左右運氣,甚至在任何情況下,都能影響所謂的運氣。

洛克斐勒能夠成為億萬富翁,洛克斐勒家族能夠傳承多年,果然是有原因的。我們能從中學到很多東西啊。

 

如何利用ffmpeg將影片轉換成HLS切片

HLS(HTTP Live Stream)是蘋果推出的影音串流的標準,目前可支援大多數的行動裝置與電視盒,如何利用ffmpeg將直播或影片進行切片(chunk)轉成HLS格式。
編碼參數說明不多敘述。

直播

以udp為例:

ffmpeg -y -i udp://@:10000 -c copy -hls_segment_type fmp4 -hls_time 6 -hls_list_size 10 -hls_flags delete_segments+append_list+split_by_time -hls_playlist_type event ~/hls/index_4000.m3u8

影音編碼器(Encoder)將直播訊號發送到轉碼用PC(Transcoding PC),將影音內容的編碼方式直接轉換(-c copy)。
-hls_time:設定每個切片(chunk)的長度(秒),這裡設定為6秒一個切片。
-hls_segment_type: fmp4 or mpegts,切片的格式為mp4或者為mpeg-2 ts格式,目前hls version 7以上可採用mp4格式類似於mpeg-dash
-hls_list_size:設定playlist播放清單最多的內容,如果是0則無限制。因此為直播內容,可預先保留最大的值,這裡設定為10,就是會預先切個10個切片的播放清單,前面hls_time設定為6秒,切十個,就是預留60秒的內容進行播放。相對的,就有會將近60秒的延遲。
-hls_flags:有很多參數可用,這裡使用了delete_segments, append_list, split_by_time, 分述如下:

  • delete_segments: 在segment的持續時間加上播放列表(playlist)的持續時間之後的一段時間之後刪除從播放列表中刪除的段文件(segment)。
  • append_list: 將新segment添加到舊segment列表的末尾,並從舊段列表中刪除#EXT-X-ENDLIST。
  • split_by_time: 允許segment在關鍵幀(key frame)以外的幀上啟動。 當關鍵幀之間的時間不一致時,這會改善某些玩家的行為,但可能會使其他播放器的情況變得更糟,並且在搜索過程中可能會導致一些奇怪的現象。 此標誌應與hls_time選項一起使用。

-hls_playlist_type: event,發出#EXT-X-PLAYLIST-TYPE:m3u8標題中的EVENT。 強制hls_list_size為0; 播放列表(playlist)只能附加到。

點播內容:

此應用就是將一個mp4的影音檔案進行切割成HLS的切面,因此,也就是mp4的檔案轉換程式:

ffmpeg -i $1 -profile:v baseline -level 3.0 -s 640x360 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls ${1%.*}.m3u8

為了讓多數的播放器,特別是行動裝置,這裡將影音的格式轉為mpeg-4, h264, baseline level 3.0的格式,以及640×360的影片大小,讓絕大多數的播放器都可以正常播放。
-start_number 0: 從一開始就進行切片
-hls_list_size 0: 如前述,這裡因為是要把整個mp4檔案轉換,所以就不限定playlist的內容大小了。

有關ffmpeg的HLS以及格式參數可參考這網址:https://ffmpeg.org/ffmpeg-formats.html

MongoDB 3.4 Sharding 觀念、安裝、與配置

Sharding 為 MongoDB 所擁有的一種資料分散處理架構,簡單的說就是將資料分片 (Shard) 儲存到不同的機器中,最常應用在大數據的案例上。在海量資料的儲存情境上,垂直擴充架構是無法滿足的,必須透過水平擴充來實現。

MongoDB Sharded Cluster 基本的架構示意如下:

在這樣的機制下,儲存進 Collection 的資料會被盡可能平均地分散到每一個 Shard 上,每一個 Shard 都是由獨立的 mongod 實體或者 Replica Set 所構成 (想了解 Replica Set 可以看看之前的文章)。上圖我們也可以看到,Sharding 機制本身是不負責備份的,在產品上線的環境中,強烈建議使用 Replica Set 來搭建 MongoDB Sharded Cluster。在這個架構中,假設我們有 1TB 的資料,可以透過 Sharding 機制將資料切分為四個 Shard,每一個 Shard 負責儲存 256G,應該很好理解。

MongoDB Sharded Cluster 運作機制

那麼 MongoDB Sharded Cluster 是如何運作的呢?我們先看看下面的架構圖:

當使用者或應用程式 (Driver) 要操作 MongoDB Sharded Cluster 時,是透過 mongos 來進行連接,mongos 扮演 Router 的角色,Router 通常由多個實體組成,可以將 Loading 分散處理,保持高可用性 (HA)。對於應用程式來說,並不需要瞭解 MongoDB Sharding 怎麼運作的,他們看到的只是一個資料庫,所以使用上基本不會有太大的差別。如下所示:

之前提到,雖然每一個 Shard 都是由一個 mongod 或 Replica Set 構成,但如果沒有透過 mongos (Router) 進行連線操作,而直接對 Shard 進行連線,那麼你看到 Collection 的資料就不會是完整的集合,而只是單一個 Shard 的資料。那麼 Cluster 是如何分配資料呢,這裡有一個很重要的角色,就是 Config Server。

Config Server

Config Server 是 MongoDB Sharding 架構中相當重要的一個角色,它存放了資料的 Metadata,包括透過 Shard Key 計算出來的索引,用來記錄每一個資料存放的 Shard 位置,好讓 Router 可以正確的 Query 資料,如果沒有這些索引,那麼每一個用來存放資料的 mongod 實體,就「純粹」只是獨立存放分散的資料,無法協同工作。Config Server 聽起來很重要對吧!?因此 Config Server 部署時必須要多台機器,在新版 3.2 之後也可以用 Replica Set 架設 Config Server。

為了將資料分散儲存,就必須找一個方法來管理 Index,我們必須將 Document 某一個欄位定義為 Shard Key,然後透過 range based partitioning 或 hash based partitioning 其中一中方式將資料分配到 chunks 中 (每一個 Chunks 預設的大小為 64MB),最後才將 Chunks 分散到不同的 Shard 上。接下來我們先看看兩種不同的 Partitioning 機制:

Range Based Sharding

這種方式就是將 Document Shard Key 欄位的值,以線性的方式進行分群,透過 Range 範圍進行切割,相近的值理所當然會被分到同一個 Chunk 中,Chunk 分配的情況會直接受到 Range 的影響(比如某一段 Range 出現頻率高,Chunk 資料就比較大)。用這種方法我們必須考慮 Shard Key 的範圍,如下所示:

Hash Based Sharding

這種方法顧名思義就是透過「雜湊函式」將我們指定的 Shard Key 欄位進行雜湊,這樣的方式資料比較容易分散到每個 Shard 中,如果資料量足夠豐富,佔用空間的分配也會比較平均。如下:

比較一下兩種方法,Range Based 實際在 Query 時,Router 可以很輕易地判斷資料的位置,然後正確地派送運算到所屬的 Shard 上。但如果要查詢的資料片段大小差異過高,且又分散在不同的 Shard 上,查詢必定會「等待」其他 Shard 處理的情況產生。來看看 Hash Based,Shard Key 透過 Hash 計算後,很容易分散在不同的 Chunk,資料分散性佳,擴充也比較容易。但是在 Query 時就必須要經過比較多的 Shard 計算,才能由 Router 返回最後的結果。兩種方法各有利弊,可以依照實際的應用情況選用。那如果想要自行實作資料分散的邏輯呢?MongoDB 當然也是支援的,就是透過 Tag 這個功能,但我沒有研究,所以就無從介紹了。有興趣可以看看官方 Tag Aware Sharding 相關介紹。

開始建置:

由於 Shard 本身沒有備援機制,因此 MongoDB 的 Shard 必須建置在 Replica Set 上,Replica Set 建置方式請參考「MongoDB Replica Set 高可用性架構搭建」這一篇文章。假設您已經建立好 Replica Set,那麼就可以繼續接著開始建置 Shard。

我們規劃原來做的mongsh1~mongsh3三台伺服器,都拿來做shard server與config server,另外mongsh1/mongsh2拿來當router。

建置 Config Server

一開始我們先建立 Config Server,在 MongoDB Sharding Cluster 架構中,Config Server 必須有三個實體以上,強烈建議部署在不同的機器上,因為 Metadata 實在太重要了。下面的範例其實是與 Replica Set 一起部署,實際上分開會比較好。慣例上我們會先透過 /etc/hosts 管理我們的主機資訊 (用 DNS 也是可以),假設要安裝 Config Server 的 Hostname 為 mong-cfg1 ~ mong-cfg3

vi /etc/hosts
10.21.1.45 mongsh1
10.21.1.46 mongsh2
10.21.1.44 mongsh3

10.21.1.45 mong-cfg1
10.21.1.46 mong-cfg2
10.21.1.44 mong-cfg3

10.21.1.45 mong-router1
10.21.1.46 mong-router2

接著建立 Config Server 要存放的 DB File Directory,命令如下:

mkdir -p /home/mongodb-cfg
sudo chown -R mongodb:mongodb /home/mongodb-cfg

三台伺服器都要做。

然後建立 MongoDB Config Server 需要的設定檔,之後再透過 mongod 來載入啟用,因為我們測試環境的 Config Server 與 Replica Set 都在其實同一台機器(正式環境建議分開或分散比較好),Port 與 PID 都要不同,Port 隔開可以方便我們部署在不同機器,然而透過不同的設定檔也會比較好進行管理。大致上的 Port 分配如下:

  • Replica Set:27019 Port
  • Config Server:27018 Port
  • Mongo Router (mongos):27017 Port

編輯 Config Server 設定檔內容如下:

vi /etc/mongod-cfgserv.conf
storage:
  dbPath: /home/mongodb-cfg
  journal:
    enabled: true
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod-cfgserv.log
sharding:
   clusterRole: configsvr
net:
  port: 27018
  bindIp: 0.0.0.0
processManagement:
  fork: true
  pidFilePath: /var/run/mongod-cfgserv.pid

上面的設定檔先不開啟認證模式,官方規定在 Production 環境最少要配置三台以上的 Config Server。透過以下 mongod 命令分別在「mong-cfg1, mong-cfg2, mong-cfg3」三台機器各別透過 mongod 指令來啟用 Config Server。

sudo mongod -f /etc/mongod-cfgserv.conf

啟動後我們也可以在 /var/log/mongodb/mongod-cfgserv.log 看到 log 資訊。

建置 MongoDB Router

再來就是建置 MongoDB Sharding Router。首先建立 mongos 要載入的設定檔,基本上跟上面 Config Server 使用的 mongod 差不多。我們這裡測試用的 Router 是跟 Config Server 放在一起,實際上可分開存放會更好。

這裡,我們就都不設定認證模式,若有意設置,可參考這篇文章

設定檔內容如下:

sudo vi /etc/mongod-router.conf
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod-router.log
sharding:
  configDB: mong-cfg1:27018,mong-cfg2:27018,mongodb-cfg-3:27018
net:
  port: 27017
  bindIp: 0.0.0.0 
processManagement:
  fork: true
  pidFilePath: /var/run/mongodb-router.pid

我們可以看到上述的設定檔有指定 Config Server 的位置,好讓 Router 啟動時可以讀取 Config Server 中的 Metadata。也需要配置到另外一台伺服器mong-router2

如同上述的設定檔,先不用啟用認證來執行 mongos,主要是為了要先在 Config Server 中建立 User 好讓後續整個認證流程可以順利串起來,這裡通常大家都會遇到最多問題,很多人最後乾脆關閉認證來配置 Sharding,這樣其實很危險,不建議關閉認證。此外由於應用程式大多是透過 27017 Port 進行連線,所以要提供連線的 Router Bind 直接啟動在標準 MongoDB Port 這樣應用程式就不用修改囉。

先啟用其中一台的 MongoDB Sharding Router,等透過 Mongo Router 設定好 Config Server 之後再啟動所有的 Rouer 即可。注意這裡是用 mongos 命令來啟動喔,如下:

sudo mongos -f /etc/mongod-router.conf

配置自動啟動config與router服務:
於10.21.1.45與10.21.1.46兩台伺服器

vi /etc/rc.local
mongod -f /etc/mongod-cfgserv.conf
mongos -f /etc/mongod-router.conf

於10.21.1.44則配置如下

vi /etc/rc.local
mongod -f /etc/mongod-cfgserv.conf

建立 Sharding Cluster

接著我們透過認證模式進入 Mongo Router 來設定 Sharding,因為後端的 Monogd 是採用Replica Set 認證模式,所以配置 Sharding 的動作一定要透過同一把 Key 啟動,才能把服務整個串起來。以下透過我們建立好的管理者帳密登入 Mongo Router 來進行配置:

mongo mongodb-router1
mongos>sh.addShard("bes/mongodb-a1:27019,mongodb-a2:27019,mongodb-a3:27019")

加入後,再檢查一下狀態:

mongos> sh.status()
--- Sharding Status --- 
  sharding version: {
	"_id" : 1,
	"minCompatibleVersion" : 5,
	"currentVersion" : 6,
	"clusterId" : ObjectId("59b4e7b564bf31ba36e4615c")
}
  shards:
	{  "_id" : "bes",  "host" : "bes/mongsh1:27019,mongsh2:27019,mongsh3:27019",  "state" : 1 }
  active mongoses:
	"3.4.8" : 2
 autosplit:
	Currently enabled: yes
  balancer:
	Currently enabled:  yes
	Currently running:  no
		Balancer lock taken at Sun Sep 10 2017 20:27:09 GMT+0800 (CST) by ConfigServer:Balancer
	Failed balancer rounds in last 5 attempts:  5
	Last reported error:  Cannot accept sharding commands if not started with --shardsvr
	Time of Reported error:  Wed Sep 13 2017 11:18:59 GMT+0800 (CST)
	Migration Results for the last 24 hours: 
		No recent migrations
  databases:
	{  "_id" : "teammerge12",  "primary" : "bes",  "partitioned" : true }

mongos> 

實務的配置上,我們會部署多台 Router 來平衡應用程式端的查詢,在應用程式中也可以指定這一群「Router」作為 Server。到這裡 MongoDB Sharding Cluster 就算是被置完成囉,實際的使用上還需要指定 Collection Shard Key 來分配 Chunk 到不同的 Shard 上,這裡請自行參考 MongoDB 官方的 Shard Key 使用介紹。

GeoIP installation for PHP on Ubuntu 16.04

Installing GeoIP Module On Apache2, Ubuntu 16.04

  1. 以下面這個指令尋找Geoip的相關程式:
    apt search geoip
    

    將會從相關的套件裡找到 libapache2-mod-geoip

  2. 進行套件安裝與更新
    apt update
    apt upgrade
    apt install geoip-bin geoip-database libapache2-mod-geoip libgeoip1
    

    新增後,會產生 /usr/share/GeoIP/ 目錄。

  3. 下載GeoIP資料庫
    cd /usr/share/GeoIP/
    ls
    rm GeoIP.dat
    wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
    gunzip GeoIP.dat.gz
    wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
    gunzip GeoLiteCity.dat.gz
    wget http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
    gunzip GeoIPASNum.dat.gz
    

    在 /usr/share/GeoIP/ 目錄裡,會有三個檔案GeoIP.dat, GeoLiteCity.dat, GeoIPASNum.dat。

  4. 更新apache2的geoip設置:nano /etc/apache2/mods-enabled/geoip.conf
    GeoIPEnable On
    GeoIPDBFile /usr/share/GeoIP/GeoIP.dat
    GeoIPDBFile /usr/share/GeoIP/GeoLiteCity.dat
    GeoIPDBFile /usr/share/GeoIP/GeoIPASNum.dat基本上就已經設定完成。
  5. 重新啟動apache2
    apachectl -t
    sudo systemctl restart apache2.service

最後做一個範本試試看:

<?php 
$geoip_country_code = getenv(GEOIP_COUNTRY_CODE);
$geoip_country_name = getenv(GEOIP_COUNTRY_NAME);
$geoip_region = getenv(GEOIP_REGION);
$geoip_city = getenv(GEOIP_CITY);
$geoip_postal_code = getenv(GEOIP_POSTAL_CODE);
$geoip_latitude = getenv(GEOIP_LATITUDE);
$geoip_longitude = getenv(GEOIP_LONGITUDE);
 
echo 'Country code: '.$geoip_country_code.'&lt;br&gt;';
echo 'Country name: '.$geoip_country_name.'&lt;br&gt;';
echo 'Region: '.$geoip_region.'&lt;br&gt;';
echo 'City: '.$geoip_city.'&lt;br&gt;';
echo 'Postal code: '.$geoip_postal_code.'&lt;br&gt;';
echo 'Latitude: '.$geoip_latitude.'&lt;br&gt;';
echo 'Longitude: '.$geoip_longitude.'&lt;br&gt;'; 
?>

大功告成!!