這3台中型SUV一出來,什麼奔馳寶馬統統得靠邊

頂配的3。6T版本4。8 S的百公里加速性能更是令人折服。當然,300mm的涉水深度令人匪夷所思。而中控台上的空白按鍵時刻在提醒你:囊中羞澀以致某項配置未能選裝。此外,保時捷的售價就像你跟媽媽說晚上9點準時回家一樣不靠譜。

2018北京車展於4.25正式拉開帷幕,因工作關係得以參与這場人山人海的車界盛會。在車展上,除了各大傳統車企紛紛推出SUV新品外,諸多造車新勢力所亮相或展示的車型也是SUV為多,由此可見SUV的市場熱度一直未曾消減。

那些展出的SUV近乎都是:外觀愈發年輕、愈加運動“猙獰”,再難覓得一平庸之輩。若是將它們置於三五年前,必定都是明星車型。可在同質化異常嚴重的當下,已鮮有車型能在這股趨於一致的“年輕運動”的SUV洪流之中脫穎而出。

當然,也有例外。這幾款集情懷、血統、顏值、性能於一身的“尤物”備受青睞。

點評:一貫擅長打造英倫優雅紳士風的捷豹,強盛的藝術生命力在這款SUV上得以延續,俊朗精緻的外觀頗有幾分F-TYpE的神韻。年度風雲車、年度最佳設計等大獎便是對這走在時尚尖端寵兒的肯定。在老東家福特的EcoBoost 2.0T替換為自家的Ingenium 2.0T(2018沃德十佳發動機之一)后,性格變得愈加“狂豹”,低沉的聲浪時刻撩撥着駕駛者的慾望;早已滲透骨子里的獨特基因,令其在拐彎抹角的山間道路中犹如一隻飛馳的野豹。

點評:在卡宴身上嘗得SUV甜頭后,保時捷推出與老款Q5共享MLB平台(新款Q5L出自MLB EVO平台)的另一搖錢樹—Macan。萬年不變的青蛙臉令人百看不厭;跑車基因的加持,操控性能自然是無與倫比;頂配的3.6T版本4.8 S的百公里加速性能更是令人折服。當然,300mm的涉水深度令人匪夷所思;而中控台上的空白按鍵時刻在提醒你:囊中羞澀以致某項配置未能選裝。此外,保時捷的售價就像你跟媽媽說晚上9點準時回家一樣不靠譜。

點評:作為阿爾法羅密歐品牌百年歷史中第一款SUV產品,意大利人對藝術獨到的見解與對性能的痴迷在其身上得以極佳體現。精準的轉向、汽車愛好者極易上手的完美操控、恰到好處的零百以及超高的彎道極限令人愛不釋手。在北京車展上完成亞洲首秀的Stelvio QV版本更是紐北最快量產SUV圈速的記錄保持者。只是FCA的尿性,大家心照不宣,難怪有媒體朋友曾言:等我有錢了,就買它個兩台,一台修理一台開。

俗語言:逆水行舟,不進則退。在主流的市場里,品牌的差異性將變得越來越小,不論是國際品牌還是本土品牌。因此,“變通”是明智的生存之道。多數人認為保時捷、阿爾法羅密歐等豪華品牌推出SUV獲取更大市場份額意味着喪失了品牌的獨有特質。

但恰恰是這種“變通”,洞察出市場真正的需求點,才讓人看到更多好看的皮囊,感受到更多有趣的靈魂。畢竟只有存活下來,才能讓自身的基因得到延續。如果保時捷只生產跑車,捷豹只生產轎車,我們將錯過多少“尤物”呢?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

開着容易上癮,這3款10來萬的合資車,比朗逸好玩得多

6L的動力版本,會讓你在日常代步之餘,也能享受到小鋼炮的魅力。至於1。5T的,朋友,秋名山見。福克斯的短板在於儲物空間較為一般,後排在兩廂車這個級別裏面算是表現一般,中下的水平。致悅,沒錯,不是致炫,是來自菲亞特选手的致悅,至於為啥會推薦它,不是它表現的多突出,主要是價格便宜,優惠還大,這是許多人買車考慮的問題之一。

緊湊型車三廂的感覺操控不過來?

有便宜的兩廂車推薦嗎?

想買兩廂車怎麼辦?

有哪些兩廂車選擇?

首先是來自馬自達选手帶來的昂科賽拉,對於這款車大家都不陌生,操控就不說了,兩廂車操控還不好也不好意思推薦了,昂科賽拉的底盤懸挂是想要表揚的,一個字,穩,即使是高速過彎,你也不會覺得虛。

在眾多車企紛紛投入渦輪增壓發動機的大軍中去是,馬自達堅持做自吸發動機,這簡直是個異類,但是馬自達憑藉創馳藍天技術使得昂科賽拉在動力方面不遜色於搭載渦輪發動機的車型,而且還省油,這也是馬自達敢拿自吸發動機打着運動旗號的原因了。

後排較小,是昂科賽拉的短板,這也是許多馬自達車型的短板了,買馬自達的朋友們要注意哦~

另外是昂科賽拉在胎躁控制方面的還是不夠,這是許多車主反應的問題了。

福特选手帶來的則是福克斯,福克斯是大家心目中的理想車型之一了,美系車的隔音好,配置豐富的特點都具備,還有眾多的動力選擇。

1.0T的動力總成,對於日常上下班代步通勤的朋友們,會說,夠用!1.6L的動力版本,會讓你在日常代步之餘,也能享受到小鋼炮的魅力!至於1.5T的,朋友,秋名山見!

福克斯的短板在於儲物空間較為一般,後排在兩廂車這個級別裏面算是表現一般,中下的水平。

致悅,沒錯,不是致炫,是來自菲亞特选手的致悅,至於為啥會推薦它,不是它表現的多突出,主要是價格便宜,優惠還大,這是許多人買車考慮的問題之一。

除了價格之外,致悅的空間表現以及動力表現也是挺不錯的,全系搭載1.4T渦輪增壓發動機,動力能說不夠嗎?用車主的話說,就是一給油就跑!

從車身尺寸以及乘坐空間測試來看,致悅的表現在同級別不能說最好,但是中上水平還是可以有的。而讓人不滿意的是所搭配的DCT雙離合變速器在低擋換擋的時候頓挫感比較明顯。

以上三款車都是所推薦的兩廂車,綜合實力來說都是比較強的,各位看官可以根據自己的需求來挑選喲!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

想買車?看完最低9.9萬起的這6款全新SUV就可以下單了

我們再一起來回顧一下吧現代ENCINO是一款以性能著稱的小型SUV,搭載1。6T渦輪增壓發動機和雙離合器變速箱作為動力總成,177匹馬力的賬面參數也是十分誘人,配合上個性張揚的外觀設計和尚且不貴的售價,現代ENCINO要成為未來年輕人的首選車型的決心顯而易見。

《後來的我們》上映不久票房已超過10億,

繼《前任3》后又再一次給了年輕人5條建議:

1.如果結婚就要找愛你的

2.千萬別輸在“等”這個字身上

3.永遠留住30%的神秘

4.如何才能配得上你的伴侶?

關注玩車是

走向人生巔峰迎娶白富美嫁給高富帥的前提噢!

5.牢記第4條,前3條沒什麼用…

好吧,皮了一下,我們說回正事吧

看看了5月或將上市的車,

心想:除了個別車型,毫無驚喜!

這跟4月份的新車比起來,差距可不是一點點啊

起碼,全新的SUV,就有6款重磅新車了

不是改款,不是換代,

這幾款都是扎紮實實的新車、新SUV噢!

我們再一起來回顧一下吧

