移動UI系列 – 簡單地使用半衰期算法來預測手勢的滑動方向與速度

前言

有一個問題, 給定一個物體的運動軌跡, 包含時間和坐標的數組, 如何使用這個數據來預測物體未來的運動走勢??

本文提供了一個很簡單的方式去實現這個算法. 效果夠用, 又簡單, 有一定的準確程度. 

 

緣由

以前做過的一些手機應用, 沒有做動畫的, 也沒做手勢. 這個做起來挺麻煩的. 

最近開始了新的手機項目(微信項目模板) , 基於 Blazor server side , 其組件化的方式可以很方便地把各種常用的通用的東西封裝成 組件/控件 

於是, 就打算讓這段時間辛苦一些, 一次過把動畫的部分補上, 讓以後的項目更加牛逼, 意思是讓客戶更加樂意地掏錢. 

 

問題

手勢的一個問題是力度/速度判斷, 劃得快, 劃得慢, 先快後慢, 先慢後快, 都得有一個合適的算法來得到一個最後速度. 

這個算法一定要滿足基本的需求後, 要盡量簡單, 要目測, 理論上沒有bug . 

這個時候, 半衰期算法就派上用場了. (不知道有沒有半衰期算法這玩意, 應該說是使用半衰期的原理)

 

原理

這是一個很簡單的權重計算, 有很多個不同時間點的坐標, 每個相鄰時間的兩個數據, 有距離差, 有時間差

關鍵是解決先慢後快, 先快後慢的數據的處理問題, 那麼我們只需要

把新的數據, 乘以更大的權重, 把老的數據, 乘以更小的權重, 最後得到這個距離權重的合成值, 就OK了. 

 

預覽效果:

注意, 因為gif的幀數不夠, 要更好效果還是複製代碼運行一遍. 

 

 

測試代碼:

<! DOCTYPE html > 
< html > 
< head > 
    < meta charset ="utf-8"  /> 
    < title > Half Life </ title > 
    < style > 
        html, body, canvas { width : 100% ; height : 100% ; margin : 0 ; padding : 0 ; box-sizing : border-box ; overflow : hidden ; }
    </ style > 
</ head > 
< body >

    < canvas ></ canvas >

    < script type ="text/javascript" >

        var CONST_HALF_LIFE_SPAN =  50 ;     //半衰期,設置得越小,就越看淡以前的速度
        var CONST_MAX_SAMPLES =  15 ;         //保留最後15個點的數據減少無意義的運算量,主要看瀏覽器觸發onmousemove的頻率來調整.

        var pts = [];
        document.onmousemove =  function (e) {

            //儲存數據
            pts.push({ time: Date.now(), x: e.clientX, y: e.clientY });
             if (pts.length > CONST_MAX_SAMPLES) pts.shift();

            //計算

            var xs =  0 , ys =  0 ;     //走過的路的長度. 
            var previtem = pts[ 0 ];
             for ( var index =  1 ; index < pts.length; index ++ ) {
                 var newitem = pts[index ];
                 var t = newitem.time - previtem.time;

                //讓這個數據衰減一次,衰減程度由時間差決定. 
                var halflifefactor = Math.pow( 0.5 , t / CONST_HALF_LIFE_SPAN);

                //注意,這裏沒有計算速度,而是直接用距離來預測將來要走過的距離.

                //走過的距離每一次都要衰減,每一段的路程都多次乘以各時間差的factor, 
                //原理是, 0.5 ^ (t1 + t2 + t3...)等於0.5 ^ t1 * 0.5 ^ t2 * 0.5 ^ t3 * ... 
                xs = xs * halflifefactor + newitem.x - previtem.x;
                ys = ys * halflifefactor + newitem.y - previtem.y;

                previtem = newitem;
            }

            //畫圖

            var CONST_EFFECT_FACTOR =  2 ;     //乘以一個因素來畫圖用,這裏數值可以充當'摩擦係數'大小的效果. 
            xs = Math.floor(xs * CONST_EFFECT_FACTOR);
            ys = Math.floor(ys * CONST_EFFECT_FACTOR);

            var x0 = e.clientX, y0 = e.clientY;

            var canvas = document.querySelector( " canvas " );
             var ctx = canvas.getContext( " 2d " );
             var w = canvas.width = canvas.offsetWidth;
             var h = canvas.height = canvas.offsetHeight;
            ctx.clearRect( 0 , 0 , w, h);
            ctx.lineWidth =  5 ;
            ctx.strokeStyle =  " blue " ;
            ctx.beginPath();
            ctx.moveTo(x0, y0);
            ctx.lineTo(x0 + xs, y0 + ys);
            ctx.closePath();
            ctx.stroke();

            console.log(xs, ys)
        }
    </ script >

</ body >

</ html >

 

簡單講解

可以看出, 代碼量非常少. 與其說這是一種”算法” , 不然說是一種”思路” 

 

代碼先是記錄每一點的數據, 然後放進 pts 數組 

在鼠標移動後, 使用pts 數組, 計算出每一點的x , y 的移動量, 讓每一段的移動量都使用 半衰期 的方式進行調整. 

最後得出的xs , ys ,是理論上“最近移動的距離.”

使用這個數值,作為“參考值” ,就可以用於更多的判斷. 

 

例如我最近做的一個簡單的 swipe 組件, 

手指滑動了1/4個屏幕,然後再加上理論的參考值,  一共超過了1/2個屏幕,就切換到下一個panel 

這個參考值很重要. 如果手指只是很慢地滑動, 那麼參考值就很小, 就不應該切換. 如果手指很快地滑動, 那麼就應該切換panel

 

可改良的方案

上面方案, 是計算’移動距離’ 的, 它有一個弊端, 無論劃得多快, 移動的總數是有上限的. 

這段代碼完全可以 除以t , 得到一個 速度值,

這更加合理, 但是注意速度的合成方式不能普通地累加. 

 

這就留給有興趣的網友自己嘗試了. 也不難. 畢竟本文傳播的是 半衰期 的思路. 不宜說太細. 

 

 

擴展思路

其實這種算法, 一直都有人用. 很奇怪的就是, 沒有看到什麼人專門寫文章介紹? 

半衰期除了計算運動軌跡, 還可以很好地去統計熱度. 

例如一篇文章, 一個視頻, 有不同時段的點擊數量. 每一天都不一樣. 

 

怎樣使用最少的儲存方式, 去儲存一個合理的熱度參考值? 

可行的方法是,儲存兩個數值 (就夠了) : 

articleRateValue 用於儲存熱度值

articleRateTime 用於儲存熱度時間

 

每一次點擊, 都使用這個公式儲存: 

articleRateValue = newclickcount + articleRateValue * POW(0.5, (NOW – articleRateTime) / HALF_LIFE_SPAN )

articleRateTime = NOW 

排序的時候麻煩點, 要實時的計算 articleRateValue * POW(0.5, (NOW – articleRateTime) / HALF_LIFE_SPAN ) 來得到每個文章的熱度值. 

(對於排序的問題, 還有兩個變通的做法, 如果以後有時間寫一篇文章細說這個熱度方案, 再詳細解說)

(最簡單的變通方法是, 每晚找服務器空閑的時候, 把表裡的數值都重新計算一次, 平時排序的時候不計算) 

 

注意這裡有一個 HALF_LIFE_SPAN 的概念. 如果 HALF_LIFE_SPAN 是一天, 那麼昨天的熱度就佔1/2 權重, 前天的就佔 1/4 權重, 大前天的佔1/8 

這樣按天算也有個弊端, 我想按週, 按月算那怎麼辦? 

再存兩組數值 :

weeklyRateValue

weeklyRateTime

monthlyRateValue

monthlyRateTime 

如此類推. 

 

這樣做的最大好處是, 無需詳細地紀錄每一次的點擊數據. 非常節省空間.  

缺點是, 每一組數據, 只適合一個半衰期時段的數值, 要儲存多個參考值得準備多組數據. 

 

最後

時間過得真快. 這段時間挖的坑太多, 在業餘時間內根本沒有時間填坑..

5月初的時候實現了BlazorCefApp , 到現在開了幾個有意義的坑, Blazor微信項目模板 算是一個. 

但是由於沒有時間寫博客, 有時只是偶爾把測試的視頻放到B站: https://space.bilibili.com/540073960 

有興趣用Blazor 來做微信項目或手機網頁項目的, 可以去了解一下. 當項目成熟後, 會發佈到github上. 

—-

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

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

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

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

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

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

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

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

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

解Bug之路-記一次JVM堆外內存泄露Bug的查找

解Bug之路-記一次JVM堆外內存泄露Bug的查找

