分類: 3C資訊

  • BMW i3 在美銷量 首度超越 Tesla Model S

    BMW i3 在美銷量 首度超越 Tesla Model S

     

    BMW i3 純電動汽車今年 8 月在美銷量為 1,025 輛,首次超過特斯拉 Model S,後者 8 月銷量僅為 600 輛。

    寶馬 i3 純電動車型在美國市場已上市 3 個月,之前由於寶馬內部的運轉效率問題,其銷量一直低於特斯拉 Model S。但該問題解決後,寶馬 i3 的銷量也迎頭趕上。特斯拉 8 月整體需求較去年同期下降 54%,7 月更是下降了 72%。與 2013 年同期相比,特斯拉今年上半年銷量下降了 26%。

    專家稱,特斯拉目前正處發展壯大的階段,而寶馬在歐洲和亞洲市場則以紮穩腳跟。在產品創新度、更新速度及售價方面,特斯拉 Model S 的優勢愈來愈不明顯,而隨著寶馬 i3 的銷量逐步上升,預計歐洲將會成為其最大銷售市場。

     

    (圖片來源:)

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

    【其他文章推薦】

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

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

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

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

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

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

  • 看準中國市場 LG 化學在南京建電動車電池工廠

    韓國 LG 化學今(10)日表示,2015 年將在中國建電動車電池工廠,此舉是在押注身為全球最大汽車市場的中國需求將持續增加。

    LG 化學稱,這座工廠設在中國南京,將滿足上汽集團等中國汽車製造商和通用汽車 (GM) 等全球性企業的需求,工廠耗資數億美元,預計 2020 年綜合營收將達到 1 兆韓元 ( 約 9.899 億美元)。

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

    【其他文章推薦】

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

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

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

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

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

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

  • 雷諾與法國富豪攜手 搶進電動車市場

    法國雷諾集團(Renault SA)與法國富豪波洛黑(Vincent Bollore)決定合作,共同製造電動車,瞄準零排放汽車日益強勁的需求,及正於各地興起的環保汽車租用潮流。   雷諾汽車將於 2015 下半年開始生產波洛黑的電動車款「藍車(Bluecar)」,但並未透露生產目標。該車款自 2011 年起,被使用於巴黎名為「Autolib」的電動車租賃共享計畫中,此計畫同時也於里昂及波爾多等地運行。   此外,雷諾汽車與波洛黑亦宣布,將成立一策略聯盟,其中波洛黑擁有 70% 股權,雷諾股權則達 30%。該聯盟將於法國及歐洲其他地方提供車輛共享服務。另外並進行研究,以協助雷諾製造一款 3 人座、使用波洛黑所生產電池的電動車。

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

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

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

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

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

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

    ※回頭車貨運收費標準

  • 日產瞄準中國電動車市場 目標拿下 20% 市占

    日產瞄準中國電動車市場 目標拿下 20% 市占

      日本汽車大廠日產汽車(Nissan)10 日宣佈,旗下中國大陸合資公司東風汽車有限公司的乘用車部門「東風日產乘用車公司(以下稱東風日產)」自 10 日起將在大陸開賣東風日產自有品牌電動車「Venucia e30」,售價為 26 萬 7,800 元人民幣,目標為在 2018 年於中國電動車市場拿下 20% 市佔率。   Venucia e30 是以日產於 2010 年在日本開賣的電動車「Leaf」的車台、技術為根基,由日產與東風日產所攜手研發的車款,而日產也將成為第一家進軍中國電動車市場的日系車廠。   Venucia e30 初期將在北京、上海、廣州、深圳、大連、武漢、天津、鄭州和杭洲等 9 個都市販售,並計劃在 2015 年將販售區域擴及至中國全國。   據日本媒體共同通信指出,Venucia e30 約 4 小時可充飽電、充飽電狀態下的行駛距離為 175km;Venucia e30 將在廣州生產、2018 年銷售目標為 5 萬台。     (圖片來源:)

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • F-立凱公布 8 月營收 續創新高

    9 月 1 日甫與日本電池技術領導者索尼簽署電動車鋰電池合作備忘錄的 F-立凱,公布 8 月單月合併營收為 9700 萬元,年增 92.4%,月增 16.4%。繼 7 月營收增長 64.7%,8 月營收續創歷史新高。受惠於兩岸挺進新能源車推動的政策方向確定,新能源車及儲能市場需求旺盛,推動電池正極材料銷售上揚。   立凱電是國內電動巴士系統與磷酸鐵鋰電池正極材料龍頭,該公司表示,下半年客戶需求強勁,產能滿載,看好未來車用電池與儲能電池及 4G 基地台之終端應用成長,立凱電材料歷年累積銷量已達 4700 噸。

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

    【其他文章推薦】

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

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

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

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

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

  • Jmeter系列(31)- 獲取並使用 JDBC Request 返回的數據

    Jmeter系列(31)- 獲取並使用 JDBC Request 返回的數據

    如果你想從頭學習Jmeter,可以看看這個系列的文章哦

    https://www.cnblogs.com/poloyy/category/1746599.html

     

    前言

    • Jmeter 使用 JDBC Request 獲取數據庫中數據,很多人都會用,因為測試中,有時候需要大量的用戶進行登錄,然後獲取數據庫中真實的數據用於測試
    • 前面也詳細講到 JDBC Request 的具體使用,一般是通過 Variable names 和 Result variable name 來獲取返回的數據
    • 這篇文章主要講的就是把 Variable names 和 Result variable name 獲取到的數據提取出來,給到 HTTP 請求使用

     

    Variable names + Foreach控制器

    線程組結構樹

     

    JDBC Request

     

    調試取樣器運行結果

    有 100 條記錄

     

    ForEach控制器

     

    循環運行的結果( mobile:${mobile} )

     

    Variable names + 循環控制器

    和上面的栗子只是換了個控制器而已,沒太大變化

    線程組結構樹

     

    循環控制器

    填寫 100,是代表循環100次

     

    計數器

    從 1 開始,遞增加到 100為止,每次遞增 1

    • 初始值=1
    • 每次增加 1
    • 最大的值=100(包含)
    • 新變量 num

     

    循環控制器內的 Debug Sampler

     ${__V()} 是關聯函數,後面講到

     

    循環運行的結果( mobile:${mobile} )

     

    Result variable name + Foreach控制器

    線程組結構樹

     

    JDBC Request

     

    正則提取器

     

    重點

    Applu to 選中 Jmeter Variable Name to use,因為要從 Jmeter Variables 中拿到 result_mobile 變量進行提取

     

    調試取樣器運行結果

    正則提取后的值是不是跟上面 Variable names 獲取的值列表很像,是的!然後再結合 ForEach控制器就好啦

     

    ForEach控制器

    變量前綴是正則提取器里的引用名稱

     

    循環運行的結果( mobile:${mobile} )

     

    Result variable name + 循環控制器

    和上面的栗子只是換了個控制器而已,沒太大變化

    線程組結構樹

     

    循環控制器

    填寫 100,是代表循環100次

     

    計數器

     

    用戶參數

    重點一

    •  ${__BeanShell(vars.getObject(“result_mobile”).get(${num}).get(“mobile”))} 
    •  ${__BeanShell()} :執行BeanShell腳本,一般比較短的腳本可以用此方法來寫,後面會再詳細講解這個函數

    重點二

    •  vars.getObject(“result_mobile”).get(${num}).get(“mobile”) 
    • result_mobile:是一個數組,即 JDBC Request 里的 Result variable name,每個元素的格式都是 {mobile=158000480001} 
    • ${num}:上面計數器的值,每次遞增 1,這裡是數組下標的意思
    • 總結:獲取 result_mobile 數組,每次取數組中第 num 個元素,從元素中取 mobile 鍵的值【這是固定寫法,只改Object 名、鍵名就行了】

     

    循環運行的結果( mobile:${user_mobile} )

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

    【其他文章推薦】

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

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

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

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

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

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

  • ASP.NET Core Blazor Webassembly 之 漸進式應用(PWA)

    ASP.NET Core Blazor Webassembly 之 漸進式應用(PWA)

    Blazor支持漸進式應用開發也就是PWA。使用PWA模式可以使得web應用有原生應用般的體驗。

    什麼是PWA

    PWA應用是指那些使用指定技術和標準模式來開發的web應用,這將同時賦予它們web應用和原生應用的特性。
    例如,web應用更加易於發現——相比於安裝應用,訪問一個網站顯然更加容易和迅速,並且你可以通過一個鏈接來分享web應用。
    在另一方面,原生應用與操作系統可以更加完美的整合,也因此為用戶提供了無縫的用戶體驗。你可以通過安裝應用使得它在離線的狀態下也可以運行,並且相較於使用瀏覽器訪問,用戶也更喜歡通過點擊主頁上的圖標來訪問它們喜愛的應用。
    PWA賦予了我們創建同時擁有以上兩種優勢的應用的能力。
    這並不是一個新概念——這樣的想法在過去已經在web平台上通過許多方法出現了多次。漸進式增強和響應式設計已經可以讓我們構建對移動端友好的網站。在多年以前的Firefox OS的生態系統中離線運行和安裝web應用已經成為了可能。
    PWAs, 不但如此,更是提供了所有的甚至是更多的特性,來讓web更加優秀。

    引用自MDN

    說人話就是PWA可以讓你的web程序跟一般應用一樣運行,有桌面圖標,能離線,沒有瀏覽器地址欄,一切看起來想個普通的程序/APP。

    新建Blazor PWA程序

    使用VS新建一個Blazor程序,選擇Webassembly模式,勾選支持PWA。

    支持PWA的Blazor程序主要是多了幾個東西:

    1. manifest.json
    2. service-worker.js

    manifest.json

    manifest.json是個清單文件,當程序被安裝到設備上的時候會讀取裏面的信息,名稱是什麼,圖標是什麼,什麼語言等等。

    {
      "name": "BlazorPWA",
      "short_name": "BlazorPWA",
      "start_url": "./",
      "display": "standalone",
      "background_color": "#ffffff",
      "theme_color": "#03173d",
      "icons": [
        {
          "src": "icon-512.png",
          "type": "image/png",
          "sizes": "512x512"
        }
      ]
    }
    
    

    service-worker.js

    service-worker用來跑一些後台任務。它跟瀏覽器主進程是隔離的,也就是說跟原來的JavaScript運行時是分開,當然了它不會阻塞頁面。我們可以用它來完成一些功能,比如對所有的fetch/xhr請求進行過濾,哪些請求走緩存,哪些不走緩存;比如在後台偷偷給你拉一些數據緩存起來。

    // Caution! Be sure you understand the caveats before publishing an application with
    // offline support. See https://aka.ms/blazor-offline-considerations
    
    self.importScripts('./service-worker-assets.js');
    self.addEventListener('install', event => event.waitUntil(onInstall(event)));
    self.addEventListener('activate', event => event.waitUntil(onActivate(event)));
    self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
    
    const cacheNamePrefix = 'offline-cache-';
    const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
    const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/ ];
    const offlineAssetsExclude = [ /^service-worker\.js$/ ];
    
    async function onInstall(event) {
        console.info('Service worker: Install');
    
        // Fetch and cache all matching items from the assets manifest
        const assetsRequests = self.assetsManifest.assets
            .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))
            .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))
            .map(asset => new Request(asset.url, { integrity: asset.hash }));
        await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));
    }
    
    async function onActivate(event) {
        console.info('Service worker: Activate');
    
        // Delete unused caches
        const cacheKeys = await caches.keys();
        await Promise.all(cacheKeys
            .filter(key => key.startsWith(cacheNamePrefix) && key !== cacheName)
            .map(key => caches.delete(key)));
    }
    
    async function onFetch(event) {
        let cachedResponse = null;
        if (event.request.method === 'GET') {
            // For all navigation requests, try to serve index.html from cache
            // If you need some URLs to be server-rendered, edit the following check to exclude those URLs
            const shouldServeIndexHtml = event.request.mode === 'navigate';
    
            const request = shouldServeIndexHtml ? 'index.html' : event.request;
            const cache = await caches.open(cacheName);
            cachedResponse = await cache.match(request);
        }
    
        return cachedResponse || fetch(event.request);
    }
    
    

    項目里有2個service-worker.js文件,一個是開發時候的沒邏輯,還有一個是發布時候的有一些緩存的邏輯。

    運行一下

    如果是PWA程序,在瀏覽器地址欄有個+號一樣的圖標,點擊可以把程序安裝到本地。

    安裝完了會在桌面生成一個圖標,打開會是一個沒有瀏覽器地址欄的界面。

    這樣一個PWA程序已經可以運行了。

    離線運行

    如果只是這樣,僅僅是沒有瀏覽器地址欄,那PWA也太沒什麼吸引力了。個人覺得PWA最大的魅力就是可以離線運行,在沒有網絡的情況下依然可以運行,這樣才像一個原生編寫的程序。

    修改service-worker

    離線的原理也很簡單,就是請求的數據都緩存起來,一般是緩存Get請求,比如各種頁面圖片等。

    // In development, always fetch from the network and do not enable offline support.
    // This is because caching would make development more difficult (changes would not
    // be reflected on the first load after each change).
    
    self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
    self.addEventListener('install', event => event.waitUntil(onInstall(event)));
    
    async function onInstall(event) {
        console.info('Service worker: Install');
    }
    
    
    async function onFetch(event) {
        let cachedResponse = null;
        const cache = await caches.open('blazor_pwa');
        if (event.request.method === 'GET') {
            const request = event.request;
            cachedResponse = await caches.match(request);
            if (cachedResponse) {
                return cachedResponse;
            }
            var resp = await fetch(event.request)
            cache.put(event.request, resp.clone());
            return resp;
        }
    
        return fetch(event.request);
    }
    

    修改一下sevice-worker.js,把GET請求全部緩存起來。這裏為了演示圖方便,其實情況顯然不會這麼簡單粗暴。為了能緩存頁面,顯然必須先在線運行成功一次。

    模擬離線

    當我們修改完上面的js,然後在線正常一次后,可以看到所有GET請求的資源都被緩存起來了。

    我們可以用chrome來模擬離線情況:

    選擇offline模式,然後刷新我們的頁面,如果依然可以正常運行則表示可以離線運行。

    總結

    使用Blazor可以快速的開發PWA應用。利用PWA跟Blazor Webassembly的特性,可以開發出類似桌面的應用程序。或許這是跨平台桌面應用開發除了electron的又一種方案吧。

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

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

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

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

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

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

    ※回頭車貨運收費標準

  • 使用Kubernetes、K3s和Traefik2進行本地開發

    使用Kubernetes、K3s和Traefik2進行本地開發

    作者簡介

    Vyacheslav,擁有運維和項目管理經驗的軟件工程師

    這篇文章將承接我此前搭建的本地Docker開發環境,具體步驟已經放在在以下網址:

    https://github.com/Voronenko/traefik2-compose-template

    除了經典的docker化的項目之外,我還有其他的Kubernetes項目。儘管Kubernetes已經成為容器編排的事實標準,但是不得不承認Kubernetes是一個既消耗資源又消耗金錢的平台。由於我並不經常需要外部集群,因此我使用輕量級K3s發行版來進行Kubernetes本地開發。

    K3s是為IoT和邊緣計算而構建的經過認證的Kubernetes發行版之一,還能夠按產品規模部署到VM。

    我使用K3s的方式是這樣的:在我的工作筆記本上本地安裝K3s,儘管有時我需要在本地部署較重的測試工作負載,為此,我準備了兩個神器——兩個運行ESXi的外部Intel NUCs。

    默認情況下,K3s安裝Traefik 1.x作為ingress,如果你對此十分滿意,那麼無需往下繼續閱讀了。

    在我的場景中,我同時會牽涉到好幾個項目,特別是經典的docker和docker swarm,因此我經常遇到在獨立模式下部署Traefik的情況。

    因此,本文其餘部分將深入介紹如何將外部traefik2配置為K3s集群的ingress。

    安裝Kubernetes K3s系列集群

    你可以按照常規方式使用命令curl -sfL https://get.k3s.io | sh -安裝K3s,或者你可以使用輕量實用程序k3sup安裝(https://github.com/alexellis/k3sup)。具體步驟在之前的文章介紹過。

    與我們的設置不同的是,我們使用命令--no-deploy traefik專門安裝了不帶traefik組件的K3s。

    export CLUSTER_MASTER=192.168.3.100
    export CLUSTER_DEPLOY_USER=slavko
    k3sup install --ip $CLUSTER_MASTER --user $CLUSTER_DEPLOY_USER --k3s-extra-args '--no-deploy traefik'
    

    執行后,你將獲得使用kubectl所需的連接詳細信息。安裝K3s后,你可以快速檢查是否可以看到節點。

    # Test your cluster with - export path to k3s cluster kubeconfig:
    export KUBECONFIG=/home/slavko/kubeconfig
    kubectl get node -o wide
    

    注:這裏沒有固定的安裝模式,你甚至可以使用docker-compose自行啟動它。

    server:
      image: rancher/k3s:v0.8.0
      command: server --disable-agent --no-deploy traefik
      environment:
        - K3S_CLUSTER_SECRET=somethingtotallyrandom
        - K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml
        - K3S_KUBECONFIG_MODE=666
      volumes:
        # k3s will generate a kubeconfig.yaml in this directory. This volume is mounted
        # on your host, so you can then 'export KUBECONFIG=/somewhere/on/your/host/out/kubeconfig.yaml',
        # in order for your kubectl commands to work.
        - /somewhere/on/your/host/out:/output
        # This directory is where you put all the (yaml) configuration files of
        # the Kubernetes resources.
        - /somewhere/on/your/host/in:/var/lib/rancher/k3s/server/manifests
      ports:
        - 6443:6443
    
    node:
      image: rancher/k3s:v0.8.0
      privileged: true
      links:
        - server
      environment:
        - K3S_URL=https://server:6443
        - K3S_CLUSTER_SECRET=somethingtotallyrandom
      volumes:
        # this is where you would place a alternative traefik image (saved as a .tar file with
        # 'docker save'), if you want to use it, instead of the traefik:v2.0 image.
        - /sowewhere/on/your/host/custom-image:/var/lib/rancher/k3s/agent/images
    

    配置Traefik 2,與Kubernetes一起使用

    在文章開頭提到的鏈接中,我已經在我的系統中安裝了Traefik 2,並根據該鏈接內容,服務於一些需求。現在是時候配置Traefik 2 Kubernetes後端了。

    Traefik 2使用CRD(自定義資源定義)來完成這一點。定義的最新示例可以在以下鏈接中找到,但這些示例僅適用於Traefik 2也作為Kubernetes工作負載的一部分執行的情況:

    https://docs.traefik.io/reference/dynamic-configuration/kubernetes-crd/

    對於外部Traefik 2,我們僅需要以下描述的定義子集。

    我們引入一系列自定義資源定義,以允許我們來描述我們的Kubernetes服務將會如何暴露到外部,traefik-crd.yaml

    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: ingressroutes.traefik.containo.us
    
    spec:
      group: traefik.containo.us
      version: v1alpha1
      names:
        kind: IngressRoute
        plural: ingressroutes
        singular: ingressroute
      scope: Namespaced
    
    ---
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: ingressroutetcps.traefik.containo.us
    
    spec:
      group: traefik.containo.us
      version: v1alpha1
      names:
        kind: IngressRouteTCP
        plural: ingressroutetcps
        singular: ingressroutetcp
      scope: Namespaced
    
    ---
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: middlewares.traefik.containo.us
    
    spec:
      group: traefik.containo.us
      version: v1alpha1
      names:
        kind: Middleware
        plural: middlewares
        singular: middleware
      scope: Namespaced
    
    ---
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: tlsoptions.traefik.containo.us
    
    spec:
      group: traefik.containo.us
      version: v1alpha1
      names:
        kind: TLSOption
        plural: tlsoptions
        singular: tlsoption
      scope: Namespaced
    
    ---
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: traefikservices.traefik.containo.us
    
    spec:
      group: traefik.containo.us
      version: v1alpha1
      names:
        kind: TraefikService
        plural: traefikservices
        singular: traefikservice
      scope: Namespaced  
    

    同時,我們需要集群角色traefik-ingress-controller,以提供對服務、端點和secret的只讀訪問權限以及自定義的traefik.containo.us組,traefik-clusterrole.yaml

    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1beta1
    metadata:
      name: traefik-ingress-controller
    
    rules:
      - apiGroups:
          - ""
        resources:
          - services
          - endpoints
          - secrets
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - extensions
        resources:
          - ingresses
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - extensions
        resources:
          - ingresses/status
        verbs:
          - update
      - apiGroups:
          - traefik.containo.us
        resources:
          - middlewares
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - traefik.containo.us
        resources:
          - ingressroutes
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - traefik.containo.us
        resources:
          - ingressroutetcps
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - traefik.containo.us
        resources:
          - tlsoptions
        verbs:
          - get
          - list
          - watch
      - apiGroups:
          - traefik.containo.us
        resources:
          - traefikservices
        verbs:
          - get
          - list
          - watch
    

    最後,我們需要系統服務賬號traefik-ingress-controller與之前創建的集群角色traefik-ingress-controller相關聯。

    ---
    kind: ServiceAccount
    apiVersion: v1
    metadata:
      namespace: kube-system
      name: traefik-ingress-controller
    
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1beta1
    metadata:
      name: traefik-ingress-controller
    
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: traefik-ingress-controller
    subjects:
      - kind: ServiceAccount
        name: traefik-ingress-controller
        namespace: kube-system
    

    我們應用以上資源之後:

    apply:
      kubectl apply -f traefik-crd.yaml
      kubectl apply -f traefik-clusterrole.yaml
      kubectl apply -f traefik-service-account.yaml
    

    我們已經準備好開始調整Traefik 2

    將Traefik 2指向K3s集群

    根據Traefik文檔的建議,當Traefik部署到Kubernetes中時,它將讀取環境變量KUBERNETES_SERVICE_HOST和KUBERNETES_SERVICE_PORT或KUBECONFIG來構造端點。

    /var/run/secrets/kubernetes.io/serviceaccount/token中查找訪問token,而SSL CA證書將在/var/run/secrets/kubernetes.io/serviceaccount/ca.crt.中查找。當部署到Kubernetes內部時,兩者都會自動提供掛載。

    當無法找到環境變量時,Traefik會嘗試使用external-cluster客戶端連接到Kubernetes API server。這一情況下,需要設置endpoint。具體來說,可以將其設置為kubectl代理使用的URL,以使用相關的kubeconfig授予的身份驗證和授權連接到Kubernetes集群。

    Traefik 2可以使用任何受支持的配置類型來靜態配置-toml、yaml或命令行交換。

    [providers.kubernetesCRD]
      endpoint = "http://localhost:8080"
      token = "mytoken"
    
    providers:
      kubernetesCRD:
        endpoint = "http://localhost:8080"
        token = "mytoken"
        # ...
    
    --providers.kubernetescrd.endpoint=http://localhost:8080 
    --providers.kubernetescrd.token=mytoken
    

    第一次運行時,如果你在外部有Traefik,很有可能沒有traefik-ingress-controller訪問token來指定mytoken。那麼,你需要執行以下命令:

    # Check all possible clusters, as your .KUBECONFIG may have multiple contexts:
    kubectl config view -o jsonpath='{"Cluster name\tServer\n"}{range .clusters[*]}{.name}{"\t"}{.cluster.server}{"\n"}{end}'
    
    # Output kind of
    # Alias tip: k config view -o jsonpath='{"Cluster name\tServer\n"}{range .clusters[*]}{.name}{"\t"}{.cluster.server}{"\n"}{end}'
    # Cluster name  Server
    # default  https://127.0.0.1:6443
    
    # You are interested in: "default", if you did not name it differently
    
    # Select name of cluster you want to interact with from above output:
    export CLUSTER_NAME="default"
    
    # Point to the API server referring the cluster name
    export APISERVER=$(kubectl config view -o jsonpath="{.clusters[?(@.name==\"$CLUSTER_NAME\")].cluster.server}")
    # usually https://127.0.0.1:6443
    
    # Gets the token value
    export TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='traefik-ingress-controller')].data.token}" --namespace kube-system|base64 --decode)
    
    # Explore the API with TOKEN
    

    如果成功了,你應該收到以下響應:

    {
      "kind": "APIVersions",
      "versions": [
        "v1"
      ],
      "serverAddressByClientCIDRs": [
        {
          "clientCIDR": "0.0.0.0/0",
          "serverAddress": "192.168.3.100:6443"
        }
      ]
    

    以及一些事實,如token:

    eyJhbGciOiJSUzI1NiIsImtpZCI6IjBUeTQyNm5nakVWbW5PaTRRbDhucGlPeWhlTHhxTXZjUDJsRmNacURjVnMifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJ0cmFlZmlrLWluZ3Jlc3MtY29udHJvbGxlci10b2tlbi12emM3diIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ0cmFlZmlrLWluZ3Jlc3MtY29udHJvbGxlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImQ5NTc3ZTkxLTdlNjQtNGMwNi1iZDgyLWNkZTk0OWM4MTI1MSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTp0cmFlZmlrLWluZ3Jlc3MtY29udHJvbGxlciJ9.Mk8EBS4soO8uX-uSnV3o4qZKR6Iw6bgeSmPhHbJ2fjuqFgLnLh4ggxa-N9AqmCsEWiYjSi5oKAu986UEC-_kGQh3xaCYsUwlkM8147fsnwCbomSeGIct14JztVL9F8JwoDH6T0BOEjn-J9uY8-fUKYL_Y7uTrilhFapuILPsj_bFfgIeOOapRD0XshKBQV9Qzg8URxyQyfzl68ilm1Q13h3jLj8CFE2RlgEUFk8TqYH4T4fhfpvV-gNdmKJGODsJDI1hOuWUtBaH_ce9w6woC9K88O3FLKVi7fbvlDFrFoJ2iVZbrRALPjoFN92VA7a6R3pXUbKebTI3aUJiXyfXRQ
    

    根據上次響應的API server的外部地址:https://192.168.3.100:6443

    同樣,提供的token中沒有任何特殊之處:這是JWT的token,你可以使用https://jwt.io/#debugger-io,檢查它的內容。

    {
      "alg": "RS256",
      "kid": "0Ty426ngjEVmnOi4Ql8npiOyheLxqMvcP2lFcZqDcVs"
    }
    {
      "iss": "kubernetes/serviceaccount",
      "kubernetes.io/serviceaccount/namespace": "kube-system",
      "kubernetes.io/serviceaccount/secret.name": "traefik-ingress-controller-token-vzc7v",
      "kubernetes.io/serviceaccount/service-account.name": "traefik-ingress-controller",
      "kubernetes.io/serviceaccount/service-account.uid": "d9577e91-7e64-4c06-bd82-cde949c81251",
      "sub": "system:serviceaccount:kube-system:traefik-ingress-controller"
    }
    

    正確的配置非常重要,因此請確保對APISERVER的兩個調用均返回合理的響應。

    export APISERVER=YOURAPISERVER
    export TOKEN=YOURTOKEN
    
    curl -X GET $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
    
    curl -X GET $APISERVER/api/v1/endpoints --header "Authorization: Bearer $TOKEN" --insecure
    

    創建其他訪問token

    控制器循環確保每個服務賬戶都有一個帶有API token的secret,可以像我們之前那樣被發現。

    此外,你還可以為一個服務賬戶創建額外的token,創建一個ServiceAccountToken類型的secret,併為服務賬戶添加一個註釋,控制器會用生成的token來更新它。

    ---
    apiVersion: v1
    kind: Secret
    namespace: kube-system
    metadata:
      name: traefik-manual-token
      annotations:
        kubernetes.io/service-account.name: traefik-ingress-controller
    type: kubernetes.io/service-account-token
    
    # Any tokens for non-existent service accounts will be cleaned up by the token controller.
    
    # kubectl describe secrets/traefik-manual-token
    

    用以下命令創建:

    kubectl create -f ./traefik-service-account-secret.yaml
    kubectl describe secret traefik-manual-token
    

    刪除/無效:

    kubectl delete secret traefik-manual-token
    

    對外部traefik 2的更改構成定義

    我們需要在文章開頭給出的鏈接中獲得的traefik2配置進行哪些更改?

    https://github.com/Voronenko/traefik2-compose-template

    a) 我們在新文件夾kubernetes_data中存儲ca.crt文件,該文件用於驗證對Kubernetes授權的調用。這是可以在kubeconfig文件的clusters-> cluster-> certificate-authority-data下找到的證書。

    該volume將映射在/var/run/secrets/kubernetes.io/serviceaccount下以獲取官方Traefik 2鏡像

    volumes:
        ...
          - ./kubernetes_data:/var/run/secrets/kubernetes.io/serviceaccount
    

    b) 調整Traefik 2 kubernetescrd後端以提供3個參數:endpoint、證書路徑和token。請注意,作為外部Traefik作為docker容器,你需要指定正確的endpoint地址,並確保以安全的方式進行。

      - "--providers.kubernetescrd=true"
          - "--providers.kubernetescrd.endpoint=https://192.168.3.100:6443"
          - "--providers.kubernetescrd.certauthfilepath=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
          - "--providers.kubernetescrd.token=YOURTOKENWITHOUTANYQUOTES
    

    如果你都執行正確了,那麼你現在應該在Traefik UI上看到了一些希望。如果你沒有看到traefik,或者在運行Traefik時有問題,你可以查看之後的故障排除部分。

    現在是時候通過Trafik 2暴露一些Kubernetes服務了,以確保Traefik 2能夠作為ingress工作。讓我們來看經典案例whoami服務,whoami-service.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: whoami
    
    spec:
      ports:
        - protocol: TCP
          name: web
          port: 80
      selector:
        app: whoami
    
    ---
    kind: Deployment
    apiVersion: apps/v1
    metadata:
      namespace: default
      name: whoami
      labels:
        app: whoami
    
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: whoami
      template:
        metadata:
          labels:
            app: whoami
        spec:
          containers:
            - name: whoami
              image: containous/whoami
              ports:
                - name: web
                  containerPort: 80
    
    

    並且以http或https的方式暴露它,whoami.k.voronenko.net全限定域名下的whoami-ingress-route.yaml

    apiVersion: traefik.containo.us/v1alpha1
    kind: IngressRoute
    metadata:
      name: ingressroute-notls
      namespace: default
    spec:
      entryPoints:
        - web
      routes:
        - match: Host(`whoami.k.voronenko.net`)
          kind: Rule
          services:
            - name: whoami
              port: 80
    
    ---
    apiVersion: traefik.containo.us/v1alpha1
    kind: IngressRoute
    metadata:
      name: ingressroute-tls
      namespace: default
    spec:
      entryPoints:
        - websecure
      routes:
        - match: Host(`whoami.k.voronenko.net`)
          kind: Rule
          services:
            - name: whoami
              port: 80
      tls:
        certResolver: default
    

    然後應用它:

    kubectl apply -f whoami-service.yaml
      kubectl apply -f whoami-ingress-route.yaml
    

    應用后,你應該會在Traefik dashboard上看到一些希望,即KubernetesCRD後端。

    正如你所看到的,Traefik已經檢測到我們的K3s Kubernetes集群上運行的新工作負載,而且它與我們在同一個盒子上的經典Docker工作負載(如portainer)很好地共存。

    讓我們檢查一下Traefik 2是否將Traefik路由到了我們的Kubernetes工作負載:如你所見,你可以在http和https endpoint上成功地接觸到whoami工作負載,瀏覽器接受你的證書為可信任的“綠標籤”。

    我們的目標達到了!我們在本地筆記本上配置了Traefik 2。Traefik 2將你的docker或Kubernetes工作流暴露在http或https endpoint上。帶可選的 letsencrypt 的 Traefik 2 將負責 https。

    故障排查

    正如你所知,在配置過程可能存在多個問題,你可以考慮使用一些分析工具,如:

    https://github.com/Voronenko/dotfiles/blob/master/Makefile#L185

    我特別建議:

    a) VMWare octant:這是一個基於Web的功能強大的Kubernetes dashboard,你可以在上面使用你的kubeconfig

    b) Rakess:這是一個獨立工具也是一個kubectl插件,用於显示Kubernetes服務器資源的訪問矩陣(https://github.com/corneliusweig/rakkess)

    檢查系統賬戶的憑據

    rakkess --sa kube-system:traefik-ingress-controller
    

    c) kubectl

    檢查哪些角色與服務賬戶相關聯

    kubectl get clusterrolebindings -o json | jq -r '
      .items[] |
      select(
        .subjects // [] | .[] |
        [.kind,.namespace,.name] == ["ServiceAccount","kube-system","traefik-ingress-controller"]
      ) |
      .metadata.name'
    

    d) Traefik 文檔:例如kubernetescrd後端提供了更多配置開關的方式。

    --providers.kubernetescrd  (Default: "false")
            Enable Kubernetes backend with default settings.
        --providers.kubernetescrd.certauthfilepath  (Default: "")
            Kubernetes certificate authority file path (not needed for in-cluster client).
        --providers.kubernetescrd.disablepasshostheaders  (Default: "false")
            Kubernetes disable PassHost Headers.
        --providers.kubernetescrd.endpoint  (Default: "")
            Kubernetes server endpoint (required for external cluster client).
        --providers.kubernetescrd.ingressclass  (Default: "")
            Value of kubernetes.io/ingress.class annotation to watch for.
        --providers.kubernetescrd.labelselector  (Default: "")
            Kubernetes label selector to use.
        --providers.kubernetescrd.namespaces  (Default: "")
            Kubernetes namespaces.
        --providers.kubernetescrd.throttleduration  (Default: "0")
            Ingress refresh throttle duration
        --providers.kubernetescrd.token  (Default: "")
            Kubernetes bearer token (not needed for in-cluster client).
        --providers.kubernetesingress  (Default: "false")
            Enable Kubernetes backend with default settings.
        --providers.kubernetesingress.certauthfilepath  (Default: "")
            Kubernetes certificate authority file path (not needed for in-cluster client).
        --providers.kubernetesingress.disablepasshostheaders  (Default: "false")
            Kubernetes disable PassHost Headers.
        --providers.kubernetesingress.endpoint  (Default: "")
            Kubernetes server endpoint (required for external cluster client).
        --providers.kubernetesingress.ingressclass  (Default: "")
            Value of kubernetes.io/ingress.class annotation to watch for.
        --providers.kubernetesingress.ingressendpoint.hostname  (Default: "")
            Hostname used for Kubernetes Ingress endpoints.
        --providers.kubernetesingress.ingressendpoint.ip  (Default: "")
            IP used for Kubernetes Ingress endpoints.
        --providers.kubernetesingress.ingressendpoint.publishedservice  (Default: "")
            Published Kubernetes Service to copy status from.
        --providers.kubernetesingress.labelselector  (Default: "")
            Kubernetes Ingress label selector to use.
        --providers.kubernetesingress.namespaces  (Default: "")
            Kubernetes namespaces.
        --providers.kubernetesingress.throttleduration  (Default: "0")
            Ingress refresh throttle duration
        --providers.kubernetesingress.token  (Default: "")
            Kubernetes bearer token (not needed for in-cluster client).
    

    e) 確保Traefik有足夠的權限可以訪問apiserver endpoint

    如果你希望Traefik為你查詢信息:通過在配置中放置一些錯誤的apiserver地址,可以查看訪問的endpoint和查詢順序。有了這些知識和你的Traefik Kubernetes token,你就可以使用Traefik憑證檢查這些endpoint是否可以訪問。

    traefik_1    | E0421 12:30:12.624877       1 reflector.go:125] pkg/mod/k8s.io/client-go@v0.0.0-20190718183610-8e956561bbf5/tools/cache/reflector.go:98: Failed to list *v1.Endpoints: Get https://192.168.3.101:6443/api/v1/endpoints?limit=500&resourceVersion=0:
    traefik_1    | E0421 12:30:12.625341       1 reflector.go:125] pkg/mod/k8s.io/client-go@v0.0.0-20190718183610-8e956561bbf5/tools/cache/reflector.go:98: Failed to list *v1.Service: Get https://192.168.3.101:6443/api/v1/services?limit=500&resourceVersion=0:
    traefik_1    | E0421 12:30:12.625395       1 reflector.go:125] pkg/mod/k8s.io/client-go@v0.0.0-20190718183610-8e956561bbf5/tools/cache/reflector.go:98: Failed to list *v1beta1.Ingress: Get https://192.168.3.101:6443/apis/extensions/v1beta1/ingresses?limit=500&resourceVersion=0:
    traefik_1    | E0421 12:30:12.625449       1 reflector.go:125] pkg/mod/k8s.io/client-go@v0.0.0-20190718183610-8e956561bbf5/tools/cache/reflector.go:98: Failed to list *v1alpha1.Middleware: Get https://192.168.3.101:6443/apis/traefik.containo.us/v1alpha1/middlewares?limit=500&resourceVersion=0:
    traefik_1    | E0421 12:30:12.625492       1 reflector.go:125] pkg/mod/k8s.io/client-go@v0.0.0-20190718183610-8e956561bbf5/tools/cache/reflector.go:98: Failed to list *v1alpha1.IngressRoute: Get https://192.168.3.101:6443/apis/traefik.containo.us/v1alpha1/ingressroutes?limit=500&resourceVersion=0:
    traefik_1    | E0421 12:30:12.625531       1 reflector.go:125] pkg/mod/k8s.io/client-go@v0.0.0-20190718183610-8e956561bbf5/tools/cache/reflector.go:98: Failed to list *v1alpha1.TraefikService: Get https://192.168.3.101:6443/apis/traefik.containo.us/v1alpha1/traefikservices?limit=500&resourceVersion=0:
    traefik_1    | E0421 12:30:12.625572       1 reflector.go:125] pkg/mod/k8s.io/client-go@v0.0.0-20190718183610-8e956561bbf5/tools/cache/reflector.go:98: Failed to list *v1alpha1.TLSOption: Get https://192.168.3.101:6443/apis/traefik.containo.us/v1alpha1/tlsoptions?limit=500&resourceVersion=0:
    traefik_1    | E0421 12:30:12.625610       1 reflector.go:125] pkg/mod/k8s.io/client-go@v0.0.0-20190718183610-8e956561bbf5/tools/cache/reflector.go:98: Failed to list *v1alpha1.IngressRouteTCP: Get https://192.168.3.101:6443/apis/traefik.containo.us/v1alpha1/ingressroutetcps?limit=500&resourceVersion=0:
    

    f) 記錄K3s本身

    安裝腳本將自動檢測你的操作系統是使用systemd還是openrc並啟動服務。使用openrc運行時,將在/var/log/k3s.log中創建日誌。使用systemd運行時,將在/var/log/syslog中創建日誌,並使用journalctl -u k3s查看。

    在那裡,你可能會得到一些提示,例如:

    кві 21 15:42:44 u18d k3s[612]: E0421 15:42:44.936960     612 authentication.go:104] Unable to authenticate the request due to an error: invalid bearer token
    

    這將為你提供有關K8s Traefik起初使用時出現問題的線索,Enjoy your journey!

    相關代碼你可以在以下鏈接中找到:

    https://github.com/Voronenko/k3s-mini

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 深入理解JVM(③)虛擬機的類加載時機

    深入理解JVM(③)虛擬機的類加載時機

    前言

    Java虛擬機把描述類的數據從Class文件加載到內存,並對數據進行校驗、轉換解析和初始化,最終形成可以被虛擬機直接使用的Java類型,這個過程被稱為虛擬機的類加載機制。

    類加載的時機

    一個類型從被加載到虛擬機內存中開始,到卸載除內存為止,它的生命周期將會經歷加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和 卸載(Unloading)、七個階段,其中驗證、準備、解析三個部分統稱為連接(Linking)。
    類的生命周期如下圖:

    其實加載、驗證、準備、初始化和卸載這五個階段的順序是確定的,類型的加載過程必須按照這種順序按部就班地開始,而解析階段則不一定:它在某些情況下可以在初始化階段之後再開始,這是為了支持Java語音的運行時綁定特性(也稱為動態綁定或晚期綁定)。
    在什麼情況下需要開始類加載過程的第一個階段“加載”,《Java虛擬機規則》中並沒有進行強制約束,但是對於初始化階段《Java虛擬機規範》則是嚴格規定了有且只有以下六種情況必須立即對類進行“初始化”。

    1. 遇到newgetstaticputstaticinvokestatic這四條字節碼指令時,如果類型沒有進行過初始化,則需要先觸發其初始化階段。
      涉及到這四條指令的典型場景有:
    • 使用new關鍵字實例化對的時候。
    • 讀取或設置一個類型的靜態字段(被final修飾、已在編譯期把結果放入常量池的靜態字段除外)的時候。
    • 調用一個類型的靜態方法的時候。
    1. 使用 java.lang.reflect 包的方法對類型進行反射調用的時候,如果類型沒有進行過初始化,則需要先觸發其初始化。
    2. 當初始化類型的時候,如果發現其父類還沒有進行過初始化,則需要先觸發其父類的初始化。
    3. 當虛擬機啟動時,用戶需要指定一個要執行的主類(包含main()方法的那個類),虛擬機會先初始化這個主類。
    4. 當使用JDK7新加入的動態語言支持時,如果一個java.lang.invoke.MethodHandle實例最後的解析結果為REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四種類型的方法句柄,並且這個方法句柄對應的類沒有進行過初始化,則需要先觸發其初始化。
    5. 當一個接口中定義了JDK8新加入的默認方法(被default關鍵字修飾的接口方法)時,如果這個接口的實現類發生了初始化,那該接口要在其之前被初始化。
      除了以上的這個六種場景外,所有引用類型的方式都不會觸發初始化,稱為被動引用。
      下面來看一下哪些是被動引用:

    例子1:

    父類

    package com.jimoer.classloading;
    
    /**
     * @author jimoer
     * @date Create in 2020/06/24 16:08
     * @description 通過子類引用父類的靜態字段,不會導致子類初始化。
     */
    public class FatherClass {
    
        static {
            System.out.println("FatherClass init!!!!!");
        }
    
        public static int value = 666;
    
    }
    

    子類

    package com.jimoer.classloading;
    
    public class SonClass extends FatherClass{
    
        static {
            System.out.println("SonClass init!!!");
        }
    
    }
    

    測試類

    @Test
    public void testInitClass(){
        System.out.println(SonClass.value);
    }
    

    運行結果:

    FatherClass init!!!!!
    666
    

    通過運行結果我們看到,只輸出了“FatherClass init!!!!!”,並沒有輸出“SubClass init!!!”,這是因為對於使用靜態字段,只有直接定義這個字段的類才會被初始化,因此通過子類來引用父類中定義的靜態字段,並不會初始化子類。

    例子2:

    /**
     * 通過數組定義來引用類,不會觸發此類的初始化
     */
    @Test
    public void testInitClass2(){
        FatherClass[] fathers = new FatherClass[5];
    }
    

    運行結果:未打印任何信息。
    通過運行結果我們發現,並沒有打印出 FatherClass init!!!!! ,這說明並沒有觸發Father類的初始化階段。但是這段代碼裏面觸發了另一個名為“[Lcom.jimoer.classloading.FatherClass”的類的初始化階段,它是一個由虛擬機自動生成的、直接繼承與java.lang.Object的子類,創建動作由字節碼newarray觸發。這個類代表了一個元素類型為FatherClass的一維數組,數組中應用的屬性和方法(length屬性和clone()方法)都實現在這個類里。

    例子3:

    /**
     * @author jimoer
     * 常量在編譯階段會存入調用類的常量池中,
     * 本質上沒有直接引用到定義常量的類,
     * 因此不會觸發定義常量的類的初始化。
     */
    public class ConstantClass {
        
        static {
            System.out.println("ConstantClass init !!!");
        }
        
        public static final String CLASS_LOAD = "class load test !!!";
        
    }
    

    使用

    /**
     * 使用常量
     */
    @Test
    public void testInitClass3(){
        System.out.println(ConstantClass.CLASS_LOAD);
    }
    

    運行結果:

    class load test !!!
    

    通過運行結果,我們看到當在使用一個類的常量時,並不會初始化定義了常量的類。這是因為雖然在Java源碼中確實引用了ConstatClass的類的常量CLASS_LOAD,但其實在編譯階段通過常量傳播優化,已經將此常量的值“class load test !!!”直接存儲在使用常量的類中的常量池中了,所以在使用ConstantClass.CLASS_LOAD時候,實際上都被轉化為在使用類自身的常量池的引用了。

    接口也是有初始化過程的,上面的代碼都是用靜態語句塊“static {}”來輸出初始化信息的,而接口中不能使用static{}語句塊,但編譯器仍然會為接口生成“ ()”類構造器,用於初始化接口中所定義的成員變量。
    還有一點接口與類不同,當一個類在初始化時,要求其父類全部都已經初始化過了,但是在一個接口初始化時,並不要求其父接口全部都完成了初始化,只有在真正使用到父接口的時候(例如引用接口中的常量)才會初始化。

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

    【其他文章推薦】

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

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

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

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

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

  • 算法崗面試題:模型的bias和variance是什麼?用隨機森林舉例

    算法崗面試題:模型的bias和variance是什麼?用隨機森林舉例

    校招在即,準備準備一些面試可能會用到的東西吧。希望這次面試不會被掛。

    基本概念

    說到機器學習模型的誤差,主要就是bias和variance。

    • Bias:如果一個模型的訓練錯誤大,然後驗證錯誤和訓練錯誤都很大,那麼這個模型就是高bias。可能是因為欠擬合,也可能是因為模型是弱分類器。

    • Variance:模型的訓練錯誤小,但是驗證錯誤遠大於訓練錯誤,那麼這個模型就是高Variance,或者說它是過擬合。

    這個圖中,左上角是低偏差低方差的,可以看到所有的預測值,都會落在靶心,完美模型;

    右上角是高偏差,可以看到,雖然整體數據預測的好像都在中心,但是波動很大。

    【高偏差vs高方差】
    在機器學習中,因為偏差和方差不能兼顧,所以我們一般會選擇高偏差、低方差的左下角的模型。穩定性是最重要的,寧可所有的樣本都80%正確率,也不要部分樣本100%、部分50%的正確率。個人感覺,穩定性是學習到東西的體現,高方差模型與隨機蒙的有什麼區別?

    隨機森林為例

    上面的可能有些抽象,這裏用RandomForest(RF)來作為例子:
    隨機森林是bagging的集成模型,這裏:
    \(RF(x)=\frac{1}{B}\sum^B_{i=1}{T_{i,z_i}(x)}\)

    • RF(x)表示隨機森林對樣本x的預測值;
    • B表示總共有B棵樹;
    • \(z_i\)表示第i棵樹所使用的訓練集,是使用bagging的方法,從所有訓練集中進行行採樣和列採樣得到的子數據集。

    這裏所有的\(z\),都是從所有數據集中隨機採樣的,所以可以理解為都是服從相同分佈的。所以不斷增加B的數量,增加隨機森林中樹的數量,是不會減小模型的偏差的。
    【個人感覺,是因為不管訓練再多的樹,其實就那麼多數據,怎麼訓練都不會減少,這一點比較好理解】

    【RF是如何降低偏差的?】
    直觀上,使用多棵樹和bagging,是可以增加模型的穩定性的。怎麼證明的?

    我們需要計算\(Var(T(x))\)
    假設不同樹的\(z_i\)之間的相關係數為\(\rho\),然後每棵樹的方差都是\(\sigma^2\).

    先複習一下兩個隨機變量相加的方差如何表示:
    \(Var(aX+bY)=a^2 Var(X)+b^2 Var(Y) + 2ab cov(X,Y)\)

    • Cov(X,Y)表示X和Y的協方差。協方差和相關係數不一樣哦,要除以X和Y的標準差:
      \(\rho=\frac{cov(X,Y)}{\sigma_X \sigma_Y}\)

    下面轉成B個相關變量的方差計算,是矩陣的形式:

    很好推導的,可以試一試。

    這樣可以看出來了,RF的樹的數量越多,RF方差的第二項會不斷減小,但是第一項不變。也就是說,第一項就是RF模型偏差的下極限了。

    【總結】

    • 增加決策樹的數量B,偏差不變;方差減小;
    • 增加決策樹深度,偏差減小;\(\rho\)減小,\(\sigma^2\)增加;
    • 增加bagging採樣比例,偏差減小;\(\rho\)增加,\(\sigma^2\)增加;

    【bagging vs boost】
    之前也提到過了boost算法:
    一文讀懂:GBDT梯度提升
    GBDT中,在某種情況下,是不斷訓練之前模型的殘差,來達到降低bias的效果。雖然也是集成模型,但是可以想到,每一個GBDT中的樹,所學習的數據的分佈都是不同的,這意味着在GBDT模型的方差會隨着決策樹的數量增多,不斷地增加。

    • bagging的目的:降低方差;
    • boost的目的:降低偏差

    喜歡的話請關注我們的微信公眾號~【你好世界煉丹師】。

    • 公眾號主要講統計學,數據科學,機器學習,深度學習,以及一些參加Kaggle競賽的經驗。
    • 公眾號內容建議作為課後的一些相關知識的補充,飯後甜點。
    • 此外,為了不過多打擾,公眾號每周推送一次,每次4~6篇精選文章。

    微信搜索公眾號:你好世界煉丹師。期待您的關注。

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

    【其他文章推薦】

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

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

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

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

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

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