現代ENCINO是一款以性能著稱的小型SUV,搭載1.6T渦輪增壓發動機和雙離合器變速箱作為動力總成,177匹馬力的賬面參數也是十分誘人,配合上個性張揚的外觀設計和尚且不貴的售價,現代ENCINO要成為未來年輕人的首選車型的決心顯而易見。

威馬EX5是一款非常具有市場潛力的電動SUV,雖然是新品牌下的新車型,但是威馬公司背後的技術背書和他們自建工廠的生產方式讓他們的品牌形象顯得十分靠譜。而威馬EX5的實車已經正式上市,在2018年下半年就可以正式交付,EX5的設計非常符合大眾審美,屬於十分耐看的一款車型,而且續航里程可以達到400多公里的動力特性,也讓它十分有成為一二線限行城市的熱銷車型的潛力。

自主品牌非承載式SUV對於普通消費者來說更像是一個要麼廉價,要麼粗糙的存在。但是榮威RX8的上市便打破了這一種的傳統認知,榮威RX8的非承載式SUV和全時四驅的特性讓它有着比較出色的越野能力,而且定位豪華的RX8在內飾氛圍的設計上融入了非常多的木紋飾板和檔次感出眾的軟質材料,讓整車的檔次感顯現地非常到位。

對於越野有需求的消費者,或許就在途達上市以後有了新的選擇,非承載式車身,分時四驅,二十五萬以內的頂配售價,這些特點都在表明途達是一款可以入門越野圈的新車;而且久經市場考驗的動力總成更讓它的可靠性有所保障,雖然內飾設計相對廉價,但是對於追求更多在嚴苛環境下有靠譜表現的消費者來說,途達的產品力正是他們想要的。

Jeep在中國市場上的發力趨勢愈發明顯,相繼自由光,指南者這類車型在國內市場獲得一定成功以後,現如今又推出了一款中國特供的中型SUV,大指揮官。雖然這款車型是一款低於大切諾基的中型SUV,但是它的外觀與內飾設計,配置供給與裝配工藝等等方面都基本上稱得上是現如今合資國產的Jeep車型中的旗艦。售價區間與漢蘭達,銳界等車型有着高度重合,未來中型7座SUV中的強有力競爭者勢必將會多出大指揮官的身影。

GLC和Q5在BBA的豪華中型SUV市場稱雄已久,操控大師寶馬也就看不過眼了,華晨寶馬X3正式在中國上市,都說它沒有加長會影響車內空間,但其實這款車型換代后本就有了一定車身尺寸上的增加,所以空間並不是什麼硬傷,相反,更原汁原味的引入國產化后的Q3勢必會成為BBA中型SUV中最具運動基因的一款車型,而廣大寶馬迷們在X3上市以後也必定有了更為接地氣和更實惠的車型備選方案。

怎麼樣,這幾款新SUV很吸引吧~

感興趣的話不妨去4S店看看實車噢本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

15萬買啥車?有轎車有SUV,這2款合資車可以放心買

勁客的優勢在於成熟可靠的動力總成,採用1。5L自然吸氣發動機+CVT無級變速器的搭配能夠帶來非常平順線性的輸出,油門調校靈敏,能夠很好地應付日常市區內行駛,並且也非常省油,可靠性較高。不過其檔次感與配置水平不如哈弗H2。

15萬左右比較推薦的是本田XR-V與豐田卡羅拉,這兩款車目前在市場上都有着不錯的銷量、保值率以及口碑,XR-V在小型SUV市場混得風生水起,靠的就是其成熟的動力系統和越級的空間表現,家用是個非常棒的選擇。而卡羅拉乃全球銷量神車,中庸就是其最大的武器,除了汽油版本外還有雙擎版本可選,擁有非常優秀的燃油經濟性,能夠滿足許許多多的消費者,除了隔音濾振差點,其它方面的表現都非常不錯,乃家用車的不二之選。

一輛是接近中型車的緊湊型車,一輛是標準的中型車,凌渡280DSG豪華版擁有更加豐富的配置,不過因為其比較扁平的設計所以頭部空間表現一般,而君威中型車的身份自然擁有更大的空間以及更高的檔次感,同時全系標配9AT也讓其競爭力進一步上升,採用的1.5T發動機也有着不錯的動力輸出,因此更推薦君威1.5T中配。

510採用的是6擋手動變速器和5擋AMT變速器,假設會開手動擋的話更加推薦手動車型,6個擋位在高速行駛時把轉速壓得更低,能帶來更好的燃油經濟性,同時擁有更高的傳動效率及可靠性,510的手動擋換擋手感不錯,有吸入感並且行程不長,離合器的力度也不沉,沒那麼容易疲勞。而AMT變速器雖然說省去了踩離合器的麻煩,但是其換擋邏輯不清晰,而且頓挫比較嚴重,尤其是在起步階段或者是在堵車狀況下,因此更加推薦510的手動版車型。

兩車都是定位小型SUV,哈弗H2擁有更加親民的售價,更加大氣上檔次的外觀內飾設計,同時配置更加豐富,採用的1.5T發動機+7擋雙離合的搭配,擁有不錯的爆發力,但是雙離合變速器的邏輯有待提高,並且油耗也會偏高。

勁客的優勢在於成熟可靠的動力總成,採用1.5L自然吸氣發動機+CVT無級變速器的搭配能夠帶來非常平順線性的輸出,油門調校靈敏,能夠很好地應付日常市區內行駛,並且也非常省油,可靠性較高。不過其檔次感與配置水平不如哈弗H2。

綜上,假如你預算充足的話,更加建議購買勁客的中配以上車型,而預算不是很足的話,那麼家用選擇H2是一個非常具有性價比的選擇。

2018款飛度新增了運動套件車型,不過在配置方面還是一如既往的寒酸,比較推薦指導價為8.88萬的1.5L CVT潮跑版,在配置上面擁有主/副駕駛座安全氣囊、運動外觀套件、行車電腦显示屏、前霧燈等,類似比較常用的电子車身穩定系統、駐車雷達要到頂配才配備,但是飛度的動力和空間還是非常不錯的,1.5L自吸發動機就能爆發出131匹馬力,日常市區駕駛毫無壓力,加上本田“MM”理念,讓它的空間能夠滿足大多數人的使用需求,市面上大量的改裝件也能讓每位飛度車主把愛車改成獨一無二的樣子。

以上就是本期網友問答欄目的全部內容,假如你也想上牆的話,點擊下方留言留下你的問題並且點個贊,就有機會在下期欄目看見你的身影!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

初識Redis的數據類型HyperLogLog

前提

未來一段時間開發的項目或者需求會大量使用到Redis,趁着這段時間業務並不太繁忙,抽點時間預習和複習Redis的相關內容。剛好看到博客下面的UVPV統計,想到了最近看書裏面提到的HyperLogLog數據類型,於是花點時間分析一下它的使用方式和使用場景(暫時不探究HyperLogLog的實現原理)。RedisHyperLogLog數據類型是Redid 2.8.9引入的,使用的時候確保Redis版本>= 2.8.9

HyperLogLog簡介

基數計數(cardinality counting),通常用來統計一個集合中不重複的元素個數。一個很常見的例子就是統計某個文章的UVUnique Visitor,獨立訪客,一般可以理解為客戶端IP)。大數據量背景下,要實現基數計數,多數情況下不會選擇存儲全量的基數集合的元素,因為可以計算出存儲的內存成本,假設一個每個被統計的元素的平均大小為32bit,那麼如果統計一億個數據,佔用的內存大小為:

  • 32 * 100000000 / 8 / 1024 / 1024 ≈ 381M