前言

JVM的堆外內存泄露的定位一直是個比較棘手的問題。此次的Bug查找從堆內內存的泄露反推出堆外內存,同時對物理內存的使用做了定量的分析,從而實錘了Bug的源頭。筆者將此Bug分析的過程寫成博客,以饗讀者。
由於物理內存定量分析部分用到了linux kernel虛擬內存管理的知識,讀者如果有興趣了解請看ulk3(《深入理解linux內核第三版》)

內存泄露Bug現場

一個線上穩定運行了三年的系統,從物理機遷移到docker環境后,運行了一段時間,突然被監控系統發出了某些實例不可用的報警。所幸有負載均衡,可以自動下掉節點,如下圖所示:

登錄到對應機器上后,發現由於內存佔用太大,觸發OOM,然後被linux系統本身給kill了。

應急措施

緊急在出問題的實例上再次啟動應用,啟動后,內存佔用正常,一切Okay。

奇怪現象

當前設置的最大堆內存是1792M,如下所示:

-Xmx1792m -Xms1792m -Xmn900m -XX:PermSi
ze=256m -XX:MaxPermSize=256m -server -Xss512k 

查看操作系統層面的監控,發現內存佔用情況如下圖所示:

上圖藍色的線表示總的內存使用量,發現一直漲到了4G后,超出了系統限制。
很明顯,有堆外內存泄露了。

查找線索

gc日誌

一般出現內存泄露,筆者立馬想到的就是查看當時的gc日誌。
本身應用所採用框架會定時打印出對應的gc日誌,遂查看,發現gc日誌一切正常。對應日誌如下:

查看了當天的所有gc日誌,發現內存始終會回落到170M左右,並無明顯的增加。要知道JVM進程本身佔用的內存可是接近4G(加上其它進程,例如日誌進程就已經到4G了),進一步確認是堆外內存導致。

排查代碼

打開線上服務對應對應代碼,查了一圈,發現沒有任何地方顯式利用堆外內存,其沒有依賴任何額外的native方法。關於網絡IO的代碼也是託管給Tomcat,很明顯,作為一個全世界廣泛流行的Web服務器,Tomcat不大可能有堆外內存泄露。

進一步查找

由於在代碼層面沒有發現堆外內存的痕迹,那就繼續找些其它的信息,希望能發現蛛絲馬跡。

Dump出JVM的Heap堆

由於線上出問題的Server已經被kill,還好有其它幾台,登上去發現它們也 佔用了很大的堆外內存,只是還沒有到觸發OOM的臨界點而已。於是就趕緊用jmap dump了兩台機器中應用JVM的堆情況,這兩台留做現場保留不動,然後將其它機器迅速重啟,以防同時被OOM導致服務不可用。
使用如下命令dump:

jmap -dump:format=b,file=heap.bin [pid]

使用MAT分析Heap文件

挑了一個heap文件進行分析,堆的使用情況如下圖所示:

一共用了200多M,和之前gc文件打印出來的170M相差不大,遠遠沒有到4G的程度。
不得不說MAT是個非常好用的工具,它可以提示你可能內存泄露的點:

這個cachedBnsClient類有12452個實例,佔用了整個堆的61.92%。
查看了另一個heap文件,發現也是同樣的情況。這個地方肯定有內存泄露,但是也佔用了130多M,和4G相差甚遠。

查看對應的代碼

系統中大部分對於CachedBnsClient的調用,都是通過註解Autowired的,這部分實例數很少。
唯一頻繁產生此類實例的代碼如下所示:

@Override
    public void fun() {
            BnsClient bnsClient = new CachedBnsClient();
          // do something
    		return  ;
	}

此CachedBnsClient僅僅在方法體內使用,並沒有逃逸到外面,再看此類本身

public class CachedBnsClient   {
    private ConcurrentHashMap<String, List<String>> authCache = new ConcurrentHashMap<String, List<String>>();
    private ConcurrentHashMap<String, List<URI>> validUriCache = new ConcurrentHashMap<String, List<URI>>();
    private ConcurrentHashMap<String, List<URI>> uriCache = new ConcurrentHashMap<String, List<URI>>();
	......
}

沒有任何static變量,同時也沒有往任何全局變量註冊自身。換言之,在類的成員(Member)中,是不可能出現內存泄露的。
當時只粗略的過了一過成員變量,回過頭來細想,還是漏了不少地方的。

更多信息

由於代碼排查下來,感覺這塊不應該出現內存泄露(但是事實確是如此的打臉)。這個類也沒有顯式用到堆外內存,而且只佔了130M,和4G比起來微不足道,還是先去追查主要矛盾再說。

使用jstack dump線程信息

現場信息越多,越能找出蛛絲馬跡。先用jstack把線程信息dump下來看下。
這一看,立馬發現了不同,除了正常的IO線程以及框架本身的一些守護線程外,竟然還多出來了12563多個線程。

