月份: 2020 年 9 月

  • 三菱汽車計畫到2020年 擴增環保車款比重至20%

    三菱汽車計畫到2020年 擴增環保車款比重至20%

    據日經新聞11日報導,因看好今後日本國內快速充電器可望日益普及,汽車大廠三菱汽車(Mitsubishi Motors)計畫擴增插電式油電混合車(PHV)的車種數量;並計畫投資約50億日圓改良主力生產據點「名古屋製作所」的產線,目標為在2015年5月底前將PHV年產能倍增至6萬台的水準、並計劃於2015年開始出口至北美進行販售。

    目前PHV等環保車款佔三菱汽車整體產量比重僅2%,但三菱汽車計劃於2020年度將其比重提高至20%的水準。三菱汽車已於2013年1月開賣PHV車種「Outlander PHEV」,目前日本國內累計銷售量為1萬台、歐洲市場累銷也約1萬台。而除了Outlander車種之外,三菱汽車也計畫推出「Pajero」及「RVR」車款的PHV。

    Outlander PHEV

    日經新聞曾於2013年7月報導指出,豐田汽車(Toyota)、日產汽車(Nissan)、本田汽車(Honda)及三菱汽車(Mitsubishi Motors)等日本4大車廠計畫攜手合作,計畫將日本國內使用於電動車等車種的快速充電器設置數量擴增至4,000座以上,將較現行提高1倍。以期望藉由擴充充電設備,擴大電動車及插電式油電混合車(PHV)市場。

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

    【其他文章推薦】

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

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

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

    ※幫你省時又省力,新北清潔一流服務好口碑

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

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

  • 中國醞釀小範圍試點扶持微型電動車

    據上證報從第四屆全球新能源大會上獲悉,中國大陸主管部門正在研究在全國部分城市開展小範圍示範試點工作,以加強管理,規範市場,對微型電動車的發展「謹慎扶持」。中國微型電動車市場潛力巨大,有車企人士表示,「去年大陸國內銷售達35萬輛左右,今年有望增至50萬輛。」

    中汽協副秘書長葉盛基指出,國家正研究制定相關政策,推動微型電動車向準電動車發展,未來將提升微型電動車的安全標準,確保符合環保要求,並不斷提高微型電動車的電池性能。

    此外,因採取租賃模式,微型電動車在浙江等省份發展迅速,如2,000元人民幣左右就能租到一輛微型電動車,使消費者的用車成本大幅下降,促進了微型電動車的快速成長。

    據瞭解,已在美國納斯達克上市的浙江康迪車業(KNDI.US)是中國微型電動車的代表企業,受益於新能源汽車產業的廣闊空間,公司股價自去年底以來已創歷史新高。

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

    【其他文章推薦】

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

    新北清潔公司,居家、辦公、裝潢細清專業服務

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

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

    ※超省錢租車方案

    FB行銷專家,教你從零開始的技巧

  • 萬向集團收購價更優厚 Fisker將再次公開拍賣

    據悉,萬向集團與李澤楷爭奪已破產的美國豪華電動車廠Fisker的官司,上周五(10日)有了結果,法官拒絕了李澤楷的收購建議,並同意萬向集團提出將Fisker公開拍賣的請求。Fisker的律師其後開會討論拍賣日期,以及萬向集團取代混合動力控股作為Fisker的破產貸方事宜。

    此前,萬向旗下美國公司VL向當地法院提出,對Fisker的收購提價1000萬美元,令總作價達3570萬美元,該價格無疑對負債纍纍的Fisker極具吸引,並獲Fisker債權人支持。

    美國能源部曾為Fisker提供5.29億美元貸款,Fisker在2007年成立後,於民間及公開集資逾14億美元,但最終仍要破產。

    去年10月,混合動力控股於拍賣中,僅花2500萬美元,從美國政府方面購入Fisker的貸款而控制該公司。但Fisker的無擔保債權人為保利益,與萬向聯手提出反對,聲言可為債權人追收近40%的債款。

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

    【其他文章推薦】

    新北清潔公司,居家、辦公、裝潢細清專業服務

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

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

    ※超省錢租車方案

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

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

  • 傳Tesla擬在中國建免費電動車充電站

    據國外媒體報導,美國電動汽車生產商特斯拉(Tesla)正準備在中國建立一批免費充電站,從而支援公司汽車的長距離行駛,例如從北京開到上海。特斯拉方面已開始同物業主及電力服務提供商進行交流,但尚未透露這些充電站何時可以投入使用。
     
    特斯拉在美國有一套類似的充電站網絡,靠電池行駛的特斯拉「Model S」型轎車能夠通過免費充電站的支援,橫穿美國。該公司目前還在為歐洲建設類似的網絡。
     
    中國政府一直在推廣電動汽車銷售,作為解決當地汽車尾氣污染的措施之一。但這一舉措並不怎么成功,主要是因為充電設施建設的難度太大。

    特斯拉目前在中國北京有一處展廳,以及一個服務與銷售網點。該公司打算將上海作為下一個目標,並且大膽拓展業務。目前中國購車者可以訂購特斯拉「Model S」與即將發布的「Model X」,預付款為25萬元人民幣,約合4.1萬美元。

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

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

  • 去年四季度Model S大賣6900輛 特斯拉股價飆

    雖然美國電動車製造商特斯拉(Tesla)日前召回了2.9萬個充電器轉接頭,使Model S安全疑慮再起,但Tesla週二公布,2013年第4季(10~12月)Model S高級房車大賣6900輛,銷量與營收年增率可望雙雙超越20%。

    據特斯拉提交美國國家公路交通安全管理局(NHTSA)的文件表示,2013年出廠的Model S充電器轉接頭藏有過熱可能性,「可能造成轉接頭融化,且在最遭情況下可能起火」。去年Model S一共傳出3起事故,全因車輛行駛時遭重物撞裂底盤電池防護蓋才起火,但3起事故皆未造成人員傷亡。

    特斯拉周二發表的銷售數字再度驗證,消費者對Model S的信心絲毫不減。特斯拉近來不僅獲得多方產業專家肯定Model S安全性,也在美國增設快速充電的「超級充電站」,估計不久後用戶橫跨美國就不用擔心沒電。

    Model S是特斯拉的主打車型,已有超過2.5萬輛Model S在上路行駛。特斯拉預期今年年底銷售分店應會增設2倍以上,今年特斯拉電動汽車銷量可能會大幅成長。

    Tesla股價在周二收盤大漲16%至161.27美元,創6周以來最大漲幅,周三盤中續漲6%,每股171.37美元。

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

    【其他文章推薦】

    ※超省錢租車方案

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

    ※回頭車貨運收費標準

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

    FB行銷專家,教你從零開始的技巧

  • Accelerate Framework in Swift

    Accelerate Framework in Swift

    介紹:

          最近看到這篇文章有對Accelerate框架有一個介紹,自己也按照作者給的思路整理了一遍,也算是對這一框架的一個重新的回顧和學習,在以前研究AR先關只是的時候有接觸到這個框架,贊具體裏面的東西沒有好好的實踐一下,文章中有一些關於向量和矩陣運算的實際的Swift例子。可以簡單的看一下。

         Introduction to the Accelerate Framework in Swift

         關於這個框架和文章其實在前面介紹iOS框架系列文章的時候有提過(第一篇),對這個框架有不清楚是做什麼的可以翻翻我以前總結的文章。 

         由於下面的運算都是些向量和矩陣的運算,要是不清楚他們的概念和運算規則的可以看下面,先了解清楚再往下看,這些具體的內容在項目當中其實還是會用到的,比如說視頻編碼處理、AR等等。

         向量

         矩陣

     

    Accelerate

     

          使用之前請先導入這兩個框架:

          NOTE: 下面所有的例子全都是在 Playground 運行驗證

    import UIKit
    import Accelerate
    import simd

          1、cblas_saxpy  

          函數cblas_saxpy(_:_:_:_:_:_:)是一個計算常數乘以一個向量加上一個向量的函數,具體的使用看下面的例子:

    var x:[Float] = [1,2,3]
    var y:[Float] = [4,5,6]
    
    cblas_saxpy(3, 10, &x, 2, &y, 2)
    

          具體的驗證結果和詳細的函數參數說明我們會在下面展示,大家可以先看上面給出的函數的說明推導一下結果:

          2、cblas_sdot 這個函數能幫助我們計算出兩個向量的數量積:  ∑ a[i] * b[i] 

    y = [4,5,6]
    /// x*y = (1*4)+(2*5)+(3*6) = 32
    /// 這個函數的具體的參數可以參考上面
    cblas_sdot(3, &x, 1, &y, 1)

          3、sgesv_ 這個函數可以幫我們解方程,比如下面的三元三次方程,具體的驗證你可以自己嘗試一下,了解一下函數的參數的意義,我們已經驗證過就不再重複結果。

    /// 下面我們解一個三元方程
    /// 7x+5y-3z = 16
    /// 3x-5y+2z = -8
    /// 5x+3y-7z = 0
    typealias LAInt = __CLPK_integer
    
    var A:[Float] = [
    
        7, 3, 5,   /// x
        5, -5,3,   /// y
        -3,2,-7    /// z
    ]
    
    var b:[Float] = [16,-8,0]
    
    /// 定義要解的是一個幾元方程
    let equations = 3
    /// 方程的個數
    var numberOfEquations:LAInt = 3
    var columnsIntA:LAInt = 3
    var elementsIntB:LAInt = 3
    /// 解的個數
    var bSolutionCount:LAInt = 1
    /// 驗證是否計算有問題
    var outputOk:LAInt = 0
    /// [0,0,0]
    var pivot = [LAInt](repeating: 0, count: equations)
    
    /// 參數定義(按順序):求解的線性方程個數、解的個數、係數矩陣A、
    /// 矩陣A的列數、排列矩陣、係數向量B、向量B的列數、輸出值。
    sgesv_(&numberOfEquations, &bSolutionCount, &A, &columnsIntA, &pivot, &b, &elementsIntB, &outputOk)
    
    /// outputOk == 0 說明一切計算正確
    outputOk
    
    /// 這個結果就是我們想要的答案 [1, 3, 2]
    b
    

     

    simd + vecLib + vDSP

           

          具體的這三個框架的內容文章中有介紹過,我們這裏主要的還是驗證和實踐一下裏面的例子,看下面的代碼。

          1、矩陣的加法運算,看下面的例子,注意下面的不是向量的加法,留意區別不要混淆,代碼簡單我直接截圖順便看驗證結果:

           2、vvfabsf 求絕對值的運算,代碼如下:

    /// fabs 求絕對值
    func floats(_ n:Int32) -> [Float]{
        return [Float] (repeating: 0, count: Int(n))
    }
    
    var count:Int32 = 4
    var aAbsoAbsolute = floats(count)
    
    var c:[Float] = [-1,-2,-3,-4]
    vvfabsf(&aAbsoAbsolute, &c, &count)
    
    /// [1,2,3,4] 
    aAbsoAbsolute

          3、vvintf 小數取整求絕對值

    c = [9.987,6.576,-3.345,-4.9]
    var bAbsoAbsolute = floats(count)
    vvintf(&bAbsoAbsolute, &c, &count)
    
    /// [9, 6, -3, -4]
    bAbsoAbsolute

          4、sqrtf 開平方根

    /// sqrt 開平方根  sqrtf()
    c = [25,16,9,4]
    var cAbsoAbsolute = floats(count)
    vvsqrtf(&cAbsoAbsolute, &c, &count)
    
    /// [5, 4, 3, 2]
    cAbsoAbsolute
    

          5、分數取逆 這時候是分母和分子互換位置在做計算得來的

    /// 分數取逆 這時候是分母和分子互換位置在做計算得來的
    var d:[Float] = [1/3,1/5,3/9,4/2]
    var dAbsoAbsolute = floats(count)
    vvrecf(&dAbsoAbsolute, &d, &count)
    
    /// [3, 5, 3, 0.5]
    dAbsoAbsolute
    

          6、vDSP_vdist 這個例子其實也很有趣的,具體的例子說明可以參考最上面文章的最後一個例子,我們直接看代碼和驗證的結果,代碼裏面有比較詳細的說明,還是值得一看的,能幫助我們回憶鞏固一些知識點:

    var points:[CGPoint] = [
        
        CGPoint(x: 0, y: 0),
        CGPoint(x: 0, y: 10),
        CGPoint(x: 0, y: 20),
        CGPoint(x: 0, y: 30),
        CGPoint(x: 0, y: 40),
        CGPoint(x: 0, y: 50),
        CGPoint(x: 0, y: 60),
        CGPoint(x: 0, y: 70),
        CGPoint(x: 0, y: 80)
    ]
     
    let path = UIBezierPath()
    path.move(to: points[0])
     
    // IMP: Remove the space between the < and points
    for i in 1 ..< points.count {
        path.addLine(to: points[i])
    }
    
    var xs = points.compactMap { (point) -> Float? in
        return Float(point.x)
    }
    
    var ys = points.compactMap { (point) -> Float? in
        return Float(point.y)
    }
    
    var distance:[Float] = [Float](repeating: 0, count: points.count)
    
    vDSP_vdist(&xs, 1, &ys, 1, &distance,1,vDSP_Length(points.count))
    
    /// 遍歷
    distance.map {$0}
    
    /// 順便幫忙在加深一下對 reduce 函數的理解
    /// 給一個初始值 然後對集合的每一個元素進行操作
    distance.reduce(0, +)
    
    let initialResult:Float = 0
    var reduceResult =  distance.reduce(initialResult) { (tempResult,element) -> Float in
        return tempResult + element
    }
    
    reduceResult

         下面是上面例子的結果驗證: 

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

    【其他文章推薦】

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

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

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

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

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

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

  • 對象創建與堆

    對象創建與堆

    這一節主要介紹對象創建時,在堆中的一些過程。

    回憶下,我們之前說的,什麼時候會發生垃圾回收?

    除了在一些安全點處也許會發生垃圾回收(只是也許),如果在所需內存不足的情況下,一定會發生垃圾回收。

    分配堆空間

    首先通過設置參數,把堆空間設置為 20M,其中 新生代 10M,老年代 10M。

    參數設置:

    -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails

    結果為:

    Heap
     PSYoungGen      total 9216K, used 1685K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
      eden space 8192K, 20% used [0x00000007bf600000,0x00000007bf7a5580,0x00000007bfe00000)
      from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
      to   space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
     ParOldGen       total 10240K, used 0K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
      object space 10240K, 0% used [0x00000007bec00000,0x00000007bec00000,0x00000007bf600000)
    

    創建一個新對象

    我們首先創建一個對象,這個對象佔用 2M 的空間。

    package heap;
    
    public class CreateObject {
        public static void main(String[] args) {
            byte[] obj1 = new byte[1024 * 1024 * 2];
        }
    }
    

    最後的輸出:

    Heap
     PSYoungGen      total 9216K, used 3733K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
      eden space 8192K, 45% used [0x00000007bf600000,0x00000007bf9a5590,0x00000007bfe00000)
      from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
      to   space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
     ParOldGen       total 10240K, used 0K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
      object space 10240K, 0% used [0x00000007bec00000,0x00000007bec00000,0x00000007bf600000)
    

    可以看到,新生代 被佔用了,老年代佔用為 0K,沒有被使用。

    所以,new 的對象先放在 eden 區。

    填滿 eden 區

    在填滿 eden 區后,會發生什麼呢?因為 survivor 區實在太小了,很難看到。所以,這裏可以藉助 Visual VM,來觀察,更加直觀。

    程序如下:

    package heap;
    
    public class CreateObject {
        public static void main(String[] args) {
            while(true){
                byte[] bytes = new byte[1024 * 512];
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    

    重點是看右邊的記錄圖。注意,這裏我們將每次創建對象的大小設置為了 0.5M。

    當 Eden 滿的時候,會調用垃圾回收器,調用垃圾回收器后,Eden 出現了低谷,Survivor 出現了一個增長。老年區也出現了一個增長。

    當 Eden 滿的時候,如果 Survivor 區有足夠的空間容納存活對象,那麼可以把存活對象放入 Survivor,多的對象放入老年區。

    現在,我們把對象的大小調大。設置為 2M,這樣 Survivor 就無法存放下。

    可以看到,在經過一次垃圾回收的時候(可以看到GC Time 上有波峰,說明執行了一次垃圾回收),但我們注意到,Survivor 區中並沒有被佔用。說明垃圾回收過程中,直接將存活對象放到了老年代中。

    再來聊聊 survivor 區

    對象通常在 Eden 區里誕生,如果經過第一次 MInor GC 后仍然存活,並且能夠被 Survivor 容納的話,該對象會被移動到 Survivor 區,並且將其年齡設置為 1 歲。對象在 Survivor 區每熬過一次 Minor GC,年齡就增加 1 歲,當它年齡增大到一定程度(默認是 15 歲),就會被晉陞到老年代。

    特殊情況

    有些時候,如果用戶創建了大對象,如很長的字符串或者元素很多的數組的時候。這種大對象都佔用大量的內存,像這種大對象,有很大概率是長時間使用的,不然為什麼要創建大對象。

    如果大對象朝生夕滅,我們知道在 Java 8 中,新生代默認採用的 標記-複製 算法,那麼對於大對象而言,是非常耗時的。

    所以,如果 JVM 設置了一個閾值,那麼當分配的對象大於這個閾值的時候,會直接被分配到老年代。

    總結

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

    【其他文章推薦】

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

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

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

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

    新北清潔公司,居家、辦公、裝潢細清專業服務

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

  • python動態柱狀圖圖表可視化:歷年軟科中國大學排行

    python動態柱狀圖圖表可視化:歷年軟科中國大學排行

    本來想參照:https://mp.weixin.qq.com/s/e7Wd7aEatcLFGgJUDkg-EQ搞一個往年編程語言動態圖的,奈何找不到數據,有數據來源的歡迎在評論區留言。

    這裏找到了一個,是2020年6月的編程語言排行,供大家看一下:https://www.tiobe.com/tiobe-index/

     

    我們要實現的效果是:

    大學排名來源:http://www.zuihaodaxue.com/ARWU2003.html

    部分截圖:

    在http://www.zuihaodaxue.com/ARWU2003.html中的年份可以選擇,我們解析的頁面就有了:

    "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)

    初步獲取頁面的html信息的代碼:

    def get_one_page(year):
        try:
            headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
                }
            url = "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
            response=requests.get(url,headers=headers)
            if response.status_code == 200:
                return response.content
        except RequestException:
            print('爬取失敗')

    我們在頁面上進行檢查:

    數據是存儲在表格中的,這樣我們就可以利用pandas獲取html中的數據,基本語法:

    tb = pd.read_html(url)[num]

    其中的num是標識網頁中的第幾個表格,這裏只有一個表格,所以標識為0。初步的解析代碼就有了:

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        return tb

    我們還要將爬取下來的數據存儲到csv文件中,基本代碼如下:

    def save_csv(tb):
        start_time=time.time()
        tb.to_csv(r'university.csv', mode='a', encoding='utf_8_sig', header=True, index=0)
        endtime = time.time()-start_time
        print('程序運行了%.2f秒' %endtime)

    最後是一個主函數,別忘了還有需要導入的包:

    import requests
    from requests.exceptions import RequestException
    import pandas as pd
    import time
    def main(year):
        for i in range(2003,year):
            html=get_one_page(i)
            tb=parse_on_page(html,i)
            #print(tb)
            save_csv(tb)
    if __name__ == "__main__":
        main(2004)

    運行之後,我們在同級目錄下就可以看到university.csv,部分內容如下:

    存在幾個問題:

    (1)缺少年份

    (2)最後一列沒有用

    (3)國家由於是圖片表示,沒有爬取下來

    (4)排名100以後的是一個區間

    我們接下來一一解決:

    (1)刪掉沒用的列

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2, 'score',4]
        tb.drop([2,4],axis=1,inplace=True)
        return tb

    新的結果:

    (2) 對100以後的進行唯一化,增加一列index作為排名標識

    tb['index_rank'] = tb.index
    tb['index_rank'] = tb['index_rank'].astype(int) + 1

    (3)新增加年份

    tb['year'] = i

    (4)新增加國家

    首先我們進行檢查:

    發現國家在td->a>img下的圖像路徑中有名字:UnitedStates。 我們可以取出src屬性,並用正則匹配名字即可。

    def get_country(html):
        soup = BeautifulSoup(html,'lxml')
        countries = soup.select('td > a > img')
        lst = []
        for i in countries:
            src = i['src']
            pattern = re.compile('flag.*\/(.*?).png')
            country = re.findall(pattern,src)[0]
            lst.append(country)
        return lst

    然後這麼使用:

    # read_html沒有爬取country,需定義函數單獨爬取
    tb['country'] = get_country(html)

    最終解析的整體函數如下:

    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2, 'score',4]
        tb.drop([2,4],axis=1,inplace=True)
        tb['index_rank'] = tb.index
        tb['index_rank'] = tb['index_rank'].astype(int) + 1
        tb['year'] = i
        # read_html沒有爬取country,需定義函數單獨爬取
        tb['country'] = get_country(html)
        return tb

    運行之後:

    最後我們要提取屬於中國部分的相關信息:

    首先將年份改一下,獲取到2019年為止的信息:

    if __name__ == "__main__":
        main(2019)

    然後我們提取到中國高校的信息,直接看代碼理解:

    def analysis():
        df = pd.read_csv('university.csv')
        # 包含港澳台
        # df = df.query("(country == 'China')|(country == 'China-hk')|(country == 'China-tw')|(country == 'China-HongKong')|(country == 'China-Taiwan')|(country == 'Taiwan,China')|(country == 'HongKong,China')")[['university','year','index_rank']]
    
        # 只包括內地
        df = df.query("(country == 'China')")
        df['index_rank_score'] = df['index_rank']
        # 將index_rank列轉為整形
        df['index_rank'] = df['index_rank'].astype(int)
    
        # 美國
        # df = df.query("(country == 'UnitedStates')|(country == 'USA')")
    
        #求topn名
        def topn(df):
            top = df.sort_values(['year','index_rank'],ascending = True)
            return top[:20].reset_index()
        df = df.groupby(by =['year']).apply(topn)
    
        # 更改列順序
        df = df[['university','index_rank_score','index_rank','year']]
        # 重命名列
        df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
    
        # 輸出結果
        df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)
        # index可以設置

    本來是想爬取從2003年到2019年的,運行時發現從2005年開始,頁面不一樣了,多了一列:

    方便起見,我們就只從2005年開始了,還需要修改一下代碼:

        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2,3, 'score',5]
        tb.drop([2,3,5],axis=1,inplace=True)

    最後是整體代碼:

    import requests
    from requests.exceptions import RequestException
    import pandas as pd
    import time
    from bs4 import BeautifulSoup
    import re
    def get_one_page(year):
        try:
            headers = {
                    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'
                }
            url = "http://www.zuihaodaxue.com/ARWU%s.html" % str(year)
            response=requests.get(url,headers=headers)
            if response.status_code == 200:
                return response.content
        except RequestException:
            print('爬取失敗')
    def parse_on_page(html,i):
        tb=pd.read_html(html)[0]
        # 重命名表格列,不需要的列用數字錶示
        tb.columns = ['world rank','university', 2,3, 'score',5]
        tb.drop([2,3,5],axis=1,inplace=True)
        tb['index_rank'] = tb.index
        tb['index_rank'] = tb['index_rank'].astype(int) + 1
        tb['year'] = i
        # read_html沒有爬取country,需定義函數單獨爬取
        tb['country'] = get_country(html)
        return tb
    def save_csv(tb):
        start_time=time.time()
        tb.to_csv(r'university.csv', mode='a', encoding='utf_8_sig', header=True, index=0)
        endtime = time.time()-start_time
        print('程序運行了%.2f秒' %endtime)
    # 提取國家名稱
    def get_country(html):
        soup = BeautifulSoup(html,'lxml')
        countries = soup.select('td > a > img')
        lst = []
        for i in countries:
            src = i['src']
            pattern = re.compile('flag.*\/(.*?).png')
            country = re.findall(pattern,src)[0]
            lst.append(country)
        return lst
    def analysis():
        df = pd.read_csv('university.csv')
        # 包含港澳台
        # df = df.query("(country == 'China')|(country == 'China-hk')|(country == 'China-tw')|(country == 'China-HongKong')|(country == 'China-Taiwan')|(country == 'Taiwan,China')|(country == 'HongKong,China')")[['university','year','index_rank']]
    
        # 只包括內地
        df = df.query("(country == 'China')")
        df['index_rank_score'] = df['index_rank']
        # 將index_rank列轉為整形
        df['index_rank'] = df['index_rank'].astype(int)
    
        # 美國
        # df = df.query("(country == 'UnitedStates')|(country == 'USA')")
    
        #求topn名
        def topn(df):
            top = df.sort_values(['year','index_rank'],ascending = True)
            return top[:20].reset_index()
        df = df.groupby(by =['year']).apply(topn)
    
        # 更改列順序
        df = df[['university','index_rank_score','index_rank','year']]
        # 重命名列
        df.rename (columns = {'university':'name','index_rank_score':'type','index_rank':'value','year':'date'},inplace = True)
    
        # 輸出結果
        df.to_csv('university_ranking.csv',mode ='w',encoding='utf_8_sig', header=True, index=False)
        # index可以設置
    def main(year):
        for i in range(2005,year):
            html=get_one_page(i)
            tb=parse_on_page(html,i)
            save_csv(tb)
            print(i,'年排名提取完成完成')
            analysis()
    if __name__ == "__main__":
        main(2019)

    運行之後會有一個university_ranking.csv,部分內容如下:

    接下來就是可視化過程了。

    1、 首先,到作者的github主頁:  
    https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js

    2、克隆倉庫文件,使用git

    # 克隆項目倉庫
    git clone https://github.com/Jannchie/Historical-ranking-data-visualization-based-on-d3.js
    # 切換到項目根目錄
    cd Historical-ranking-data-visualization-based-on-d3.js
    # 安裝依賴
    npm install

    這裏如果git clone超時可參考:

    https://www.cnblogs.com/xiximayou/p/12305209.html

    需要注意的是,這裏的npm是我之前裝node.js裝了的,沒有的自己需要裝一下。

    在執行npm install時會報錯:

    先執行:

    npm init

    之後一直回車即可:

    再執行npm install

    任意瀏覽器打開bargraph.html網頁,點擊選擇文件,然後選擇前面輸出的university_ranking.csv文件,看下效果:

    只能製作動圖上傳了。

    可以看到,有了大致的可視化效果,但還存在很多瑕疵,比如:表順序顛倒了、字體不合適、配色太花哨等。可不可以修改呢?

    當然是可以的,只需要分別修改文件夾中這幾個文件的參數就可以了:

    • config.js 全局設置各項功能的開關,比如配色、字體、文字名稱、反轉圖表等等功能;

    • color.css 修改柱形圖的配色;

    • stylesheet.css 具體修改配色、字體、文字名稱等的css樣式;

    • visual.js 更進一步的修改,比如圖表的透明度等。

    知道在哪裡修改了以後,那麼,如何修改呢?很簡單,只需要簡單的幾步就可以實現:

    • 打開網頁,右鍵-檢查,箭頭指向想要修改的元素,然後在右側的css樣式表裡,雙擊各項參數修改參數,修改完元素就會發生變化,可以不斷微調,直至滿意為止。

        

    • 把參數複製到四個文件中對應的文件里並保存。

    • Git Bash運行npm run build,之後刷新網頁就可以看到優化后的效果。(我發現這一步其實不需要,而且會報錯,我直接修改config.js之後運行也成功了)

    這裏我主要修改的是config.js的以下項:

      // 倒序,使得最短的條位於最上方 
      reverse: true,
      // 附加信息內容。
      // left label
      itemLabel: "本年度第一大學",
      // right label
      typeLabel: "世界排名",
      //為了避免名稱重疊
      item_x: 500,
      // 時間標籤坐標。建議x:1000 y:-50開始嘗試,默認位置為x:null,y:null
      dateLabel_x: 1000,
      dateLabel_y: -50,

    最終效果:

    至此,就全部完成了。

    看起來簡單,還是得要自己動手才行。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
    【其他文章推薦】

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

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

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

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

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※回頭車貨運收費標準

  • angular 接入 IdentityServer4

    angular 接入 IdentityServer4

    angular 接入 IdentityServer4

    Intro

    最近把活動室預約的項目做了一個升級,預約活動室需要登錄才能預約,並用 IdentityServer4 做了一個統一的登錄註冊中心,這樣以後就可以把其他的需要用戶操作的應用統一到 IdentityServer 這裏,這樣就不需要在每個應用里都做一套用戶的機制,接入 IdentityServer 就可以了。

    目前活動室預約的服務器端和基於 angular 的客戶端已經完成了 IdentityServer 的接入,並增加了用戶的相關的一些功能,比如用戶可以查看自己的預約記錄並且可以取消自己未開始的預約,

    還有一個小程序版的客戶端暫時還未完成接入,所以小程序版目前暫時是不能夠預約的

    為什麼要寫這篇文章

    目前在網上看到很多都是基於 implicit 模式接入 IdentityServer,這樣實現起來很簡單,但是現在 OAuth 已經不推薦這樣做了,OAuth 推薦使用 code 模式來代替 implicit

    implicit 模式會有一些安全風險,implicit 模式會將 accessToken 直接返回到客戶端,而 code 模式只是會返回一個 code,accessToken 和 code 的分離的兩步,implicit 模式很有可能會將 token 泄露出去

    詳細可以參考 StackOverflow 上的這個問答

    https://stackoverflow.com/questions/13387698/why-is-there-an-authorization-code-flow-in-oauth2-when-implicit-flow-works

    除此之外,還有一個小原因,大多是直接基於 oidc-client 的 一個 npm 包來實現的,我是用了一個針對 angular 封裝的一個庫 angular-oauth2-oidc,如果你在用 angular ,建議你可以嘗試一下,針對 angular 做了一些封裝和優化,對 angular 更友好一些

    準備接入吧

    API 配置

    預約系統的 API 和網站管理系統是在一起的,針對需要登錄才能訪問的 API 單獨設置了的 policy 訪問

    services.AddAuthentication()
        .AddIdentityServerAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme, options =>
        {
            options.Authority = Configuration["Authorization:Authority"];
            options.RequireHttpsMetadata = false;
    
            options.NameClaimType = "name";
            options.RoleClaimType = "role";
        })
        ;
    
    services.AddAuthorization(options =>
    {
        options.AddPolicy("ReservationApi", builder => builder
            .AddAuthenticationSchemes(IdentityServerAuthenticationDefaults.AuthenticationScheme)
            .RequireAuthenticatedUser()
            .RequireScope("ReservationApi")
        );
    });
    

    需要授權才能訪問的接口設置 Authorize 並指定 Policy 為 ReservationApi

    [Authorize(Policy = "ReservationApi")]
    [HttpPost]
    public async Task<IActionResult> MakeReservation([FromBody] ReservationViewModel model)
    

    IdentityServer Client 配置

    首先我們需要在 IdentityServer 這邊添加一個客戶端,因為我們要使用 code 模式,所以授權類型需要配置 authorization-code 模式,不使用 implicit 模式

    允許的作用域(scope) 是客戶端允許訪問的 api 資源和用戶的信息資源,openid 必選,profile 是默認的用戶基本信息的集合,根據自己客戶端的需要進行配置,ReservationApi 是訪問 API 需要的 scope,其他的 scope 根據客戶端需要進行配置

    angular 客戶端配置

    安裝 angular-oauth2-oidc npm 包,我現在使用的是 9.2.0 版本

    添加 oidc 配置:

    export const authCodeFlowConfig: AuthConfig = {
      issuer: 'https://id.weihanli.xyz',
    
      // URL of the SPA to redirect the user to after login
      redirectUri: window.location.origin + '/account/callback',
    
      clientId: 'reservation-angular-client',
    
      dummyClientSecret: 'f6f1f917-0899-ef36-63c8-84728f411e7c',
    
      responseType: 'code',
    
      scope: 'openid profile ReservationApi offline_access',
    
      useSilentRefresh: false,
    
      showDebugInformation: true,
    
      sessionChecksEnabled: true,
    
      timeoutFactor: 0.01,
    
      // disablePKCI: true,
    
      clearHashAfterLogin: false
    };
    

    在 app.module 引入 oauth 配置

      imports: [
        BrowserModule,
        AppRoutingModule,
        AppMaterialModule,
        HttpClientModule,
        FormsModule,
        ReactiveFormsModule,
        BrowserAnimationsModule,
        OAuthModule.forRoot({
          resourceServer: {
            allowedUrls: ['https://reservation.weihanli.xyz/api'],
            sendAccessToken: true
          }
        })
      ]
    

    OAuthModule 里 resourceServer 中的 allowedUrls 是配置的資源的地址,訪問的資源符合這個地址時就會自動發送 accessToken,這樣就不需要自己實現一個 interceptor 來實現自動在請求頭中設置 accessToken 了

    在 AppComponment 的構造器中初始化 oauth 配置,並加載 ids 的發現文檔

    export class AppComponent {
      constructor(
            private oauth: OAuthService
        ) {
        this.oauth.configure(authConfig.authCodeFlowConfig);
        this.oauth.loadDiscoveryDocument();
        }
        // ...
    }
    

    添加一個 AuthGuard,路由守衛,需要登錄才能訪問的頁面自動跳轉到 /account/login 自動登錄

    AuthGuard:

    import { Injectable } from '@angular/core';
    import { CanActivate, Router } from '@angular/router';
    import { OAuthService } from 'angular-oauth2-oidc';
    
    @Injectable({
      providedIn: 'root'
    })
    export class AuthGuard implements CanActivate {
      constructor(private router: Router, private oauthService: OAuthService) {}
    
      canActivate() {
        if (this.oauthService.hasValidAccessToken()) {
          return true;
        } else {
          this.router.navigate(['/account/login']);
          return false;
        }
      }
    }
    
    

    路由配置:

    import { NgModule } from '@angular/core';
    import { Routes, RouterModule } from '@angular/router';
    import { ReservationListComponent } from './reservation/reservation-list/reservation-list.component';
    import { NoticeListComponent } from './notice/notice-list/notice-list.component';
    import { NoticeDetailComponent } from './notice/notice-detail/notice-detail.component';
    import { AboutComponent } from './about/about.component';
    import { NewReservationComponent } from './reservation/new-reservation/new-reservation.component';
    import { LoginComponent } from './account/login/login.component';
    import { AuthGuard } from './shared/auth.guard';
    import { AuthCallbackComponent } from './account/auth-callback/auth-callback.component';
    import { MyReservationComponent } from './account/my-reservation/my-reservation.component';
    
    const routes: Routes = [
      { path: '', component: ReservationListComponent },
      { path: 'reservations/new', component:NewReservationComponent, canActivate: [AuthGuard] },
      { path: 'reservations', component: ReservationListComponent },
      { path: 'notice', component: NoticeListComponent },
      { path: 'notice/:noticePath', component: NoticeDetailComponent },
      { path: 'about', component: AboutComponent },
      { path: 'account/login', component: LoginComponent },
      { path: 'account/callback', component: AuthCallbackComponent },
      { path: 'account/reservations', component: MyReservationComponent, canActivate: [AuthGuard] },
      { path: '**', redirectTo: '/'}
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
    

    AccountLogin 會將用戶引導到 ids 進行登錄,登錄之後會跳轉到配置的重定向 url,我配置的是 account/callback

    import { Component, OnInit } from '@angular/core';
    import { OAuthService } from 'angular-oauth2-oidc';
    
    @Component({
      selector: 'app-login',
      templateUrl: './login.component.html',
      styleUrls: ['./login.component.less']
    })
    export class LoginComponent implements OnInit {
    
      constructor(private oauthService: OAuthService) {
      }
    
      ngOnInit(): void {
        // 登錄
        this.oauthService.initLoginFlow();
      }
    
    }
    

    Auth-Callback

    import { Component, OnInit } from '@angular/core';
    import { OAuthService } from 'angular-oauth2-oidc';
    import { Router } from '@angular/router';
    
    @Component({
      selector: 'app-auth-callback',
      templateUrl: './auth-callback.component.html',
      styleUrls: ['./auth-callback.component.less']
    })
    export class AuthCallbackComponent implements OnInit {
    
      constructor(private oauthService: OAuthService, private router:Router) {
      }
    
      ngOnInit(): void {
        this.oauthService.loadDiscoveryDocumentAndTryLogin()
        .then(_=> {
          this.oauthService.loadUserProfile().then(x=>{
            this.router.navigate(['/reservations/new']);
          });
        });
      }
    
    }
    

    More

    當前實現還不太完善,重定向現在始終是跳轉到的新預約的頁面,應當在跳轉登錄之前記錄一下當前的地址保存在 storage 中,在 auth-callback 里登錄成功之後跳轉到 storage 中之前的地址

    Reference

    • https://sunnycoding.cn/2020/03/14/angular-spa-auth-with-ocelot-and-ids4-part3/#i-2
    • https://github.com/OpenReservation/angular-client
    • https://github.com/manfredsteyer/angular-oauth2-oidc/
    • https://github.com/OpenReservation/ReservationServer

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 思考:如何保證服務穩定性?

    最近一直在忙618大促的全鏈路壓測&穩定性保障相關工作,結果618還未開始,生產環境就出了幾次生產故障,且大多都是和系統穩定性、性能相關的bad case。

    生產全鏈路壓測終於告一段落,抽出時間將個人收集的穩定性相關資料整理review了一遍,順帶從不同的維度,談談穩定性相關的“務虛”認知和思考。。。

     

    一、SLA!

    在開始談穩定性保障之前,我們先來聊聊業內經常提及的一個Topic:SLA!

    業內喜歡用SLA (服務等級協議,全稱:service level agreement)來衡量系統的穩定性,對互聯網公司來說就是網站服務可用性的一個保證。

    9越多代表全年服務可用時間越長服務越可靠,停機時間越短。就以一個標準99.99%為例,停機時間52.6分鐘,平均到每周也就是只能有差不多1分鐘的停機時間,

    也就是說網絡抖動這個時間可能就沒了。保證一個系統四個9或者更高的五個9,需要一套全體共識嚴格標準的規章制度,沒有規矩不成方圓。創建的規範有如下幾種:

    1、研發規範、自身穩定;

    2、事務中不能包含遠程調用;

    3、超時時間和重試次數要合理;

    4、表數據操作必須double check,合理利用索引,避免出現慢查詢、分庫分表不走分表鍵;

    5、沒有有效的資源隔離, 避免不同業務共用一個線程池或連接池;

    6、合理的系統拓撲,禁止不合理的服務依賴,能去依賴就去依賴,否則同步依賴盡量改成異步弱依賴;

    7、精簡的代碼邏輯;

    8、核心路徑流程必須進行資源隔離,確保任何突發情況主流程不能受影響。

     

    二、單服務穩定性

    關鍵字:開關可控、單一職責、服務隔離、異常兜底、監控發現!

    對於穩定性來說,拋開整體系統架構設計,單就每個業務域服務的穩定性也是非常的重要。

    只有每個業務環節都穩如泰山,才可以保障整個穩定性。單服務的穩定可以從以下幾個方面來進行:

    1、禁用設計:應該提供控制具體功能是否開啟可用的配置,在相應的功能服務出現故障時,快速下線局部功能,以保證整體服務的可用性;

    2、必要的緩存:緩存是解決併發的利器,可以有效的提高系統的吞吐量。按照業務以及技術的緯度必要時可以增加多級緩存來保證其命中率;

    3、接口無狀態性:服務接口應該是無狀態的,當前接口訪問不應該依賴上層接口的狀態邏輯;

    4、接口單一職責性:對於核心功能的接口,不應該過多的耦合不屬於它的功能。如果一個接口做的事情太多應做拆分,保證單接口的穩定性和快速響應;

    5、第三方服務隔離性:任何依賴於第三方的服務(不論接口還是中間件等),都應該做到熔斷和降級,不能有強耦合的依賴;

    6、業務場景兜底方案:核心業務場景需要做到完整的兜底方法,從前端到後端都應該有兜底措施;

    7、服務監控與及時響應:每個服務應該做好對應的監控工作,如有異常應及時響應,不應累積。

     

    三、集群穩定性

    關鍵字:系統架構、部署發布、限流熔斷、監控體系、壓測機制!

    對於集群維度的穩定性來說,穩定性保障會更加複雜。單服務是局部,集群是全局。一個見微知著,一個高瞻遠矚。

    1、合理的系統架構:合理的系統架構是穩定的基石;

    2、小心的代碼邏輯:代碼時刻都要小心,多擔心一點這裡會不會有性能問題,那裡會不會出現併發,代碼就不會有多少問題;

    3、優秀的集群部署:一台機器永遠會有性能瓶頸,優秀的集群部署,可以將一台機器的穩定放大無限倍,是高併發與大流量的保障;

    4、科學的限流熔斷:高併發來臨時,科學的限流和熔斷是系統穩定的必要條件;

    5、精細的監控體系:沒有監控體系,你永遠不會知道你的系統到底有多少隱藏的問題和坑,也很難知道瓶頸在哪裡;

    6、強悍的壓測機制:壓測是高併發穩定性的試金石,能提前預知高併發來臨時,系統應該出現的模樣;

    7、膽小的開發人員:永遠需要一群膽小的程序員,他們討厭bug,害怕error,不放過每一個波動,不信任所有的依賴。

     

    四、穩定性專項

    專項指的是針對某些特定場景下的特定問題而梳理出對應的方案。下面是針對一些常見的穩定性專項的概述:

    1、預案:分為定時預案和緊急預案,定時預案是大促常規操作對於一系列開關的編排,緊急預案是應對突發情況的特殊處理,都依賴於事前梳理;

    2、預熱:分為JIT代碼預熱和數據預熱,阿里內部有專門的一個產品負責這塊,通過存儲線上的常態化流量或者熱點流量進行回放來提前預熱,

      起源於某年雙十一零點的毛刺問題,原因是訪問了數據庫的冷數據rt增高導致的一系列上層限流,現在預熱已經成了大促之前的一個必要流程。

    3、強弱依賴:梳理強弱依賴是一個偏人肉的過程,但是非常重要,這是一個系統自查識別潛在風險點併為後續整理開關限流預案和根因分析的一個重要參考,

      阿里內部有一個強弱依賴檢測的平台,通過對測試用例注入RPC調用的延遲或異常來觀察鏈路的依賴變化,自動梳理出強弱依賴關係。

    4、限流降級熔斷:應對突發流量防止請求超出自身處理能力系統被擊垮的必要手段;

    5、監控告警&鏈路追蹤:監控分為業務監控、系統監控和中間件監控和基礎監控,作為線上問題發現和排查工具,重要性不言而喻。

     

    五、穩定性建設

    穩定性建設,就和基礎技術建設一樣,是一個長期迭代和不斷調整的過程,業內常見的穩定性建設類型,主要有如下幾種:

    1、容量規劃:個人感覺容量規劃在大廠里也並沒有做的很好,更多依賴的是業務方自己拍腦袋,然後全鏈路壓測期間驗證,不夠就再加機器。

    2、混沌工程:混沌工程是近幾年比較火的名詞,通過不斷給系統找麻煩來驗證並完善系統能力,阿里在這塊花了很大的精力建設紅藍軍對抗攻防,進行定期和不定期的演練,

      最後以打分的形式來給各個部門系統做排名,除了系統層面的故障演練外還有資金演練,篡改線上sql語句製造資損來測試業務監控糾錯的能力,通過製造小錯來避免大錯。

      跳轉門:混沌工程-初識

    3、流量調度:通過metric秒級監控和聚類算法實時找出異常單機來降低RPC流量權重,提升集群整體吞吐能力減少異常請求。

    4、容災&異地多活:起源於15年某施工隊將光纖挖斷帶來的支付寶故障,由此出來的三地五中心和單元化架構,異地多活本身的成本比較高,

      然後又存在數據同步的延時問題和切流帶來的臟數據問題,對於業務和技術都有比較高的要求。常見的容災有如下幾種:

      1)緩存掛掉,集群重啟緩存預熱如何處理?本地緩存,多級緩存是否可以替代?

      2)分佈式鎖,是否有開關一鍵切換?比如:ZK/ETCD編寫的分佈式鎖;

      3)大促峰值流量,如何防止外部ddos攻擊?如何識別流量類型?

      4)資源隔離:資源隔離,服務分組,流量隔離;

      5)高可用思想:避免單點設計!

      6)容錯:容錯上游,防禦下游。容錯主要需要注意如下幾點:

         6-1:外部依賴的地方都要做熔斷,避免雪崩;

         6-2:對於依賴我們的上游要限流,防止上游突發流量超過自己系統能夠扛住的最大QPS;

         6-3:對於下游既要評估好接口超時時間,防止下游接口超時異常導致自己系統被拖累;

         6-4:下游的接口要考慮各種異常情況,需要考慮中間狀態,通過引入柔性事務,確保數據最終一致。

    5、異地多活

    異地多活的本質,是數據中心架構的演進

    1)演進:單機房——雙機房——異地災備——異地多活;

    2)定義:分多個地域、多個數據中心運行線上的業務,並且每個IDC均提供在線服務;

    3)優點:彈性擴展能力、流量就近接入、靈活調度、提升可用性與用戶體驗、容災;

    4)步驟

      4-1:基礎設施:機房之間專線互聯,保證網絡質量穩定;

      4-2:持久存儲:一主三從,主IDC同步複製,異地IDC異步複製;

      4-3:中間件:DB、MQ、分佈式存儲;

      4-4:應用部署:根據應用域劃分,不同應用部署在不同地域,保持親緣性;

      4-5:流量接入與調度:網絡協議兼容,DNS,動態調度用戶就近訪問;

      4-6:監控與運維保障:專線實時監控,確保發生故障時可以觸發Failover(失效備援)和流量調度。

     

    六、穩定性思考

    關鍵字:階段工作、角色轉變!

    穩定性建設是一個演進的階段性過程,主要分為三個階段:

    1、發現問題解決問題:當問題較多時候就很被動,很多時候我們通過不斷完善監控來確保我們來快速定位問題,但仍處於被動的一方;

    2、主動尋找問題:混沌工程、破壞性測試、極限壓測、紅藍對抗等手段,一方作為創造問題方不斷挑戰系統極限,另一方見招拆招快速修復。

    3、角色轉變:這個過程中會積累很多處理問題的經驗,不斷完善系統健壯性,爭取在用戶發現問題前消滅於萌芽中。角色轉變,變被動為主動。

     

    七、推薦閱讀

    聊聊服務災備

    大促穩定性建設

    運維監控體系建設

    這樣的高可用,我不要

    高併發限流,到底限的什麼鬼

    新浪微博平台穩定性體系介紹

    StabilityGuide—穩定大於一切

    沒有預熱,不叫高併發,叫併發高

    信號量限流,高併發限流不得不說的秘密

     

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

    【其他文章推薦】

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

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

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

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

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

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