如果有多個集合,並且允許計算多個集合的合併計數結果,那麼這個操作帶來的複雜度可能是毀滅性的。因此,不會使用BitmapTree或者HashSet等數據結構直接存儲計數元素集合的方式進行計數,而是在不追求絕對準確計數結果的前提之下,使用基數計數的概率算法進行計數,目前常見的有概率算法以下三種:

  • Linear Counting(LC)
  • LogLog Counting(LLC)
  • HyperLogLog Counting(HLL)

所以,HyperLogLog其實是一種基數計數概率算法,並不是Redis特有的,Redis基於C語言實現了HyperLogLog並且提供了相關命令API入口。

Redis的作者Antirez為了紀念Philippe Flajolet對組合數學和基數計算算法分析的研究,所以在設計HyperLogLog命令的時候使用了Philippe Flajolet姓名的英文首字母PF作為前綴。也就是說,Philippe Flajolet博士是HLL算法的重大貢獻者,但是他其實並不是RedisHyperLogLog數據類型的開發者。遺憾的是Philippe Flajolet博士於2011年3月22日因病在巴黎辭世。這個是Philippe Flajolet博士的維基百科照片:

Redis提供的HyperLogLog數據類型的特徵:

  • 基本特徵:使用HyperLogLog Counting(HLL)實現,只做基數計算,不會保存元數據
  • 內存佔用:HyperLogLog每個KEY最多佔用12K的內存空間,可以計算接近2^64個不同元素的基數,它的存儲空間採用稀疏矩陣存儲,空間佔用很小,僅僅在計數基數個數慢慢變大,稀疏矩陣佔用空間漸漸超過了閾值時才會一次性轉變成稠密矩陣,轉變成稠密矩陣之後才會佔用12K的內存空間。
  • 計數誤差範圍:基數計數的結果是一個標準誤差(Standard Error)為0.81%的近似值,當數據量不大的時候,得到的結果也可能是一個準確值。

內存佔用小(每個KEY最高佔用12K)是HyperLogLog的最大優勢,而它存在兩個相對明顯的限制:

  • 計算結果並不是準確值,存在標準誤差,這是由於它本質上是用概率算法導致的。
  • 不保存基數的元數據,這一點對需要使用元數據進行數據分析的場景並不友好。

HyperLogLog命令使用

Redis提供的HyperLogLog數據類型一共有三個命令APIPFADDPFCOUNTPFMERGE

PFADD

PFADD命令參數如下:

PFADD key element [element …]

支持此命令的Redis版本是:>= 2.8.9
時間複雜度:每添加一個元素的複雜度為O(1)

  • 功能:將所有元素參數element添加到鍵為keyHyperLogLog數據結構中。

PFADD命令的執行流程如下:

PFADD命令的使用方式如下:

127.0.0.1:6379> PFADD food apple fish
(integer) 1
127.0.0.1:6379> PFADD food apple
(integer) 0
127.0.0.1:6379> PFADD throwable
(integer) 1
127.0.0.1:6379> SET name doge
OK
127.0.0.1:6379> PFADD name throwable
(error) WRONGTYPE Key is not a valid HyperLogLog string value.

雖然HyperLogLog數據結構本質是一個字符串,但是不能在String類型的KEY使用HyperLogLog的相關命令。

PFCOUNT

PFCOUNT命令參數如下:

PFCOUNT key [key …]

支持此命令的Redis版本是:>= 2.8.9
時間複雜度:返回單個HyperLogLog的基數計數值的複雜度為O(1),平均常數時間比較低。當參數為多個key的時候,複雜度為O(N),N為key的個數。

  • PFCOUNT命令使用單個key的時候,返回儲存在給定鍵的HyperLogLog數據結構的近似基數,如果鍵不存在, 則返回0
  • PFCOUNT命令使用key的時候,返回儲存在給定的所有HyperLogLog數據結構的並集的近似基數,也就是會把所有的HyperLogLog數據結構合併到一個臨時的HyperLogLog數據結構,然後計算出近似基數。

PFCOUNT命令的使用方式如下:

127.0.0.1:6379> PFADD POST:1 ip-1 ip-2
(integer) 1
127.0.0.1:6379> PFADD POST:2 ip-2 ip-3 ip-4
(integer) 1
127.0.0.1:6379> PFCOUNT POST:1
(integer) 2
127.0.0.1:6379> PFCOUNT POST:1 POST:2
(integer) 4
127.0.0.1:6379> PFCOUNT NOT_EXIST_KEY
(integer) 0

PFMERGE

PFMERGE命令參數如下:

PFMERGE destkey sourcekey [sourcekey ...]

支持此命令的Redis版本是:>= 2.8.9
時間複雜度:O(N),其中N為被合併的HyperLogLog數據結構的數量,此命令的常數時間比較高

  • 功能:把多個HyperLogLog數據結構合併為一個新的鍵為destkeyHyperLogLog數據結構,合併后的HyperLogLog的基數接近於所有輸入HyperLogLog的可見集合(Observed Set)的並集的基數。
  • 命令返回值:只會返回字符串OK

PFMERGE命令的使用方式如下

127.0.0.1:6379> PFADD POST:1 ip-1 ip-2
(integer) 1
127.0.0.1:6379> PFADD POST:2 ip-2 ip-3 ip-4
(integer) 1
127.0.0.1:6379> PFMERGE POST:1-2 POST:1 POST:2
OK
127.0.0.1:6379> PFCOUNT POST:1-2
(integer) 4

使用HyperLogLog統計UV的案例

假設現在有個簡單的場景,就是統計博客文章的UV,要求UV的計數不需要準確,也不需要保存客戶端的IP數據。下面就這個場景,使用HyperLogLog做一個簡單的方案和編碼實施。

這個流程可能步驟的先後順序可能會有所調整,但是要做的操作是基本不變的。先簡單假設,文章的內容和統計數據都是後台服務返回的,兩個接口是分開設計。引入Redis的高級客戶端Lettuce依賴:

<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>5.2.1.RELEASE</version>
</dependency>

編碼如下:

public class UvTest {

    private static RedisCommands<String, String> COMMANDS;

    @BeforeClass
    public static void beforeClass() throws Exception {
        // 初始化Redis客戶端
        RedisURI uri = RedisURI.builder().withHost("localhost").withPort(6379).build();
        RedisClient redisClient = RedisClient.create(uri);
        StatefulRedisConnection<String, String> connect = redisClient.connect();
        COMMANDS = connect.sync();
    }

    @Data
    public static class PostDetail {

        private Long id;
        private String content;
    }

    private PostDetail selectPostDetail(Long id) {
        PostDetail detail = new PostDetail();
        detail.setContent("content");
        detail.setId(id);
        return detail;
    }

    private PostDetail getPostDetail(String clientIp, Long postId) {
        PostDetail detail = selectPostDetail(postId);
        String key = "puv:" + postId;
        COMMANDS.pfadd(key, clientIp);
        return detail;
    }

    private Long getPostUv(Long postId) {
        String key = "puv:" + postId;
        return COMMANDS.pfcount(key);
    }

    @Test
    public void testViewPost() throws Exception {
        Long postId = 1L;
        getPostDetail("111.111.111.111", postId);
        getPostDetail("111.111.111.222", postId);
        getPostDetail("111.111.111.333", postId);
        getPostDetail("111.111.111.444", postId);
        System.out.println(String.format("The uv count of post [%d] is %d", postId, getPostUv(postId)));
    }
}

輸出結果:

The uv count of post [1] is 4

可以適當使用更多數量的不同客戶端IP調用getPostDetail(),然後統計一下誤差。

題外話-如何準確地統計UV

如果想要準確統計UV,則需要注意幾個點:

  • 內存或者磁盤容量需要準備充足,因為就目前的基數計數算法來看,沒有任何算法可以在不保存元數據的前提下進行準確計數。
  • 如果需要做用戶行為分析,那麼元數據最終需要持久化,這一點應該依託於大數據體系,在這一方面筆者沒有經驗,所以暫時不多說。