"Thread-5" daemon prio=10 tid=0x00007fb79426e000 nid=0x7346 waiting on condition [0x00007fb7b5678000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at com.xxxxx.CachedBnsClient$1.run(CachedBnsClient.java:62)

而且這些正好是運行再CachedBnsClient的run方法上面!這些特定線程的數量正好是12452個,和cachedBnsClient數量一致!

再次check對應代碼

原來剛才看CachedBnsClient代碼的時候遺漏掉了一個關鍵的點!

    public CachedBnsClient(BnsClient client) {
        super();
        this.backendClient = client;
        new Thread() {
            @Override
            public void run() {
                for (; ; ) {
                    refreshCache();
                    try {
                        Thread.sleep(60 * 1000);
                    } catch (InterruptedException e) {
                        logger.error("出錯", e);
                    }
                }
            }
            ......
        }.start();
    }

這段代碼是CachedBnsClient的構造函數,其在裏面創建了一個無限循環的線程,每隔60s啟動一次刷新一下裏面的緩存!

找到關鍵點

在看到12452個等待在CachedBnsClient.run的業務的一瞬間筆者就意識到,肯定是這邊的線程導致對外內存泄露了。下面就是根據線程大小計算其泄露內存量是不是確實能夠引起OOM了。

發現內存計算對不上

由於我們這邊設置的Xss是512K,即一個線程棧大小是512K,而由於線程共享其它MM單元(線程本地內存是是現在線程棧上的),所以實際線程堆外內存佔用數量也是512K。進行如下計算:

12563 * 512K = 6331M = 6.3G

整個環境一共4G,加上JVM堆內存1.8G(1792M),已經明顯的超過了4G。

(6.3G + 1.8G)=8.1G > 4G

如果按照此計算,應用應用早就被OOM了。

怎麼回事呢?

為了解決這個問題,筆者又思考了好久。如下所示:

Java線程底層實現

JVM的線程在linux上底層是調用NPTL(Native Posix Thread Library)來創建的,一個JVM線程就對應linux的lwp(輕量級進程,也是進程,只不過共享了mm_struct,用來實現線程),一個thread.start就相當於do_fork了一把。
其中,我們在JVM啟動時候設置了-Xss=512K(即線程棧大小),這512K中然後有8K是必須使用的,這8K是由進程的內核棧和thread_info公用的,放在兩塊連續的物理頁框上。如下圖所示:

眾所周知,一個進程(包括lwp)包括內核棧和用戶棧,內核棧+thread_info用了8K,那麼用戶態的棧可用內存就是:

512K-8K=504K

如下圖所示:

Linux實際物理內存映射

事實上linux對物理內存的使用非常的摳門,一開始只是分配了虛擬內存的線性區,並沒有分配實際的物理內存,只有推到最後使用的時候才分配具體的物理內存,即所謂的請求調頁。如下圖所示:

查看smaps進程內存使用信息

使用如下命令,查看

cat /proc/[pid]/smaps > smaps.txt

實際物理內存使用信息,如下所示:

7fa69a6d1000-7fa69a74f000 rwxp 00000000 00:00 0 
Size:                504 kB
Rss:                  92 kB
Pss:                  92 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:        92 kB
Referenced:           92 kB
Anonymous:            92 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

7fa69a7d3000-7fa69a851000 rwxp 00000000 00:00 0 
Size:                504 kB
Rss:                 152 kB
Pss:                 152 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:       152 kB
Referenced:          152 kB
Anonymous:           152 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB

搜索下504KB,正好是12563個,對了12563個線程,其中Rss表示實際物理內存(含共享庫)92KB,Pss表示實際物理內存(按比例共享庫)92KB(由於沒有共享庫,所以Rss==Pss),以第一個7fa69a6d1000-7fa69a74f000線性區來看,其映射了92KB的空間,第二個映射了152KB的空間。如下圖所示:

挑出符合條件(即size是504K)的幾十組看了下,基本都在92K-152K之間,再加上內核棧8K

(92+152)/2+8K=130K,由於是估算,取整為128K,即反映此應用平均線程棧大小。

注意,實際內存有波動的原因是由於環境不同,從而走了不同的分支,導致棧上的增長不同。

重新進行內存計算

JVM一開始申請了

-Xmx1792m -Xms1792m

即1.8G的堆內內存,這裡是即時分配,一開始就用物理頁框填充。
12563個線程,每個線程棧平均大小128K,即:

128K * 12563=1570M=1.5G的對外內存

取個整數128K,就能反映出平均水平。再拿這個128K * 12563 =1570M = 1.5G,加上JVM的1.8G,就已經達到了3.3G,再加上kernel和日誌傳輸進程等使用的內存數量,確實已經接近了4G,這樣內存就對應上了!(注:用於定量內存計算的環境是一台內存用量將近4G,但還沒OOM的機器)

為什麼在物理機上沒有應用Down機

筆者登錄了原來物理機,應用還在跑,發現其同樣有堆外內存泄露的現象,其物理內存使用已經達到了5個多G!幸好物理機內存很大,而且此應用發布還比較頻繁,所以沒有被OOM。
Dump了物理機上應用的線程,

一共有28737個線程,其中28626個線程等待在CachedBnsClient上。 

同樣用smaps查看進程實際內存信息,其平均大小依舊為

128K,因為是同一應用的原因

繼續進行物理內存計算

1.8+(28737 * 128k)/1024K =(3.6+1.8)=5.4G

進一步驗證了我們的推理。

這麼多線程應用為什麼沒有卡頓

因為基本所有的線程都睡眠在

 Thread.sleep(60 * 1000);//一次睡眠60s

上。所以僅僅佔用了內存,實際佔用的CPU時間很少。

總結

查找Bug的時候,現場信息越多越好,同時定位Bug必須要有實質性的證據。例如內存泄露就要用你推測出的模型進行定量分析。在定量和實際對不上的時候,深挖下去,你會發現不一樣的風景!

公眾號

關注筆者公眾號,獲取更多乾貨文章:

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

※回頭車貨運收費標準

Kubernetes日誌的6個最佳實踐

本文轉自Rancher Labs

Kubernetes可以幫助管理部署在Pod中的上百個容器的生命周期。它是高度分佈式的並且各個部分是動態的。一個已經實現的Kubernetes環境通常涉及帶有集群和節點的幾個系統,這些系統託管着幾百個容器,而這些容器不斷地基於工作負載啟動、毀滅。

當在Kubernetes中處理大量的容器化應用和工作負載時,主動進行監控和調試錯誤十分重要。在容器、節點或集群級別,這些錯誤都能在容器中看到。Kubernetes的日誌機制是一個十分重要的組件,可以用來管理和監控服務以及基礎設施。在Kubernetes中,日誌可以讓你跟蹤錯誤甚至可以調整託管應用程序的容器的性能。

配置stdout(標準輸出)和stderr(標準錯誤)數據流

圖片來源:kubernetes.io

第一步是理解日誌是如何生成的。通過Kubernetes,日誌會被發送到兩個數據流——stdout和stderr。這些數據流將寫入JSON文件,並且此過程由Kubernetes內部處理。你可以配置將哪個日誌發送到哪個數據流中。而一個最佳實踐的建議是將所有應用程序日誌都發送到stdout並且所有錯誤日誌都發送到stderr。

決定是否使用Sidecar模型

Kubernetes建議使用sidecar容器來收集日誌。在這一方法中,每個應用程序容器將有一個鄰近的“streaming容器”,該容器將會將所有日誌流傳輸到stdout和stderr。Sidecar模型可以幫助避免在節點級別公開日誌,並且它可以讓你控制容器級別的日誌。

然而,這一模型的問題是它能夠適用於小容量的日誌記錄,如果面對大規模的日誌記錄,可能會造成大量資源被佔用。因此,你需要為每個正在運行的應用程序容器單獨運行一個日誌容器。在Kubernetes文檔中,將sidecar模型形容為“幾乎沒有很大的開銷”。需要由你決定是否嘗試這一模型並在選擇它之前查看它所消耗的資源類型。

替代方法是使用日誌代理,該代理在節點級別收集日誌。這樣可以減少開銷,並確保安全地處理日誌。Fluentd已成為大規模聚合Kubernetes日誌的最佳選擇。它充當Kubernetes與你要使用Kubernetes日誌的任意數量的端點之間的橋樑。你也可以選擇像Rancher這樣的Kubernetes管理平台,在應用商店已經集成了Fluentd,無需從頭開始安裝配置。

確定Fluentd可以更好地匯總和路由日誌數據后,下一步就是確定如何存儲和分析日誌數據。

選擇日誌分析工具:EFK或專用日誌記錄

傳統上,對於以本地服務器為中心的系統,應用程序日誌存儲在系統中的日誌文件中。這些文件可以在定義的位置看到,也可以移動到中央服務器。但是對於Kubernetes,所有日誌都發送到磁盤上/var/log的JSON文件中。這種類型的日誌聚合併不安全,因為節點中的Pod可以是臨時的也可以是短暫的。刪除Pod時,日誌文件將丟失。如果你需要嘗試對部分日誌數據丟失進行故障排除時,這可能很難。

Kubernetes官方推薦使用兩個選項:將所有日誌發送到Elasticsearch,或使用你選擇的第三方日誌記錄工具。同樣,這裏存在一個潛在的選擇。採用Elasticsearch路線意味着你需要購買一個完整的堆棧,即EFK堆棧,包括Elasticsearch、Fluentd和Kibana。每個工具都有其自己的作用。如上所述,Fluentd可以聚合和路由日誌。Elasticsearch是分析原始日誌數據並提供可讀輸出的強大平台。Kibana是一種開源數據可視化工具,可以從你的日誌數據創建漂亮的定製dashboard。這是一個完全開源的堆棧,是使用Kubernetes進行日誌記錄的強大解決方案。

儘管如此,有些事情仍然需要牢記。Elasticsearch除了由名為Elastic的組織構建和維護,還有龐大的開源社區開發人員為其做貢獻。儘管經過大量的實踐檢驗,它可以快速、強大地處理大規模數據查詢,但在大規模操作時可能會出現一些問題。如果採用的是自我管理(Self-managed)的Elasticsearch,那麼需要有人了解如何構建大規模平台。

替代方案是使用基於雲的日誌分析工具來存儲和分析Kubernetes日誌。諸如Sumo Logic和Splunk等工具都是很好的例子。其中一些工具利用Fluentd來將日誌路由到他們平台,而另一些可能有它們自己的自定義日誌代理,該代理位於Kubernetes中的節點級別。這些工具的設置十分簡單,並且使用這些工具可以花費最少的時間從零搭建一個可以查看日誌的dashboard。

使用RBAC控制對日誌的訪問

在Kubernetes中身份驗證機制使用的是基於角色訪問控制(RBAC)以驗證一個用戶的訪問和系統權限。根據用戶是否具有特權(authorization.k8s.io/decision )並向用戶授予原因(authorization.k8s.io/reason ),對在操作期間生成的審核日誌進行註釋。默認情況下,審核日誌未激活。建議激活它以跟蹤身份驗證問題,並可以使用kubectl進行設置。

保持日誌格式一致

Kubernetes日誌由Kubernetes架構中不同的部分生成。這些聚合的日誌應該格式一致,以便諸如Fluentd或FluentBit的日誌聚合工具更易於處理它們。例如,當配置stdout和stderr或使用Fluentd分配標籤和元數據時,需要牢記這一點。這種結構化日誌提供給Elasticsearch之後,可以減少日誌分析期間的延遲。

在日誌收集守護進程上設置資源限制

由於生成了大量日誌,因此很難在集群級別上管理日誌。DaemonSet在Kubernetes中的使用方式與Linux類似。它在後台運行以執行特定任務。Fluentd和filebeat是Kubernetes支持的用於日誌收集的兩個守護程序。我們必須為每個守護程序設置資源限制,以便根據可用的系統資源來優化日誌文件的收集。

結 論

Kubernetes包含多個層和組件,因此對其進行良好地監控和跟蹤能夠讓我們在面對故障時從容不迫。Kubernetes鼓勵使用無縫集成的外部“Kubernetes原生”工具進行日誌記錄,從而使管理員更輕鬆地獲取日誌。文章中提到的實踐對於擁有一個健壯的日誌記錄體繫結構很重要,該體繫結構在任何情況下都可以正常工作。它們以優化的方式消耗計算資源,並保持Kubernetes環境的安全性和高性能。

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

【其他文章推薦】

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

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

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

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

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

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

※回頭車貨運收費標準

自主SUV陣型中的又一爆款車型 有實力擠進前十

空間人性化更貼心雖然軸距只有2630mm,但是柔軟適中的座椅,方正的車身造型使其乘坐空間表現還是很出色的,前後排都能獲得充裕的頭部和腿部空間,多達22處的人性化儲物空間十分便利,開口較大的後備箱內部很規整,可以輕鬆放入大型物品,後排座椅4/6比例摺疊后更為平坦,擴展性夠強,滿足日常需求。

緊抓住時間的腳步,東風風神推出了旗下全新的緊湊型SUV-東風風神AX5,並於11月29日正式上市,其定位介於風神AX7和風神AX3之間,秉承着“流•動之美”的設計理念打造,擁有着超高的顏值,它的推出無疑將豐富東風風神旗下的產品線布局,一起來看一下這輛潛力股吧!

外觀

高顏值高原創

第一眼看見東風風神AX5,會讓人有眼前一亮的感覺,外觀造型非常忠於原創,幾乎找不到任何借鑒的影子,秉承着“流•動之美”的設計理念,車子總體以簡潔的線條為主,用豐富的曲線勾勒出飽滿的車體。

前臉造型富有層次感,配以絢麗的遠近光一體帶透鏡大燈,加上造型獨特的保險杠和大尺寸蜂窩狀進氣格柵,讓車頭看上去更加時尚大氣,立式造型獠牙狀日行燈有着較高的辨識度。

波浪式的前後分段雙腰線絕對是獨樹一幟的設計,讓側面更加年輕動感,車頂行李架、腳踏板、190mm的離地間隙配以18英寸雙色旋風輪轂,兼顧了美觀和實用性。

廠家為AX5車窗配備了晴雨擋,雖說成本不高,但是勝在實用性強,夠貼心,全系尾燈均採用LED光源,穿透力更好更厚道,後車窗下面小鴨尾的折角豐富了尾部的層次感,零星的鍍鉻裝飾、雙色保險桿的設計,簡單而不失大氣。

內飾/配置

科技享受生活

內飾整體造型是比較家族化的設計,環抱式的座艙風格比較簡潔、幹練,並沒有太多花哨的地方,用料和做工都很夠到,比較上檔次,懸浮式液晶显示屏是一大亮點。

搭載了WindLink車載智能互聯繫統也是一大利器,具備了車輛關懷、語音識別、手機App、智能導航等多項功能,功能性上可以媲美奔馳寶馬等豪華品牌系統,撥通控制中心后,說出你想去的地方,客服會自動將導航信息發送至車載導航。

鏈接手機App后,可實現手機控制車窗的開啟與關閉,車門開鎖、空調控制(夏天就一進到車內就可以享受涼爽的空調了)、道路救援、尋車以及車輛信息显示,就如隨身攜帶了專業的車輛檢測電腦,隨時了解愛車哪些地方出了問題和什麼時候該保養了。

空間

人性化更貼心

雖然軸距只有2630mm,但是柔軟適中的座椅,方正的車身造型使其乘坐空間表現還是很出色的,前後排都能獲得充裕的頭部和腿部空間,多達22處的人性化儲物空間十分便利,開口較大的後備箱內部很規整,可以輕鬆放入大型物品,後排座椅4/6比例摺疊后更為平坦,擴展性夠強,滿足日常需求。

動力

平順流暢更輕鬆

全系搭載東風風神自主研發的1.4T全鋁合金小排量增壓發動機,自重更輕更節能,與之匹配的是一款5速手動變速器,或者是德國的格特拉克生產的6速濕式雙離合變速器,保證低油耗的同時有着高效的動力輸出,駕駛過程中動力輸出夠線性,換擋平順,電動助力方向盤操控精準又省力,調教紮實的底盤很舒適。

競爭力分析

突圍而出

那東風風神AX5到底是不是一款誠意之作呢,我們來看一下全系標配的配置,打紅色框的配置如LED日間行車燈、多功能方向盤、手機智能互聯、定速巡航、智能啟停系統、ESp、上坡輔助等可是一般車型作為高中低配的差距配置,而AX5卻作為全系標配來打造的一款車,性價比很高,優勢就很明顯了,也很有誠意。

我們再拿銷量比較好的傳祺GS4作對比,看一下風神AX5的競爭力如何。

安全配置上傳祺GS4的頭部氣囊有所欠缺,倒車影像也沒有,只有個陡坡緩降配置。

多媒體配置和座椅配置上風神AX5是完爆傳祺GS4,非常的豐富。

最關鍵的高科技配置如發動機啟停、併線輔助、全景攝像頭風神AX5都有配備,簡直就是越級的配置,要知道20萬級別的SUV都未必有這些配置,競爭力很強。

全文總結:作為老資格的自主品牌,風神AX5全系搭載1.4T渦輪增壓發動機,也是適應時代的要求,加上6速DCT雙離合變速箱,組成雙T鉑金動力組合,動力強,油耗低,高顏值個性鮮明的外觀有着很高的原創度,相比於競爭對手有着足夠優秀的配置來與之抗衡,WindLink智能互聯繫統非常實用,科技化十足,舒適的乘坐空間能滿足家庭日常所需,綜合實力夠強。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

※超省錢租車方案

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

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※回頭車貨運收費標準

如果你也喜歡自主品牌,那麼這些事情你有必要了解!

可尼瑪事與願違啊。剛過去俗稱“金九銀十”銷售旺季的10月份,我國的乘用車銷量共計234。41萬輛,而光轎車就賣出了117。05萬輛。哪怕現在SUV市場再怎麼火,當月的轎車銷量依然要比SUV多出27。45萬輛。所以事實就是,轎車依然是中國汽車市場上最好賣的車型。

憑藉著SUV浪潮的興起,我國的自主品牌頓時間風生水起,長城、吉利、傳祺…迅速取代合資品牌,成為中國車市的第一驅動力。甚至連一些名不見經傳的品牌,譬如力帆、野馬等也都憑藉推出SUV過上了翻身農奴把歌唱的好日子。咋一看,革面全面勝利,形勢一片大好!然鵝,在一片繁榮的背後貌似隱藏着危機四伏的危險。

這個危機四伏的危險是什麼?

咱們的自主品牌相當缺乏能夠拿得出手的轎車產品呀!除了帝豪、帝豪GL、艾瑞澤5、逸動之外,大家還能叫得上幾款口碑、銷量都不錯的自主品牌轎車么?沒有了。如果要說不光口碑好、銷量好,而且還有歷史傳承的自主品牌轎車,那就只有累計銷量剛剛突破百萬輛的帝豪了。而合資品牌呢?朗逸、福睿斯、高爾夫、卡羅拉,個個的銷量、口碑都是彪悍級的。

SUV市場火熱,就拚命地研發SUV、銷售SUV固然是人之常情。畢竟吃飽了,才有力氣幹活,把現錢都掙了是正常思維。但咱們自主品牌偏偏是在這樣的思維下走到了極端。最典型的,莫過於剛剛憑藉哈弗H6單月7萬+銷量刷新中國單一車型月均銷量紀錄的長城。哈弗H6在SUV風頭無兩,但旗下的轎車車型C30,近半年來的月均的銷量卻只有千餘輛的水平。略有些營養不良的感覺。

這個危機到底有多危險?

有的人說:大家都買SUV了,誰還會買轎車?!我也是這樣想的啊!可尼瑪事與願違啊!剛過去俗稱“金九銀十”銷售旺季的10月份,我國的乘用車銷量共計234.41萬輛,而光轎車就賣出了117.05萬輛。哪怕現在SUV市場再怎麼火,當月的轎車銷量依然要比SUV多出27.45萬輛。所以事實就是,轎車依然是中國汽車市場上最好賣的車型。相信大夥都已經明白到轎車市場的重要性,但絕大多數的自主品牌卻竟然一致地選擇無視這個市場。這不叫集中力量干大事,這叫把所有雞蛋都放一個籃子里。就差合資品牌給你絆一跤,讓你的籃子里的雞蛋都摔破。

合資品牌在轎車領域有多強勢?

要說合資品牌跟自主品牌一樣,把全副身家押寶在SUV車型上那還不至於讓人膽戰心驚,但問題就在於合資品牌在轎車領域的牛逼程度簡直是垄斷式經營(不是人家想垄斷,是自主品牌把這市場拱手相讓)。同樣是“金九銀十”的10月份,轎車銷量的前十位企業分別為:一汽大眾、上汽大眾、上汽通用、東風日產、吉利控股、北京現代、長安福特、東風悅達起亞、廣汽本田和神龍汽車。十個茅坑,竟然有九個被合資品牌佔了。更可怕的是,自主品牌壓根連剩下的肉都吃不上。因為這十家車企的轎車銷量,已經佔到了整個轎車市場的72.53%。估計自主品牌也就能夠吃上兩口青菜吧,清淡點。

自主品牌你們要當個“德智體美勞全面健康發展”的好學生呀!

說實話,看着自主品牌由民間小作坊生產、向合資企業討落後的技術,到擁有媲美國際一線車企的現代化生產車間(去看看吉利台州的基地就一目瞭然了)以及發動機、汽車互聯等核心技術方面的創新性領先,我作為一个中國人是相當的自豪,我相信大家也是。但也正因為這一份對自主品牌的熱切期待,才更使得我們去發現自主品牌在轎車市場方面的不足,才憂心好不容易才建立起來的中國汽車工業因為轎車市場的乏力而付諸一旦。所以,請自主品牌們發展的步伐再穩一些、再穩一些。

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※推薦台中搬家公司優質服務,可到府估價

國產SUV稱霸!最接地氣的銷量榜解析

期望非常大,如果又遇到黑它的人,請大家備好磚頭,你懂的。

哈弗H6的銷量如此火爆,下個月還能賣7萬輛嗎?期望非常大,如果又遇到黑它的人,請大家備好磚頭,你懂的。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

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

※回頭車貨運收費標準

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

※產品缺大量曝光嗎?你需要的是一流包裝設計!

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

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

價錢低逼格不低,小弟車型這麼屌,叫大哥怎麼混?

由於全系的X1使用了UKL平台,橫置布局的發動機,再加上對車內空間的優化,最終的表現非常出色,加上X1的第二排座椅還可以前後移動和調節靠背角度,空間表現已經超越了其大哥X3。X1 xDrive25Li使用了代號為B48A20Ο0的高功率版2。

在中國的傳統家庭里,有一個非常有趣的現象,如果你有哥哥或者姐姐,一般情況下都不能比哥哥姐姐早結婚,父母要催婚,肯定是先從哥哥姐姐下手,如果弟弟妹妹先結婚了,哥哥姐姐會過上很慘的被催婚生活。

其實在很多領域都存在着這樣的現象,例如考量業績的銷售業,鄉鎮級分銷點的銷量比縣城級分銷點高,那就非常尷尬了。

但是在汽車行業,卻是截然不同,消費者非常樂意看到某車型超越自己的大哥,最典型的例子就是經常被冠以“小S”稱號的奔馳E級。

我們拿同樣是320 L的奔馳E級與S級進行對比,雖然兩者採用了同樣的設計語言,但是在車身尺寸上還是相差甚遠的,奔馳E 320 L 4MATIC的車身尺寸為:5065x1860x1482 mm,軸距:3079 mm,奔馳S 320 L 商務型的車身尺寸為:5250x1899x1494 mm,軸距:3165 mm。

奔馳E級雖然後排座椅的橫向空間和頭部空間不及S級,但是後排的腿部縱向空間表現幾乎一樣,非常出色。奔馳E 320 L 4MATIC指導價:62.98萬,奔馳S 320 L 商務型指導價:93.80萬,兩者同樣擁有后風擋遮陽簾和後排側遮陽簾,E 320L還多出了後排側隱私玻璃。

兩車的指導價雖然相差30.82萬,但是發動機同樣是3.0T雙渦輪增壓V6發動機,E 320 L 4MATIC更是擁有9AT和全時四驅系統,配置上比S 320 L 商務型多出了無鑰匙進入、電動/感應後備廂、方向盤/電動座椅/后視鏡記憶功能,還有自適應巡航、主動剎車等一系列高科技配置。

雖然奔馳E級和S級在氣場上還是有不少差距,但如果讓選擇,還是會選擇E級,因為是配置控,同時E 320的机械品質足以滿足絕大多數情景的需求。

接下來的這個對比更加有看點,寶馬X1 xDrive25Li 豪華型對比寶馬X3 sDrive20i,兩者的指導價分別是43.9萬和42.1萬,價格非常接近,重點是兩車的車身尺寸差距很小,寶馬X1的軸距也只是比X3短了30mm而已。

由於全系的X1使用了UKL平台,橫置布局的發動機,再加上對車內空間的優化,最終的表現非常出色,加上X1的第二排座椅還可以前後移動和調節靠背角度,空間表現已經超越了其大哥X3。

X1 xDrive25Li使用了代號為B48A20Ο0的高功率版2.0T發動機,X3 sDrive20i則是使用N20B20的低功率版2.0T發動機,X1的動力表現比X3要好出不少,而且X1 xDrive25Li是前置適時四驅,X3 sDrive20i只是前置后驅。

在配置方面,X1 xDrive25Li多出了無鑰匙進入系統、電動/感應後備廂方向盤換擋、HUD抬頭显示、GpS導航、藍牙、LED大燈、後排出風口、自動泊車、車道偏離預警等等,第二排座椅還可以前後移動和調節靠背角度。

與奔馳的E級和S級不同,X1 xDrive25Li和X3 sDrive20i在價格上相差無幾,X1使用了新的平台、新的動力總成、新的設計,可以說是把還沒換代的老X3打敗了,動力更強、配置更高。

林肯的MKC和MKX這兩款SUV的情況和X1、X3的情況有點相似,我們拿MKC的2017款 2.3T 四驅總統系列與MKX的2015款 2.0T 兩驅尊享版作對比,兩者的指導價分別是43.88萬和44.98萬。

先來進行配置對比MKC僅多出了方向盤加熱、前排座椅通風、後排座椅加熱、自適應遠近光、感應雨刷、自動泊車入位、自適應巡航、車道偏離預警和併線輔助,兩者在配置上的差異其實並不是很大,主要是因為最低配的MKX配置水平真心不低。

MKC和MKX的外觀內飾設計都非常相似,慶幸的是兩車都還沒有使用林肯MKZ的那個最新前臉設計,它們都很好的保留了林肯家族該有的美式設計美學,霸氣的中網和貫穿式的尾燈非常漂亮。

空間表現並不是它們的優勢,重點是MKC和MKX的內飾氛圍都非常豪華,僅看內飾的話,真的感覺不出MKC定位比MKX低,這就是消費者最喜歡的典型例子:花更少的錢得到更高級的視覺享受。

其實同品牌的雞頭鳳尾之選,還是有不少的,例如日產的軒逸和天籟,新款天籟的外觀設計真是佩服,相信有不少人把天籟硬生生看成軒逸,還有國內即將上市的寶馬5系,無論是設計元素還是各項配置,都在向著7系靠攏。

雖然說上面提到的在很多方面都向著大哥靠攏,但我們還是要理性對待,外觀內飾的設計,還有車輛的配置,這些都能夠做到互相媲美,但是在車輛的行駛品質,動態體驗方面,不同級別的車型還是存在着本質區別的,是否值得購買,就要看你注重車輛的是哪個方面了。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

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

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?

這些國產“豪車”價錢可不豪,十幾萬就能考慮入手了!

觀致身處的這個惡性循環:產品力不足 → 經銷商加盟量少 → 銷量沒起色 → 成本居高不下 → 新產品性價比低 → 潛在經銷商更加望而卻步,如此循環。觀致在期待着一個救世主,挽救頹勢。觀致的全新跨界轎車觀致3 GT指導價為11。

稍有起色的自主車企都慢慢開始轉型,尋求向上發展,要涉足中高端路線,要麼推出高端化產品,要麼就再立門戶、開設新的子品牌來抗衡豐田、福特、大眾等一干合資大咖。

而成功“解決溫飽問題、活下來”的自主品牌,都基本具備了推出中高端品牌的造車技術經驗、品牌簇擁者以及市場營銷基礎,自下而上的往上發展亦無可厚非。

傳祺GM8

相比建立中高端子品牌,推出高端化產品來提升品牌形象的效果並沒有前者來得直接,前車之鑒就有行政級轎車東風A9、GA8,走越野路線的哈弗H9,地方補貼的新能源產物榮威E950,市場表現皆慘淡。當然也不乏市場熱烈的車型,吉利博瑞、傳祺GS8把准了時代的脈搏,一炮走紅,銷量當然理想。

更看好自主車企在推出高端化產品獲得成功后再去涉足中高端子品牌,循序漸進,遵循企業發展規律。期待廣汽傳祺今後能為我們繼續打造高端化產品(GA8、GS8、GM8三足鼎立),甚至乎帶來一個高端子品牌。

東風A9

傳祺GA8

哈弗H9

榮威e950

吉利博瑞

傳祺GS8

觀致可以說是該領域的先行者(紅旗打一開始就沒想過要走量、盈利,姑且不算),剛面世時,被外界大肆宣傳、捧得很高,但由於撿錯了敲門磚,觀致選擇以轎車作為第一款面向消費者的產品,而冷落了受眾面更廣的SUV,加上觀致3自身產品力不足、經銷商營銷不力以及售價偏高,導致最終無人問津、摔得很痛。

觀致5

但我們並不能單單隻看到觀致試水失敗這個表象,認為觀致更起到了帶頭作用,吹響了自主品牌走出國門、邁向高端的號角,一石激起千層浪,寶沃、吉利、長城等車企都紛紛覬覦這塊待開發的市場,哪怕它們選取的路徑、理念不同,但他們都為中華汽車製造業爭一口氣,擺脫以往廉價、低端的形象,從事汽車行業的甚是欣慰。

寶沃BX7

下面來為大家介紹自主高端品牌剛推出以及即將推出的量產車,一同拭目以待。

LYNK & CO

LYNK & CO的品牌發布會地點在德國柏林,現場充滿前衛、時尚元素。吉利集團高級設計副總裁彼得·霍布里,過往阿斯頓馬丁、捷豹、路虎和沃爾沃等品牌不少作品都出自他手,博瑞和博越皆由他帶領的設計團隊完成, LYNK & CO 01同樣如此。彼得·霍布里:“車型應當風格鮮明、引人注目,能夠吸引包括中國、歐洲和美國在內的全球消費者。”反正是被吸引住了。

分體式大燈組,LED光帶式日間行車燈,L形尾燈設計前瞻、個性,糅合到一起卻相當和諧,毫不違和,延伸至引擎蓋上的LED日間行車燈靈感源自北歐上空的極光,絢麗奪目,不得不感嘆設計團隊的功架。

相信這款車將來量產後會消化不少來自沃爾沃的技術,尤其在動力總成和主動安全技術方面。(需要指出的是,吉利僅僅是收購了沃爾沃乘用車,而不是指整個沃爾沃集團,扮演着控股的角色,並未達到為所欲為的地步。)

WEY

WEY:長城的高端品牌WEY就這樣低調、悄無聲息出現在我們眼前,相對LYNK & CO要低調,魏建軍講到的:“民營企業沒有後路才能發展”,表達了長城一往無前、決意要做出成績的堅定決心,決意破釜沉舟。

哈弗系列的動力和底盤總成缺乏新意,W01的底盤結構與哈弗H7十分相像,就連動力總成也是2.0T搭配7速雙離合變速箱。而W02的底盤則與哈弗H6相同。

W 01

W 02

核心三大件沒升級、行駛質感沒得到提升的話,再多的噱頭也只是徒勞,希望WEY最後出來的產品不會令失望。

觀致

奇瑞與以色列集團各持股50%的方式成立觀致,給觀致帶來一定的合資背景,但銷量始終不如人意,在歐洲銷售期間更是無人問津。觀致身處的這個惡性循環:產品力不足 → 經銷商加盟量少 → 銷量沒起色 → 成本居高不下 → 新產品性價比低 → 潛在經銷商更加望而卻步,如此循環。觀致在期待着一個救世主,挽救頹勢。

觀致的全新跨界轎車觀致3 GT指導價為11.09-13.99萬元。增加了一套跨界風格的車身套件,如前後的保險杠下護板、運動包圍、黑色輪眉,相信年輕人會對其青睞有加。

觀致3 GT採用1.6T發動機,最大功率為156ps,峰值扭矩230N·m,參數要比起轎車版要高點,匹配6速手動或6速雙離合變速箱。

希望觀致能推出更多競爭力強的產品去豐富產品線、整頓經營,力挽狂瀾。挫折並不像江河那樣不可逾越,而是前進的動力,觀致彆氣餒!

寶沃

寶沃BX5在2016年廣州車展正式亮相。寶沃BX5定位緊湊型SUV,長寬高分別是4483×1876×1677mm,軸距2685mm,在同級別車型中,它是屬於規格相對比較大的類型。

新車依舊採用寶沃家族式的多邊形格柵設計,后包圍的裝飾件帶有濃濃地運動氣息,寶沃這次將目標人群瞄準在年輕人。

寶沃BX5將提供1.4T混動和1.8T汽油發動機版本。1.8T發動機最大功率190ps,峰值扭矩280N·m,搭配6速手自一體變速箱,如無意外將會是BX7上那副AISIN愛信6AT。預計寶沃還將推出BX7 TS和BX6 TS,進一步豐富產品線,實現真正的品牌復興。

寶沃BX7 TS

左為寶沃BX6 TS,右為寶沃BX5

總結:很慶幸出生在這個時代,能見證着自主汽車的起步,在市場摸爬滾打,獨當一面再到後來往上發展,開拓高端品牌、突破自我,自豪感油然而生。但不少人卻對自主汽車嗤之以鼻,用他們有限的認知、先入為主地去詆毀它們,這是所不能接受的。

自主汽車目前所經歷的發展階段是一種歷史的必然,哪怕是鍵盤車神們跪舔的德系、日系亦同樣經歷過,給自主汽車更多耐心和鼓勵,它一定會用更多低價格、高品質、效費比更理想的產品來回報國民,證明我大中華也是汽車強國。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

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

※回頭車貨運收費標準

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

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

7.89萬起的SUV配置竟然這麼高,教授看好他的銷量喔!

新車落地時,可以在選配廠家幫你加裝的行車記錄儀,集合在駕駛艙的后視鏡裏面,通過中控台的按鍵,可以將畫面轉到這個9寸彩色大屏幕上,可以手動操作拍照和錄製功能,非常方便。除了最低配之外,其他配置都是真皮包裹座椅,高配則還有座椅加熱和電動調節功能,乘坐起來給人的感覺還可以,雖然不能說包裹性很強,但是舒適性還是夠的,至於後排空間,如果一個正常體型的180CM身高小伙子坐進去,大概腿部空間還能夠有近兩拳的距離。

自從上次發完森雅R7的產品介紹后,後台很多粉絲都在追問這車新搭載的自動擋究竟開起來怎麼樣,愛信的6AT是否能夠做到眾望所歸?諸如此類問題。沒錯,這一期將詳細地往“體驗”這方面,來講一講這台車,除了價格很實惠之外,是否真的能夠為我們帶來些什麼收穫?

森雅R7作為一汽的產品,在手動擋上市時,就已經有這3個亮點,一個是超高顏值,一個是同級中最長的軸距,最後一個則是越級的配置,定價便宜,非常符合三四線城市人們購車的需求,所以在當時就已經備受粉絲關注,然而這次自動擋6AT的到來,更為許多“不會開手動擋”的消費者解決了另一個難題。

貌似在中國,有着這麼一個不成文的規定,但凡是新車,首先一定要在外觀上足夠吸引人,才能稱為成功了一半,眾泰走抄襲之路贏得了群眾的眼球,陸風靠着路虎的外觀檔次一下高了不少,而作為一汽旗下的森雅R7,則靠着與眾不同的雄鷹外觀,也贏得了許多人的關注,大燈犀利,整個車頭看起來讓人有種舒服的感覺,腰線優雅,作為一款小型SUV,整體風格小巧儒雅。

全車前大燈都採用鹵素光源,但都帶有日間行車燈,視覺效果蠻不錯,17英寸鋁合金輪轂同樣為全系標配,加上紅色的剎車卡鉗,運動感一下子上來了,在之前,後台就有很多粉絲在評論說,車子顏值是不錯,不過可惜就可惜在車標上,但覺得現在自主品牌實力不斷地雄厚,只要車子質量好,車標改不改,都是事後的問題了,不必過於糾結。

其實買車群眾可以分為兩種人,一種是堅持買自主品牌車,一種是只考慮合資車,但你瞧我們自主品牌的內飾風格,不說那些抄襲寶馬奧迪內飾的其他牌子,就拿森雅R7的內飾作為例子,7.89萬自動擋版本,能夠有這種設計還是少有的,按鍵實在,使用起來非常簡單,屏幕也夠大,觸控反應靈敏。

除了自動舒適型之外,其他自動車型全配有真皮方向盤,ESp車身穩定系統,上坡輔助,定速巡航,多功能方向盤,發動機啟停裝置,頂配則多了全景攝像頭,雖然這些每次都會說,但有了就非常不同,買配置也是我們中國人選車所考慮的因素之一,凡是熱門的車,肯定有着一套非常齊整的配置,才能稱之為性價比高。

新車落地時,可以在選配廠家幫你加裝的行車記錄儀,集合在駕駛艙的后視鏡裏面,通過中控台的按鍵,可以將畫面轉到這個9寸彩色大屏幕上,可以手動操作拍照和錄製功能,非常方便。

除了最低配之外,其他配置都是真皮包裹座椅,高配則還有座椅加熱和電動調節功能,乘坐起來給人的感覺還可以,雖然不能說包裹性很強,但是舒適性還是夠的,至於後排空間,如果一個正常體型的180CM身高小伙子坐進去,大概腿部空間還能夠有近兩拳的距離。

先說說這台1.6L的自然吸氣發動機,技術是基於大眾EA系列發動機自主研發而成的,具有進氣側的可變氣門正時技術,最大功率116匹馬力,峰值扭矩155牛米,在城市中跟車行駛的話,搭配着油門踏板,初段給人的加速感還是有的,反應积極,匹配着日本愛信第三代6速手自一體變速器,加速感覺還是比較平順。

當繼續深踩油的時候,中後段的動力則有點力不從心了,但畢竟這是一台1.6L自然吸氣發動機,並沒有像其他發動機一樣有渦輪增壓器的介入,但1.6L自然吸氣+愛信成熟的6AT,可以很好地控制油耗表現。

在平時的道路上,這款自動變速箱在升擋的節奏上,還是能夠與我們駕駛員做到節奏一致的,而在上坡的時候,變速箱則退到低速擋,同時將發動機轉速升到3000左右,將這股力氣供給前輪,動力不會很突兀,高轉數難免發動機噪音會有一些,這是難免的,但在平時的駕駛中,經過隔音棉,噪音得到了挺好的控制,不會讓人感覺到這款國產車一加速就立馬掉檔次。

底盤懸架則採用前麥弗遜后扭力梁設計,這種設計無論是在這個價位,還是這個等級,都非常之常見,在行駛過程中,來自底盤的噪音並不大,減振器在濾振方面,確實挺到位,開起來確實還是有質感的,這種調校給人一種厚實的感覺。

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

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

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

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

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

除了FastJson,你也應該了解一下Jackson(二)

概覽

上一篇文章介紹了Jackson中的映射器ObjectMapper,以及如何使用它來實現Json與Java對象之間的序列化和反序列化,最後介紹了Jackson中一些序列化/反序列化的高級特性。而本文將會介紹Jackson中的一些常用的(序列化/反序列化)註解,並且通過示例來演示如何使用這些註解,從而來提高我們在處理Json上的工作效率。

序列化註解

@JsonAnyGetter

@JsonAnyGetter註解允許靈活地使用映射(鍵值對,如Map)字段作為標準屬性。

我們聲明如下Java類:

@Data
@Accessors(chain = true)
public static class ExtendableBean {
    public String name;
    private Map<String, String> properties;

    @JsonAnyGetter
    public Map<String, String> getProperties() {
        return properties;
    }
}

編寫測試代碼,測試@JsonAnyGetter:

@Test
public void testJsonAnyGetter() throws JsonProcessingException {
    ExtendableBean extendableBean = new ExtendableBean();
    Map<String, String> map = new HashMap<>();
    map.put("age", "13");
    extendableBean.setName("dxsn").setProperties(map);
    log.info(new ObjectMapper().writeValueAsString(extendableBean));
  	//打印:{"name":"dxsn","age":"13"}
    assertThat(new ObjectMapper().writeValueAsString(extendableBean)).contains("name");
    assertThat(new ObjectMapper().writeValueAsString(extendableBean)).contains("age");
}

如上,可以看properties屬性中的鍵值對(Map)被擴展到了ExtendableBean的Json對象中。

@JsonGetter

@JsonGetter註解是@JsonProperty註解的替代品,用來將一個方法標記為getter方法。

我們創建以下Java類

@Data
@AllArgsConstructor
@NoArgsConstructor
public static class MyBean {
    public int id;
    private String name;

    @JsonGetter("name")
    public String getTheName() {
        return name;
    }
}

如上,我們在類中聲明了一個getTheName()方法,並且使用@JsonGetter(“name”)修飾,此時,該方法將會被Jackson認作是name屬性的get方法。

編寫測試代碼:

@Test
public void testJsonGetter() throws JsonProcessingException {
    MyBean myBean = new MyBean(1, "dxsn");
    String jsonStr = new ObjectMapper().writeValueAsString(myBean);
    log.info(jsonStr);
    assertThat(jsonStr).contains("id");
    assertThat(jsonStr).contains("name");
}

可以看到,jackson將私有屬性name,也進行了序列化。

@JsonPropertyOrder

我們可以使用@JsonPropertyOrder註解來指定Java對象的屬性序列化順序。

@JsonPropertyOrder({"name", "id"})
//order by key's name
//@JsonPropertyOrder(alphabetic = true)
@Data
@Accessors(chain = true)
public static class MyOrderBean {
  public int id;
  public String name;
}

編寫測試代碼:

@Test
public void testJsonPropertyOrder1() throws JsonProcessingException {
    MyOrderBean myOrderBean = new MyOrderBean().setId(1).setName("dxsn");
    String jsonStr = new ObjectMapper().writeValueAsString(myOrderBean);
    log.info(jsonStr);
    assertThat(jsonStr).isEqualTo("{\"name\":\"dxsn\",\"id\":1}");
}

如上,可以看到序列化得到的Json對象中屬性的排列順序正是我們在註解中指定的順序。

@JsonRawValue

@JsonRawValue註解可以指示Jackson按原樣序列化屬性。

在下面的例子中,我們使用@JsonRawValue嵌入一些定製的JSON作為一個實體的值:

@Data
@AllArgsConstructor
@NoArgsConstructor
public static class RawBean {
    public String name;
    @JsonRawValue
    public String json;
}

編寫測試代碼:

@Test
public void testJsonRawValue() throws JsonProcessingException {
    RawBean rawBean = new RawBean("dxsn", "{\"love\":\"true\"}");
    log.info(new ObjectMapper().writeValueAsString(rawBean));
  	//輸出:{"name":"dxsn","json":{"love":"true"}}
    String result = new ObjectMapper().writeValueAsString(rawBean);
    assertThat(result).contains("dxsn");
    assertThat(result).contains("{\"love\":\"true\"}");
}

@JsonValue

@JsonValue表示Jackson將使用一個方法來序列化整個實例。

下面我們創建一個枚舉類:

@AllArgsConstructor
public static enum TypeEnumWithValue {
    TYPE1(1, "Type A"), TYPE2(2, "Type 2");
    private Integer id;
    private String name;

    @JsonValue
    public String getName() {
        return name;
    }
}

如上,我們在getName()上使用@JsonValue進行修飾。

編寫測試代碼:

@Test
public void testJsonValue() throws JsonProcessingException {
    String  jsonStr = new ObjectMapper().writeValueAsString(TypeEnumWithValue.TYPE2);
    log.info(jsonStr);
    assertThat(jsonStr).isEqualTo("Type 2");
}

可以看到,枚舉類的對象序列化后的值即getName()方法的返回值。

@JsonRootName

如果啟用了包裝(wrapping),則使用@JsonRootName註解可以指定要使用的根包裝器的名稱。

下面我們創建一個使用@JsonRootName修飾的Java類:

@JsonRootName(value = "user")
@Data
@AllArgsConstructor
public static class UserWithRoot {
    public int id;
    public String name;
}

編寫測試:

@Test
public void testJsonRootName() throws JsonProcessingException {
    UserWithRoot userWithRoot = new UserWithRoot(1, "dxsn");
    ObjectMapper mapper = new ObjectMapper();
  	//⬇️重點!!!
    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
  
    String result = mapper.writeValueAsString(userWithRoot);
    log.info(result);
  	//輸出:{"user":{"id":1,"name":"dxsn"}}
    assertThat(result).contains("dxsn");
    assertThat(result).contains("user");
}

上面代碼中,我們通過開啟ObjectMapper的SerializationFeature.WRAP_ROOT_VALUE。可以看到UserWithRoot對象被序列化后的Json對象被包裝在user中,而非單純的{"id":1,"name":"dxsn"}

@JsonSerialize

@JsonSerialize註解表示序列化實體時要使用的自定義序列化器。

我們定義一個自定義的序列化器:

public static class CustomDateSerializer extends StdSerializer<Date> {
    private static SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateSerializer() {
        this(null);
    }

    public CustomDateSerializer(Class<Date> t) {
        super(t);
    }

    @Override
    public void serialize(
        Date value, JsonGenerator gen, SerializerProvider arg2) throws IOException, JsonProcessingException {
        gen.writeString(formatter.format(value));
    }
}

使用自定義的序列化器,創建Java類:

@Data
@AllArgsConstructor
public static class Event {
    public String name;
    @JsonSerialize(using = CustomDateSerializer.class)
    public Date eventDate;
}

編寫測試代碼:

@Test
public void testJsonSerialize() throws ParseException, JsonProcessingException {
    SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
    String toParse = "20-12-2014 02:30:00";
    Date date = formatter.parse(toParse);
    Event event = new Event("party", date);
    String result = new ObjectMapper().writeValueAsString(event);
    assertThat(result).contains(toParse);
}

可以看到,使用@JsonSerialize註解修飾指定屬性后,將會使用指定的序列化器來序列化該屬性。

反序列化註解

@JsonCreator

我們可以使用@JsonCreator註解來優化/替換反序列化中使用的構造器/工廠。

當我們需要反序列化一些與我們需要獲取的目標實體不完全匹配的JSON時,它非常有用。

現在,有如下一個Json對象:

{"id":1,"theName":"My bean"}

我們聲名了一個Java類:

@Data
public static class BeanWithCreator {
    private int id;
    private String name;
}

此時,在我們的目標實體中沒有theName字段,只有name字段。現在,我們不想改變實體本身,此時可以通過使用@JsonCreator和@JsonProperty註解來修飾構造函數:

@Data
public static class BeanWithCreator {
    private int id;
    private String name;

    @JsonCreator
    public BeanWithCreator(@JsonProperty("id") int id, @JsonProperty("theName") String name) {
        this.id = id;
        this.name = name;
    }
}

編寫測試:

@Test
public void beanWithCreatorTest() throws JsonProcessingException {
    String str = "{\"id\":1,\"theName\":\"My bean\"}";
    BeanWithCreator bean = new ObjectMapper()
        .readerFor(BeanWithCreator.class)
        .readValue(str);
 	 	assertThat(bean.getId()).isEqualTo(1);
    assertThat(bean.getName()).isEqualTo("My bean");
}

可以看到,即使Json對象中的字段名和實體類中不一樣,但由於我們手動指定了映射字段的名字,從而反序列化成功。

@JacksonInject

@JacksonInject表示java對象中的屬性將通過注入來賦值,而不是從JSON數據中獲得其值。

創建如下實體類,其中有字段被@JacksonInject修飾:

public static class BeanWithInject {
    @JacksonInject
    public int id;
    public String name;
}

編寫測試:

@Test
public void jacksonInjectTest() throws JsonProcessingException {
    String json = "{\"name\":\"dxsn\"}";
    InjectableValues inject = new InjectableValues.Std()
        .addValue(int.class, 1);
    BeanWithInject bean = new ObjectMapper().reader(inject)
        .forType(BeanWithInject.class)
        .readValue(json);
    assertThat(bean.id).isEqualTo(1);
    assertThat(bean.name).isEqualTo("dxsn");
}

如上,我們在測試中將json字符串(僅存在name字段)進行反序列化,其中id通過注入的方式對屬性進行賦值。

@JsonAnySetter

@JsonAnySetter允許我們靈活地使用映射(鍵值對、Map)作為標準屬性。在反序列化時,JSON的屬性將被添加到映射中。

創建一個帶有@JsonAnySetter的實體類:

public static class ExtendableBean {
    public String name;
    public Map<String, String> properties;

    @JsonAnySetter
    public void add(String key, String value) {
        if (properties == null) {
            properties = new HashMap<>();
        }
        properties.put(key, value);
    }
}

編寫測試:

@Test
public void testJsonAnySetter() throws JsonProcessingException {
    String json = "{\"name\":\"dxsn\", \"attr2\":\"val2\", \"attr1\":\"val1\"}";
    ExtendableBean extendableBean = new ObjectMapper().readerFor(ExtendableBean.class).readValue(json);
    assertThat(extendableBean.name).isEqualTo("dxsn");
    assertThat(extendableBean.properties.size()).isEqualTo(2);
}

可以看到,json對象中的attr1,attr2屬性在反序列化之後進入了properties。

@JsonSetter

@JsonSetter是@JsonProperty的替代方法,它將方法標記為屬性的setter方法。
當我們需要讀取一些JSON數據,但目標實體類與該數據不完全匹配時,這非常有用,因此我們需要優化使其適合該數據。

創建如下實體類:

@Data
public static class MyBean {
    public int id;
    private String name;

    @JsonSetter("name")
    public void setTheName(String name) {
        this.name = "hello " + name;
    }
}

編寫測試:

@Test
public void testJsonSetter() throws JsonProcessingException {
    String json = "{\"id\":1,\"name\":\"dxsn\"}";
    MyBean bean = new ObjectMapper().readerFor(MyBean.class).readValue(json);
    assertThat(bean.getName()).isEqualTo("hello dxsn");
}

可以看到,json對象中的name屬性為“dxsn”,我們通過在MyBean類中定義了使用@JsonSetter(“name”)註解修飾的方法,這表明該類的對象在反序列話的時候,name屬性將來自此方法。最後MyBean對象中name的值變為了hello dxsn。

@JsonDeserialize

@JsonDeserialize註解指定了在反序列化的時候使用的反序列化器。

如下,定義了一個自定義的反序列化器:

public static class CustomDateDeserializer extends StdDeserializer<Date> {
    private static SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

    public CustomDateDeserializer() {
        this(null);
    }

    public CustomDateDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Date deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException {
        String date = jsonparser.getText();
        try {
            return formatter.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}

創建一個使用@JsonDeserialize(using = CustomDateDeserializer.class)修飾的實體類:

public static class Event {
    public String name;
    @JsonDeserialize(using = CustomDateDeserializer.class)
    public Date eventDate;
}

編寫測試:

@Test
public void whenDeserializingUsingJsonDeserialize_thenCorrect()
    throws IOException {
    String json = "{\"name\":\"party\",\"eventDate\":\"20-12-2014 02:30:00\"}";
    SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
    Event event = new ObjectMapper().readerFor(Event.class).readValue(json);
    assertThat(event.name).isEqualTo("party");
    assertThat(event.eventDate).isEqualTo(df.format(event.eventDate));

}

可以看到,在Event對象中,eventDate屬性通過自定義的反序列化器,將“20-12-2014 02:30:00”反序列化成了Date對象。

@JsonAlias

@JsonAlias在反序列化期間為屬性定義一個或多個替代名稱。讓我們通過一個簡單的例子來看看這個註解是如何工作的:

@Data
public static class AliasBean {
    @JsonAlias({"fName", "f_name"})
    private String firstName;
    private String lastName;
}

如上,我們編寫了一個使用@JsonAlias修飾的AliasBean實體類。

編寫測試:

@Test
public void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {
    String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";
    AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);
    assertThat(aliasBean.getFirstName()).isEqualTo("John");
}

可以看到,即使json對象中的字段名是fName,但是由於在AliasBean中使用@JsonAlias修飾了firstName屬性,並且指定了兩個別名。所以反序列化之後fName被映射到AliasBean對象的firstName屬性上。

更多

除上述註解之外,Jackson還提供了很多額外的註解,這裏不一一列舉,接下來會例舉幾個常用的註解:

  • @JsonProperty:可以在類的指定屬性上添加@JsonProperty註解來表示其對應在JSON中的屬性名。
  • @JsonFormat:此註解在序列化對象中的日期/時間類型屬性時可以指定一種字符串格式輸出,如:@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = “dd-MM-yyyy hh:mm:ss”)。
  • @JsonUnwrapped:@JsonUnwrapped定義了在序列化/反序列化時應該被扁平化的值。
  • @JsonIgnore:序列化/反序列化時忽略被修飾的屬性。
  • ……

總結

本文主要介紹了Jackson常用的序列化/反序列化註解,最後介紹了幾個常用的通用註解。Jackson中提供的註解除了本文列舉的還有很多很多,使用註解可以讓我們的序列化/反序列化工作更加輕鬆。如果你想將某庫換成Jackson,希望這篇文章可以幫到你。

本文涉及的代碼地址:https://gitee.com/jeker8chen/jackson-annotation-demo

歡迎訪問筆者博客:blog.dongxishaonian.tech

關注筆者公眾號,推送各類原創/優質技術文章 ⬇️

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

【其他文章推薦】

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

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

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

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

※回頭車貨運收費標準

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

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