假設在不考慮內存成本的前提下,我們依然可以使用Redis做準確和實時的UV統計,簡單就可以使用Set數據類型,增加UV只需要使用SADD命令,統計UV只需要使用SCARD命令(時間複雜度為O(1),可以放心使用)。舉例:

127.0.0.1:6379> SADD puv:1 ip-1 ip-2
(integer) 2
127.0.0.1:6379> SADD puv:1 ip-3 ip-4
(integer) 2
127.0.0.1:6379> SCARD puv:1
(integer) 4

如果這些統計數據僅僅是用戶端展示,那麼可以採用異步設計:

在體量小的時候,上面的所有應用的功能可以在同一個服務中完成,消息隊列可以用線程池的異步方案替代。

小結

這篇文章只是簡單介紹了HyperLogLog的使用和統計UV的使用場景。總的來說就是:在(1)原始數據量巨大,(2)內存佔用要求盡可能小,(3)允許計數存在一定誤差並且(4)不要求存放元數據的場景下,可以優先考慮使用HyperLogLog進行計數。

參考資料:

  • antirez-Redis new data structure: the HyperLogLog
  • Redis Commands
  • 維基百科

(本文完 c-3-d e-a-20191117)

技術公眾號(《Throwable文摘》),不定期推送筆者原創技術文章(絕不抄襲或者轉載):

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

容器技術之Docker資源限制

  上一篇我們聊到了docker容器的單機編排工具docker-compose的簡單使用,回顧請參考https://www.cnblogs.com/qiuhom-1874/p/13121678.html;今天我們主要來聊一聊docker容器的資源限制;通常情況下我們啟動一個docker容器,其內存和CPU都是同宿主機一樣大,這意味着該容器和宿主機共享相同大小的內存和CPU資源;這樣一來容器正常情況下沒有什麼問題,假如容器里運行的進程特別愛吃內存,很可能存在把宿主機上的內存全部吃掉,觸發內核OOM,從而導致docker daemon直接被內核殺死;為了避免這樣的尷尬局面,對啟動容器我們有必要對容器的資源進行限制;

  所謂OOM就是當系統上的應用申請內存資源時,發現申請不到內存,這個時候Linux內核就會啟動OOM,內核將給系統上的所有進程進行評分,通過評分得分最高的進程就會被系統第一個幹掉,從而騰出一些內存空間,如果騰出的內存空間還是不夠該應用使用,它會繼續殺得分第二高的,直到應用有足夠的內存使用;一旦發生OOM,任何進程都有可能被殺死,包括docker daemon在內,為此,docker特定調整了docker daemon的oom優先級,以免發生oom被內核殺死,但是容器的oom優先級並未做任何調整;

  那麼對於內存資源來講,在啟動為容器時,我們可以通過一些選項來指定容器的內存相關設置;如下圖

  提示:-m 或 –memory 用來指定容器最大能夠使用的內存大小,默認情況不指定表示共享物理宿主機的內存大小;–memory-swap 用來指定容器的內存和交換內存的總大小;對於這個參數的取值比較詭異;待會在說吧;–memory-swappiness該選項用來指定容器使用交換內存的傾向性,swap啟用有個好處就是在內存不夠使用的情況,它可以臨時頂替一部分,但是性能會急劇下降;所以数字越大越早使用交換內存,数字越小越晚使用交換內存,取值在0-100之間;0不代表不是用交換內存,0表示能不用交換內存,則不用,但是在迫不得已的情況還是會使用的,100表示只要有一絲可以使用交換內存的希望,就使用交換內存;通常情況在運行容器的主機上不建議使用swap設備;swap交換分區如果一旦被激活,系統性能會急劇下降,建議直接禁用;–memory-reservation該選項用來指定給系統保留的內存空間大小;–kernel-memory用來指定給內核保留的內存大小;–oom-kill-disable該選項用於指定當發生oom時,是否禁用因oom而殺死該容器進程;

  提示:通常情況–memory-swap這個選項必須同–memory選項一起使用,不可用單獨使用;

  示例:限制容器使用最大內存為256M

[root@docker_registry ~]# docker run --name test --rm -m 256M lorel/docker-stress-ng --vm 2

  提示:以上命令表示啟動一個名為test的容器,限制該容器最大使用內存大小為256M;lorel/docker-stress-ng這個進行用來壓測容器;–vm表示同時使用多少進程來做壓測;

  驗證:用docker stats看看我們啟動test容器是否只能使用256M內存?

  提示:從上面的結果可以看到,在我們啟動容器時,使用-m指定內存大小的容器limit的值就是我們指定的值,而對於沒有用-m指定的容器,默認就是同宿主機內存大小一樣;

  對於CPU來講,默認情況啟動容器時,不限制CPU的資源,此時容器是共享宿主機的CPU資源,也就是說默認情況宿主機上有幾顆cpu核心,啟動的容器就有多少顆核心;對於CPU這種可壓縮資源,不會像內存那樣,如果CPU滿載,也不會導致某個容器崩潰,原因是因為cpu是可壓縮資源;而不同於內存,內存屬於不可壓縮資源,如果申請不到內存,就會出現異常,出現oom;對啟動容器來限制cpu資源,通常也是使用選項來限定;如下圖

  提示:–cpus用來指定容器能夠使用的最大cpu核心數,例如–cpus=1.5,就表示該容器最大能夠使用1.5核的CPU資源,如果宿主機上有4顆CPU核心,那麼該容器最多可把1.5顆核心跑滿;這樣說吧,如果宿主機上有4顆核心,那麼該容器如果使用–cpus限定為1.5,那麼該容器就只能使用宿主機上的百分之150的核心;–cpu-period 和–cpu-quota該選項在docker1.13以後基本廢棄;–cpuset-cpus該選項用於指定容器能夠在哪些CPU上運行;如果宿主機上有4顆CPU,–cpuset-cpus=2,3就表示該容器只能使用第2號cpu和第3號cpu;–cpu-shares該選項用於指定容器使用cpu的比例;比如宿主機上只有一個容器,而該容器啟動時指定–cpu-shares=1024,則表示,如果沒有其他容器,則它可以使用宿主機上的所有cpu資源,如果有第二個容器啟動時,指定cpu-shares=512,那麼第一個容器會從原來使用整個宿主機的cpu變為使用整個宿主機的cpu的2/3;以此類推,如果有第三個,第四個,他們使用cpu資源都是按照給定的比例動態調整;

  示例:第一個容器使用–cpu-shares=256;第二個容器使用–cpu-shares=512,看看當第一個容器啟動后,看看cpu使用情況,然後第二個容器啟動后再看看cpu使用情況

  提示:可以看到當第一個容器啟動時,雖然設置的cpu-shares=256,但是它還是把所有核心幾乎都跑滿了;我們在跑一個容器看看,看看第二個容器啟動后,第一個容器的cpu使用情況是否有變化?

  提示:從上面的結果看,t1和t2的cpu使用比例大概是1比2;總量還是400%並沒有變化;

  示例:設置容器使用1.5個CPU核心

  提示:從上面的結果可以看到使用–cpus來限定容器使用的CPU資源,默認它會在每顆黑核心上都要使用一部分,但是重量不會超過150%;

  示例:限定容器使用CPU核心,只能在0號和3號核心上使用;

  提示:從上面的結果可以看到,限定t1容器只能使用0號和3號CPU后,1號和2號就基本不會被使用,總量也不會增加;

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

【Spring註解驅動開發】面試官:如何將Service注入到Servlet中?朋友又栽了!!

寫在前面

最近,一位讀者出去面試前準備了很久,信心滿滿的去面試。沒想到面試官的一個問題把他難住了。面試官的問題是這樣的:如何使用Spring將Service注入到Servlet中呢?這位讀者平時也是很努力的,看什麼源碼啊、多線程啊、高併發啊、設計模式啊等等。沒想到卻在一個很簡單的問題上栽了跟頭,這就說明學習知識要系統化,要有條理,切忌東學一點,西記一點,否則,到頭來,啥也學不到。

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

如何實現將Service注入到Servlet中??

這裏,我們列舉兩種解決方法(推薦使用第二種)

方法一:

直接重寫Servlet的Init()方法,代碼如下:

public void init(ServletConfig servletConfig) throws ServletException {
	ServletContext servletContext = servletConfig.getServletContext();
	WebApplicationContext webApplicationContext = WebApplicationContextUtils
			.getWebApplicationContext(servletContext);
	AutowireCapableBeanFactory autowireCapableBeanFactory = webApplicationContext
			.getAutowireCapableBeanFactory();
	autowireCapableBeanFactory.configureBean(this, BEAN_NAME);
}

這裏的BEAN_NAME即為我們需要注入到Spring容器中的服務,但這並不是一個好的方法,因為我們需要在每一個Servlet中都進行這樣的操作。

方法二:

我們可以寫一個類似於“org.springframework.web.struts.DelegatingRequestProcessor”的委託的Bean,然後通過配置的方法把我們的服務注入到servlet中,具體方法如下,

Step 1:編寫委託類DelegatingServletProxy

package com.telek.pba.base.util;

import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
 * 以下是類似org.springframework.web.struts.DelegatingRequestProcessor的一個委託
 * 用於通過配置的方法,在Servlet中注入Service
 * @author binghe
 * */
public class DelegatingServletProxy extends GenericServlet{
    private static final long serialVersionUID = 1L;
    private String targetBean;
    private Servlet proxy;

   @Override
   public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException{
   		proxy.service(req, res);
   }
     /**
      * 初始化
      */
      public void init() throws ServletException {
          this.targetBean = getServletName();
          getServletBean();
          proxy.init(getServletConfig());
      }

     /**
      * 獲取Bean
      */
      private void getServletBean() {
          WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
          this.proxy = (Servlet) wac.getBean(targetBean);
      }
}

Step 2:修改Web.xml配置

在純Servlet模式下,我們的配置方式如下(以下由於代碼高亮插件的問題,請將代碼中的#替換成尖括號)

<servlet>
  <description>活動發起模塊活動查詢分頁Servlet</description>
  <display-name>launchActivityQueryServlet</display>
  <servlet-name>LaunchActivityQueryServlet</servlet-name>
  <servlet-class>com.telek.pba.launch.servlet.LaunchActivityQueryServlet</servlet-class>
<servlet>

<servlet-mapping>
  <servlet-name>LaunchActivityQueryServlet</servlet-name>
  <url-pattern>/servlet/launch/LaunchActivityQueryServlet</url-pattern>
</servlet-mapping>
</servlet>

如果採用我們這種代理的方法,則配置應該修改為:

<servlet>
  <description>活動發起模塊活動查詢分頁Servlet</description>
  <display-name>launchActivityQueryServlet</display>
  <servlet-name>launchActivityQueryServlet</servlet-name>
  <servlet-class>com.telek.pba.base.util.DelegatingServletProxy</servlet-class>
<servlet>

<servlet-mapping>
  <servlet-name>launchActivityQuery</servlet-name>
  <url-pattern>/servlet/launch/LaunchActivityQueryServlet</url-pattern>
</servlet-mapping>
</servlet> 

注意:默認情況下,Servlet的配置中,LaunchActivityQuery的首字母一般為大寫,而我們的標題中已註明,我們採用Spring的註解模式,如果是自動掃描註解的話,默認情況下,註解的value值為首字母小寫,即:launchActivityQuery,因此,在我們新的配置中,要注意將首字母改為小寫,否則會報無法找到Bean的錯誤。

Step 3:至此,我們就可以像SSH的注入方式一樣,注入Servlet了,以下是個小示例:

package com.telek.pba.launch.servlet;

import java.io.IOException;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import com.telek.pba.base.model.PbaUserInfo;
import com.telek.pba.launch.dao.IPbaActivityInfoCurrentDAO;

@Component
public class LaunchActivityQueryServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	 
	//注入IPbaActivityInfoCurrentDAO
	@Resource
	private IPbaActivityInfoCurrentDAO pbaActivityInfoCurrentDAO;

	public LaunchActivityQueryServlet() {
		super();
	}
	 
	public void destroy() {
		super.destroy(); // Just puts "destroy" string in log
		// Put your code here
	}
	 
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//sth to do
	}
	 
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//sth to do
	}
	 
	public void init() throws ServletException {
		// Put your code here
	}
}

最後,請留心在Spring配置文件中,配置上自動掃描包的路徑:

<context:component-scan base-package="com.telek.pba.*.dao.impl,
 					com.telek.pba.*.service.impl,
 					com.telek.pba.*.servlet"/>

大功告成!

好了,咱們今天就聊到這兒吧!別忘了給個在看和轉發,讓更多的人看到,一起學習一起進步!!

項目工程源碼已經提交到GitHub:https://github.com/sunshinelyz/spring-annotation

寫在最後

如果覺得文章對你有點幫助,請微信搜索並關注「 冰河技術 」微信公眾號,跟冰河學習Spring註解驅動開發。公眾號回復“spring註解”關鍵字,領取Spring註解驅動開發核心知識圖,讓Spring註解驅動開發不再迷茫。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

小師妹學JVM之:GC的垃圾回收算法

目錄

  • 簡介
  • 對象的生命周期
  • 垃圾回收算法
    • Mark and sweep
    • Concurrent mark sweep (CMS)
    • Serial garbage collection
    • Parallel garbage collection
    • G1 garbage collection
    • Z Garbage Collection
  • 怎麼選擇
  • 總結

簡介

JVM的重要性不言而喻了,如果把java的應用程序比作一輛跑車,那麼JVM就是這輛車的發動機,沒有它,java程序就成了空中樓閣,無根浮萍。而在JVM中有一塊內存區域叫做運行時數據區域,存儲了運行時所需要的所有對象,而Heap Area則是其中最大的一塊。

內存畢竟不是無限的,所以就需要一種機制來將不再使用的對象進行回收,這種機制就是今天我們要講的GC。

更多精彩內容且看:

  • 區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新
  • Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
  • Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
  • java程序員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程

對象的生命周期

小師妹:F師兄,你相信這個世界有輪迴嗎?

師兄我是一個堅定的無神論者,活在當下就好了,何必操心後面的輪迴呢?

小師妹:F師兄,這個你就不懂了,意識是組成腦的原子群的一種組合模式,我們大腦的物質基礎和一塊石頭沒有什麼不同。當我們掌握大腦的組合方式,然後重構,我們的意識就重現了,這就是輪迴。這可是量子理論中提到的觀念哦。

哇,小師妹什麼時候這麼厲害了,都開始探討這麼高深的話題了。F師兄我實在是跟不上節奏啊。

小師妹,F師兄,我是怕你尷尬,想引出java對象的生命周期這個話題嘛。

量子理論我不熟,java對象我還沒怕過誰。

對象的生命周期其實很簡單:創建,使用中,最後被銷毀。

  1. 創建對象

舉個最簡單的創建對象的例子:

Object obj = new Object();

對象創建的時候,將會為該對象分配特定的空間。

  1. 使用對象

對象創建之後,就可以被其他的對象使用,如果其他的對象有使用該對象,那麼我們成為該對象被引用了。

  1. 對象銷毀

當一個對象沒有被其他對象引用的時候,我們就稱為該對象可以被回收了。在Java中,對象的回收是由GC來負責的。

垃圾回收算法

小師妹:F師兄,我覺得垃圾回收好像挺簡單的,我們為每個對象維持一個指針計數器,每引用一次就加一,這樣不就可以實現垃圾回收器了嗎?

底層原理是這麼一個道理,但是JVM需要一種更加高效的算法來保證垃圾回收的效率,同時也不會影響正在運行的程序。

接下來我們將會介紹一下,在JVM中比較常用幾個垃圾回收算法:

Mark and sweep

Mark and sweep是最最簡單的垃圾回收算法,簡單點講,它可以分為兩個步驟:

  1. 標記live對象

標記live對象聽起來很簡單,就是掃描堆中的對象,看這些對象是否被引入。

但是這裡有一個問題,如果是兩個對象互相引用的時候,而這兩個對象實際上並沒有被外部的對象所引用,那麼這兩個對象其實是應該被回收的。所以我們還需要解決一個關鍵性的問題:從哪裡開始掃描的問題。

JVM定義了一些Root對象,從這些對象開始,找出他們引用的對象,組成一個對象圖。所有在這個圖裡面的對象都是有效的對象,反之不在對象圖中的對象就應該被回收。有效的對象將會被Mark為alive。

這些Root對象包括:正在執行的方法中的本地對象和輸入參數。活動的線程,加載類中的static字段和JNI引用。

注意,這種遍歷其實是有個缺點的,因為為了找到對象圖中哪些對象是live的,必須暫停整個應用程序,讓對象變成靜止狀態,這樣才能構建有效的對象圖。後面我們會介紹更加有效的垃圾回收算法。

  1. 刪除對象

掃描對象之後,我們就可以將未標記的對象刪除了。

刪除有三種方式,第一種方式是正常刪除。但是正常刪除會導致內存碎片的產生。所以第二種方式就是刪除之後進行壓縮,以減少內存碎片。還有一種方式叫做刪除拷貝,也就是說將alive的對象拷貝到新的內存區域,這樣同樣可以解決內存碎片的問題。

Concurrent mark sweep (CMS)

在講CMS之前,我們先講一下垃圾回收器中的Eden,Old和Survivor space幾個大家應該都很熟悉的分代技術。

Young Gen被劃分為1個Eden Space和2個Suvivor Space。當對象剛剛被創建的時候,是放在Eden space。垃圾回收的時候,會掃描Eden Space和一個Suvivor Space。如果在垃圾回收的時候發現Eden Space中的對象仍然有效,則會將其複製到另外一個Suvivor Space。

就這樣不斷的掃描,最後經過多次掃描發現任然有效的對象會被放入Old Gen表示其生命周期比較長,可以減少垃圾回收時間。

之後要將的幾個垃圾回收器,除了ZGC,其他都使用的是分代的技術。

好了,現在繼續講CMS,CMS是mark and swap的升級版本,它使用多個線程來對heap區域進行掃描,從而提升效率。

CMS在Young Generation中使用的是mark-copy,而在Old Generation主要使用的是mark-sweep。

使用CMS的命令很簡單:

-XX:+UseConcMarkSweepGC

上面是列出的一些CMS的調優參數。

Serial garbage collection

Serial garbage collection使用單一的線程來進行垃圾回收操作,其好處就是不需要和其他的線程進行交互。如果你是單核的CPU,那麼最好就是選擇Serial garbage collection,因為你不能充分利用多核的好處。同樣的它也常常用在比較小型的項目中。

Serial garbage collection在Young Generation中使用的是mark-copy,而在Old Generation主要使用的是 mark-sweep-compact。

下面是開啟命令:

-XX:+UseSerialGC

Parallel garbage collection

和serial GC類似,它在Young Generation中使用的是mark-copy,而在Old Generation主要使用的是 mark-sweep-compact。不同的是它是并行的。

可以通過下面的命令來指定併發的線程:

-XX:ParallelGCThreads=N

如果你是多核處理器,那麼Parallel GC可能是你的選擇。

Parallel GC是JDK8中的默認GC。而在JDK9之後, G1是默認的GC。

使用下面的命令來開啟Parallel GC:

-XX:+UseParallelGC

G1 garbage collection

為什麼叫G1呢,G1=Garbage First,它是為替換CMS而生的,最早出現在java7中。

G1將heap區域劃分成為多個更小的區域,每個小區域都被標記成為young generation 或者old generation。從而運行GC在更小的範圍里運行,而不是影響整個heap區域。

可以使用下面的命令來開啟:

-XX:+UseG1GC 

Z Garbage Collection

ZGC是一個可擴展的,低延遲的GC。ZGC是併發的,而且不需要停止正在運行的線程。

使用下面的命令來開啟:

 -XX:+UseZGC 

ZGC是在JDK11中被引入的。

怎麼選擇

小師妹:F師兄,你講了這麼多個GC,到底我該用哪個呢?

高射炮不能用來打蚊子,所以選擇合適的GC才是最終要的。這裏F師兄給你幾個建議:

  1. 如果你的應用程序內存本來就很小,那麼使用serial collector : -XX:+UseSerialGC.

  2. 如果你的程序運行在單核的CPU上,並且也沒有程序暫停時間的限制,那麼還是使用serial collector : -XX:+UseSerialGC.

  3. 如果對峰值期的性能要求比較高,但是對程序暫停時間沒多大的要求,那麼可以使用 parallel collector: -XX:+UseParallelGC。

  4. 如果更加關注響應時間,並且GC的對程序的暫停時間必須要小,那麼可以使用-XX:+UseG1GC。

  5. 如果響應時間非常重要,並且你在使用大容量的heap空間,那麼可以考慮使用ZGC: -XX:UseZGC。

總結

本文介紹了幾種GC的算法,大家可以根據需要選用。

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/jvm-gc-algorithms/

本文來源:flydean的博客

歡迎關注我的公眾號:程序那些事,更多精彩等着您!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

※教你寫出一流的銷售文案?

※超省錢租車方案

Node.js躬行記(4)——自建前端監控系統

  這套前端監控系統用到的技術棧是:React+MongoDB+Node.js+Koa2。將性能和錯誤量化。因為自己平時喜歡吃菠蘿,所以就取名叫菠蘿系統。其實在很早以前就有這個想法,當時已經實現了前端的參數搜集,只是後台遲遲沒有動手,也就拖着。

  • 目前完成的還只是個雛形,僅僅是搜集了錯誤和相關的性能參數。

  • 後台樣式採用了封裝過的matrix。

  • 分析功能還很薄弱,只是做了簡單的演示,並且各種基礎功能還有待完善。

  • 後面打算強化數據分析,並且還要實現錯誤的回放機制,思路的話以前也調研過,參考之前的一篇文章

  現在的這個系統還只能算是個玩具,後期還需要雕琢雕琢。下面是這套系統的目錄結構。

├── pingapple --------------------------------- 菠蘿監控系統
│   ├── client -------------------------------- 系統的前端部分
│   ├── sdk ----------------------------------- 信息搜集代碼庫
│   ├── server -------------------------------- 系統的後端部分

一、SDK

1)primus.js

  在之前的《前端頁面性能參數搜集》一文中,詳細記載了各類性能指標的計算規則,並整理到了primus.js中。

  本次將在primus.js的基礎上做適當的修改,包括刪除代理、測速、資源信息等功能,改變部分性能指標的計算規則,例如從瀏覽器發起HTTP請求算起,忽略瀏覽器重定向的時間等。

2)錯誤處理

  完善錯誤處理,將錯誤分成三類:runtime、load和Promise。在window的error事件中,處理前兩種錯誤。像img元素載入的圖片地址不存在,就會執行formatLoadError()函數;像變量未定義,就會執行formatRuntimerError()函數。

window.addEventListener("error", function (event) {
    var errorTarget = event.target;
    // 過濾 target 為 window 的異常
    if (
      errorTarget !== window &&
      errorTarget.nodeName &&
      LOAD_ERROR_TYPE[errorTarget.nodeName.toUpperCase()]
    ) {
      handleError(formatLoadError(errorTarget));
    } else {
      handleError(
        formatRuntimerError(
          event.message,
          event.filename,
          event.lineno,
          event.colno,
          event.error
        )
      );
    }
  }, true
);

  將window綁定unhandledrejection事件后,就會在Promise被拒絕且沒有reject的回調函數時觸發。

window.addEventListener(
  "unhandledrejection",
  function (event) {
    // console.log('Unhandled Rejection at:', event.promise, 'reason:', event.reason);
    handleError({
      type: ERROR_PROMISE,
      desc: event.reason,
      stack: "no stack"
    });
  },
  true
);

3)初始化

  由於要計算白屏時間,DOM時間等,所以位置不能隨便放,得要放在head的最後面。

<head>
  <script>
    window.pineapple || (pineapple = {});
    pineapple.param = {
      "token": "dsadasd2323dsad23dsada"
    };
  </script>
  <script src="js/pineapple.js"></script>
</head>

二、服務端

1)Koa

  Koa是由Express原班人馬打造的Web輕量框架,通過組合各種中間件來避免繁瑣的回調函數嵌套,當前使用的版本是V2。

npm install --save koa

  使用的Koa腳手架:koa-generator,創建項目的結構,並且在此基礎上做了調整(目錄如下所示)。暫時還不會用到靜態資源和視圖層。

npm install -g koa-generator
├── server --------------------------------- 服務端
│   ├── bin -------------------------------- 命令
│   ├── config ----------------------------- 配置目錄
│   ├── controllers ------------------------ MVC中的邏輯層
│   ├── db --------------------------------- MVC中的數據層
│   ├── public ----------------------------- 靜態資源
│   ├── routes ----------------------------- 路由
│   ├── utils ------------------------------ 工具庫
│   ├── views ------------------------------ MVC中的視圖層
│   ├── app.js ----------------------------- 入口文件

  為了區分開發環境和生產環境,通過cross-env統一不同系統設置環境變量的方式。

npm install --save cross-env

  package.json中的命令如下,添加了環境配置。

"scripts": {
  "start": "node bin/www",
  "dev": "cross-env NODE_ENV=development ./node_modules/.bin/nodemon bin/www",
  "prd": "cross-env NODE_ENV=production pm2 start bin/www"
}

  prd按字面意思應該是生產環境的命令,其中使用了pm2,默認沒有安裝。還沒部署過Node.js,還不清楚裏面有多少坑。

npm install --save pm2

2)MongoDB

  MongoDB是一個開源的非關係型數據庫(圖1是下載界面),既沒有表、行等概念,也沒有固定的模式和結構,所有的數據以文檔(一個對象)的形式存儲。但其使用方式和關係型數據庫相似,並且還支持對數據建立索引,適用於高併發讀寫、海量數據存儲和實時分析等。

圖1

  注意,在安裝時默認會下載MongoDB Compress(一個可視化的MongoDB工具),默認下載會非常慢,建議自行下載,該工具的界面還是蠻清爽的,如圖2所示。

圖2

  在Mac上配置MongoDB比較麻煩,不像Windows那樣一件安裝,需要一些步驟,廢了點力氣才裝好,下面是執行的命令。

sudo mongod --dbpath=/Users/pw/data

3)Mongoose

  Mongoose是MongoDB的一個ORM(Object-Document Mapper,對象文檔映射)工具,可在Node.js環境中執行,封裝了MongoDB操作文檔的常用方法,包括引入數據庫連接(connect),定義模型(model),聲明文檔結構(scheme),實例化模型等操作數據庫的方法。

npm install --save mongoose

  借鑒了以前PHP數據分層的思想,單獨分離出數據庫的連接,並抽象通用的Model層(如下所示)。

const mongoose = require("./db");
class Mongodb {
  constructor(name, schema) {
    //聲明結構
    const mySchema = new mongoose.Schema(schema, { typeKey: "$type" });
    this.model = mongoose.model(name, mySchema);
  }
  //保存
  save(obj) {
    obj.created = Date.now();         //日期
    const doc = new this.model(obj);
    return new Promise((resolve, reject) => {
      doc.save((err, row) => {
        if (err) {
          reject(err);
          return;
        }
        resolve(row);
      });
    });
  }
}
module.exports = {
  model: Mongodb,
  mongoose
};

4)路由

  由於發送的地址是一張gif圖片,因此在處理路由時,返回本地的一張gif圖,如下所示,圖像地址得是絕對路徑,否則無法讀取。

router.get('/pa.gif', async (ctx, next) => {
  const ctr = new indexController();
  ctr.collect(ctx);
  const url = path.resolve(__dirname, "../public/images/blank.gif");
  ctx.body = fs.readFileSync(url);    //空白gif圖
});

5)代理分析

  在接收參數的時候分析代理所帶的信息,例如瀏覽器、操作系統、設備等。使用的是一個第三方庫:UAParser.js,四年前就關注過,當時GitHub上只有1K多個關注量,現在已經翻了4倍。

npm install --save ua-parser-js

6)假數據

  製作一套合適的假數據,新增命令“npm run data”,初始化數據,便於展示。

三、後台

1)UI

  後台模板採用了之前封裝過的Matrix,但不會依賴Bootstrap框架。

  將整個頁面分成五塊,分別是導航、側邊欄、麵包屑、底部欄以及主體。

  安裝react-router的history,用於路由。

npm install --save history

  期間也會安裝各類依賴包,例如不支持在類中直接聲明屬性等。

  在使用的過程中,ESLint會不時的彈出各種錯誤和警告,期間就不停的修改問題或查找相關配置忽略部分限制。

  後台的側邊欄和麵包屑等部分,會隨着URL的不同而發生狀態變化,本來想用多頁實現,但配置要改很多,就依然做成一個SPA,只是稍微做了些改動。

  組件庫採用了流行的Ant Design,調用了按鈕、單選框、日期等組件。

npm install --save antd

  圖表庫使用的是ECharts,目前只用到了折線圖和餅圖。在引用圖表時,為了優化構建,採取了按需引用的手段。

npm install --save echarts

2)項目管理

  首先建立一個項目,然後才能分析該項目的性能和錯誤,如圖3所示。

圖3

  用彈框的形式來創建項目,使用了Ant Design的Model、Form等組件,如圖4所示。

圖4

3)性能分析

  在第一個折線圖標籤中的過濾條件包括項目、字段、日期等,性能指標按平均值呈現,可看到每個性能指標的趨勢,如圖5所示。

圖5

  按分時日統計性能平均數,在MongoDB中計算。原先創建日期是以時間戳的形式存儲的,為了便於使用Aggregate,改成字符串形式。碰到一個坑,MongoDB中的Date類型採用的是格林尼治時間,而不是當前時區的時間,也就是說存在數據庫中的時間會比當前時間早8小時。

  在第二個列表標籤中,可以詳細看到每條記錄的信息,包括代理、網絡等,便於在了解趨勢的前提下,獲悉更為細節的內容,如圖6所示。

圖6

  點擊ajax那一列,可彈出具體的異步請求信息,如圖7所示。

圖7

4)錯誤分析

  有三個標籤,第一個也是折線圖,描繪的是某個時間的錯誤個數;第二個是錯誤列表,會給出具體的錯誤信息,如圖8所示。

圖8

  第三個是餅圖,餅圖主要體現的是發生錯誤的瀏覽器分佈情況(如圖9所示),點擊某一塊可查看瀏覽器的具體版本(如圖10所示)。

圖9

圖10

 

 

【參考資料】
PerformanceTiming

unhandledrejection 處理沒有顯式捕獲的 Promise 異常

狼書(卷2)

Node-區分環境

Koa從零搭建到Api實現—項目部署

koa如何連接MongoDB

Koa2進階學習筆記

如何計算首屏加載時間 

Mongoose Schema Error: “Cast to string failed for value” when pushing object to empty array

Support for the experimental syntax ‘classProperties’ isn’t currently enabled

Template string failing with Cannot read property ‘range’ of null

Disallow JSX props spreading (react/jsx-props-no-spreading)

TypeError: Cannot read property ‘range’ of null from template-curly-spacing

echarts項目的優化

使用 happypack 提升 Webpack 項目構建速度

mac下的mongoDB的安裝和啟動

安裝MongoDB報錯 mkdir: /data/db: Read-only file system

$sum mongoose

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

python工業互聯網應用實戰2—從需求開始

前言:隨着國家工業2025戰略的推進,工業互聯網發展將會提速,將迎來一個新的發展時期,越來越多的企業開始逐步的把產線自動化,去年年底投產的小米亦庄的智能工廠就是一個熱議的新聞。小米/華為智能工廠只能說是中國製造2025的一個代表,產業轉型和製造升級,筆者從事的企業領域就越到越來越多的(製造)企業開始悄悄的自動化/智能化。這裏肯定有國家政策推動的大背景,同時,也有着企業自身不斷提高生產率的“剛需”。

  本序列我們也從一個需求問題開始;然後,拆解需求(問題);其次,解決拆解需求(問題)的點;再次,通過的不斷技術摸索和迭代過程找到一個個合理的解決需求的方法和手段,最終,完成了這個需求(問題)的項目實戰。我們會在文中描述演化過程、方法論、過程保證機制和實用的工具等,最終帶着大家完成這樣一個實際項目需求的項目過程項目涉及的Django的多基礎知識請大家閱讀筆者早期的《Python開發入門與實戰系列》。

  本文的過程採用python3.6和django2.1版本

項目需求:這是一個簡版物流自動化倉庫實例,倉庫控制系統(以下簡稱WCS)需要調度AGV小車運送一個實托盤(搬運單元)從1樓入庫站台經由提升機搬運到2樓指定的倉庫貨位。 

1.需求分析

  倉庫控制系統(以下簡稱WCS)需要調度AGV小車運送一個實托盤(搬運單元)從1樓入庫站台經由提升機搬運到2樓指定的倉庫貨位。這句簡要描述常常是我們在項目URS看到的需求描述,接下來我們需要對拿到的需求進行分析,形成一個個可度量的開發功能點。

1.1.用例說明

  需求用例說明文檔能夠很好的對需求進行詳細的分析,主要的包含內容包括:前置條件、事件流程和後置條件(執行結果)用例描述如下錶,通過用例分析我們能夠很好的把握需求的具體事件執行流程,並通過文檔清晰的描述出來,便於後期設計編碼時作為開發設計人員的指導。

  經過團隊頭腦風暴討論,大家基本上達成了如下錶的需求用例說明,我們把這個調度設備的搬運過程設計成一個序列順序執行的步驟(子任務),這些子任務對應着設備的執行分解動作。

用例編碼

1.1

執行角色

WCS

用例名稱

托盤入庫用例

前提條件

  1. WMS已完成任務貨位的分配,任務核心信息:托盤條碼、源地址、目標地址;
  2. AGV不能跨樓層作業,1樓與2樓分別是不同的AGV小車執行任務;

需求描述

1 WCS分解搬運任務成3個設備作業

2 調度AGV入庫站台搬運托盤到提升機1樓門口工位;

3 調度提升機到1樓並打開廊門

4 調度AGV提升機1樓門口工位到提升機並卸貨,返回提升機門口工位;

5 調度提升機1樓提升到2樓並開門;

6 調度AGV進入提升機並載貨搬運到2樓門口工位;

7 調度提升機關門;

8 調度AGV從2樓門口工位搬運到庫存貨位。

備選過程

 

擴展過程

 

 

原始需求描述

參見 《XXX URS》

特殊需求

後置條件

WCS調度相關設備完成實托盤從入庫站台搬運到庫存貨位,反饋結果給WMS 

2. 需求功能點

  從上面的用例說明的需求描述事件流程來看,我們需要先把這一趟搬運任務分解成設備子任務,並串行的方式順序下達到設備執行,任務清單如下錶:

序號

作業描述

執行設備

1

調度AGV入庫站台搬運托盤到提升機1樓門口工位

1AGV

2

調度提升機到1樓並打開門

提升機

3

調度AGV提升機1樓門口工位到提升機並卸貨,返回提升機門口工位

1AGV

4

調度提升機1樓提升到2樓並開門

提升機

5

調度AGV進入提升機並載貨搬運到2樓門口工位

2AGV

6

調度提升機關門

提升機

7

調度AGV從2樓門口工位搬運到庫存貨位

2AGV

  也就是說這一趟搬運任務,WCS需要分解成7個設備作業子任務,並順序下達給相應的執行設備執行,最終完成任務的執行(當前的任務劃分粒度實際對接AGV和提升機廠家來說會有調整,最終以上步驟會依賴與實際對接的情況,但是主流程不會有太大變化)。 

   經過分析從1樓入庫站台運送托盤到二樓某個指定貨位這樣一個任務,系統需要分解成7個子任務,下達給設備順序執行。系統活動圖如下:

3. 活動圖

  經過分析從1樓入庫站台運送托盤到2樓某個指定貨位這樣一個任務,系統需要分解成7個子任務,下達給設備順序執行。我們還可以通過UML活動圖來進一步詳細的描述作業的執行順序如下圖: 

    從圖中我們可以看出來一次入庫任務,系統分解為7個設備子任務(作業)來執行完整的托盤入庫流程,只有所有子任務(作業)執行完成,托盤的入庫才算完成。

 4. 功能模塊

  對於這樣一個看似簡單的需求來說,包含兩大主要功能模塊

    1. 任務分解:依據物理設備處理任務的條件,對任務進行分解,任務分解的粒度是設備能夠識別並執行(動作)
    2. 任務調度:任務調度就是按照順序執行的邏輯,把任務順序和逐一下達給設備 

  這裏也有幾個基本邏輯就是,設備在某一個時間點上只能執行一個子任務,只有這個任務執行完畢後方能下達新的子任務。多重任務邏輯只會導致設備無法完成任務(不知道到底該執行那個動作)。

 4.1. 實體關係

  我們從上面需求分析整理當前至少包括2個實體,包含的屬性(字段)如下: 

1任務

任務ID,任務號,源地址(從哪兒),目標地址(到哪兒),開始時間,結束時間,狀態 

2子任務:

子任務ID,任務ID,源地址(從哪兒 上一個子任務的目標地址), 目標地址(到哪兒 下一個子任務的源地址), 執行機構,開始時間,結束時間,狀態

5. 小節

  本章我們從一個需求問題開始,然後經過需求分析,把需求問題分解為功能點和數據實體,實體是下一步我們設計表或ORM model的基礎原型,上面的實體只是一個初步的需求分析主要字段要求,實體屬性(字段)會設計時會增加特定的其它屬性(字段)。 下一章節我們將描繪如何把這個需求逐步演化到模型設計。

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

※教你寫出一流的銷售文案?