標籤: 台北網頁設計公司

  • 寶馬投資Scoop拼車應用公司進軍汽車共享市場

    據《路透社》報導,寶馬集團透露,其旗下風險投資部門iVentures已經為加利福尼亞拼車應用公司Scoop提供了一筆投資金額,具體數目未知。

    Scoop公司目前位於三藩市港灣區,通過智慧手機支援為乘客提供拼車服務,其開發出的應用軟體可將相鄰社區及工作區域的人們連接起來,共同拼車。寶馬此舉為汽車製造商為初創公司投資的最新一次行動,使消費者在未擁有私人車輛或經常駕駛的情況下也能夠出行。

    此外,寶馬還分別為車隊管理軟體公司RideCell、泊車點定位服務Zirx、簡化公共交通系統服務Moovit、從智慧手機上集成資料教授司機如何安全駕駛的Zendrive公司進行了投資。

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

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

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

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

    小三通海運與一般國際貿易有何不同?

    小三通快遞通關作業有哪些?

  • 特斯拉超級電池工廠Gigafactory 7月正式開業 目前仍在建

    據外媒體報導,特斯拉稱其位於內華達州里諾市郊的超級電池工廠Gigafactory將於7月29日晚上舉行開業典禮,目前該工廠仍處於建設之中。

    特斯拉在發給客戶的一封電子郵件中披露,為特斯拉成功推薦的客戶超過5位元的人將會受邀參加此次開業典禮。特斯拉已經通過電子郵件向這些符合資格的客戶通知了開業典禮時間。

    事實上,在未來2個月內Gigafactory工廠不可能完全竣工,特斯拉僅僅是決定在已建成區域舉行小型典禮。在今年3月份,特斯拉、SolarCity在該廠區接待了內華達州議員,探討了太陽能業務在該州的發展。

    據悉,Gigafactory工廠建設造價逾50億美元,到今年5月初僅建成14%。此外,松下向特斯拉的超級電池工廠供應電池生產設備,並提供部分資金。

    儘管電池廠還在建設之中,但是工廠已經投產。工廠目前生產的太陽能電池被用於公共設施、企業以及各個地產業主。

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

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

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

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

    小三通海運與一般國際貿易有何不同?

    小三通快遞通關作業有哪些?

  • Gigafactory 即將正式開幕,福斯隔海叫陣

    Gigafactory 即將正式開幕,福斯隔海叫陣

    特斯拉(Tesla)位於美國內華達州的超級電池工廠 Gigafactory 已經部分營運了好一陣子,不過一直一邊生產一邊還在施工,尚未正式開幕,如今開工大典的日子出爐,特斯拉將於 2016 年 7 月 29 日舉辦開工典禮。   特斯拉 Gigafactory 將是預購熱銷的 Model 3 是否能達成出貨的重要關鍵,Gigafactory 預定 2020 年達到最大產能,1 年生產 3,500 萬度儲存容量的電池,特斯拉表示,這超過 2013 年全球鋰電池生產總量,理論上並將降低 30% 生產成本,使得 Model 3 得以壓低售價還能獲利。   在 2016 年 5 月初,Gigafactory 大約有 14% 完工,目前已經開始生產能源儲存產品 Powerpack 與 Powerwall,不過特斯拉一直未在 Gigafactory 舉辦媒體活動,只有曾經獨家邀請汽車雜誌《汽車趨勢》(Motor Trend)前往其中參觀 Model 3 原型。如今特斯拉在寄給消費者的邀請函中透露開工典禮的日期。   特斯拉的活動往往是消費者優於媒體,Model 3 發表會時,車主先受邀,之後才邀請媒體,Gigafactory 開幕式看樣子也是如此,目前特斯拉先邀請透過介紹 5 位朋友買 Model 3 而贏得參加開幕式權利的消費者參加,媒體尚未受邀,目前尚不清楚到底最後會不會邀請媒體。   就在特斯拉緊鑼密鼓籌辦開工大典時,競爭對手也不甘示弱,德國報導指出德國汽車大廠福斯(VW)打算建造與 Gigafactory 一爭雄長的「數十億歐元」工廠,用以生產電動車並自行生產鋰電池,擺脫對 Panasonic、三星與 LG 化學等電池供應商的依賴。   福斯剛經歷柴油車作弊事件,讓福斯柴油車的形象跌到谷底,很容易理解福斯如今更積極發展電動車以開拓新局,福斯將於 2016 年 6 月 22 日的年會上發表電動車與電池工廠的進一步詳情。特斯拉 Gigafactory 的開幕,可能將是全球車廠與電池廠軍備大賽的開端。

    (首圖來源:)   (本文授權轉載自《》─〈〉)

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

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    小三通物流營運型態?

    ※快速運回,大陸空運推薦?

  • Zabbix-(五)監控Docker容器與自定義jvm監控項

    Zabbix-(五)監控Docker容器與自定義jvm監控項

    Zabbix-(五)監控Docker容器與自定義jvm監控項

    一.前言

    前文中講述了Zabbix對服務器硬件方面的監控功能,本文將講述利用Zabbix監控Docker容器中的Java Web服務,並通過自定義監控項,監控JVM老年代使用情況以及GC信息。Zabbix其實提供了,自帶了JMX模板能夠直接監控JVM信息,本文主要側重於自定義參數與自定義監控項,關於JMX會在之後的文章中介紹。

    準備

    • Zabbix Server (Zabbix 4.4) (ip:192.168.152.140)
    • 運行Java應用的主機 以下簡稱Server-A (已被Zabbix監控) (ip:192.168.152.142)

    二.開啟agent用戶自定義參數配置

    1. 修改配置

      使用自定義參數時,首先需要修改Server-A的agent配置

      # vim /etc/zabbix/zabbix_agentd.conf

      修改配置 UnsafeUserParameters=1

      UnsafeUserParameters=1
    2. 重啟zabbix-agent

      # systemctl restart zabbix-agent

    三.運行tomcat容器

    在Server-A運行tomcat容器

    # docker run --name tomcat -p 8080:8080 -dit tomcat:jdk8-adoptopenjdk-hotspot

    將zabbix賬號添加到docker組。參考

    # sudo gpasswd  -a zabbix docker

    外部訪問測試一下

    四.創建自定義Docker模板

    我們可以定義一個比較通用的Docker模板,有服務需要被監控時,直接鏈接該模板即可。

    1. 創建群組

      點擊【配置】-【主機群組】-【創建主機群組】

      定義一個組名 Docker Group

      配置項
      * 組名 Docker Group
    2. 創建模板

      創建一個自定義模板,模板名稱Docker Template,選擇上步驟創建的Docker Group群組

      配置項
      * 模板名稱 Docker Template
      * 群組 Docker Group

    五.編寫腳本與自定義監控參數

    我們需要編寫一個腳本,用於發現當前正在運行的docker容器(這裏使用容器名稱)。

    1. 在Server-A編寫發現運行容器的python腳本

      創建腳本

      # cd /data/zabbix
      # touch find_container.py
      # chmod a+x find_container.py
      # vim find_container.py

      腳本內容:

      #!/usr/bin/env python
      import os
      import json
      
      # 查看當前運行的docker容器
      t=os.popen(""" docker ps  |grep -v 'CONTAINER ID'|awk {'print $NF'} """)
      container_name = []
      for container in  t.readlines():
              r = os.path.basename(container.strip())
              container_name += [{'{#CONTAINERNAME}':r}]
      # 轉換成json數據
      print json.dumps({'data':container_name},sort_keys=True,indent=4,separators=(',',':'))

      運行腳本,查看一下json數據格式:

      {
          "data":[
              {
                  "{#CONTAINERNAME}":"tomcat"
              }
          ]
      }
    2. 在Server-A自定義容器發現參數

      我們需要自定義一個鍵值對的配置類型,以便Zabbix可以通過鍵讀取到值。

      增加自定義參數

      # cd /etc/zabbix/zabbix_agentd.d
      # vim userparameter_find_container.conf
      docker.container /data/zabbix/find_container.py (腳本的運行結果)
      UserParameter=docker.container,/data/zabbix/find_container.py
    3. 在Server-A創建查看容器JVM GC情況的腳本

      我們可以使用jstat -gcutil 命令查看GC情況

      創建python腳本

      # cd /data/zabbix
      # touch monitor_gc.py
      # chmod a+x monitor_gc.py
      # vim monitor_gc.py

      腳本內容

      #!/usr/bin/python
      import sys
      import os
      
      def monitor_gc(container_name, keyword):
              cmd = ''' docker exec %s bash -c "jstat -gcutil 1" | grep -v S0 | awk '{print $%s}' ''' %(container_name, keyword)
              value = os.popen(cmd).read().replace("\n","")
              print value
      
      if __name__ == '__main__':
              # 參數1:容器的名稱
              # 參數2:查看第幾列(例如 Eden區在第3列傳入3,Full GC次數在第9列傳入9)
              container_name, keyword = sys.argv[1], sys.argv[2]
              monitor_gc(container_name, keyword)

      測試腳本,查看當前tomcat容器Full GC次數

      # /data/zabbix/monitor_gc.py 'tomcat' '9'

    4. 在Server-A自定義Zabbix JVM GC參數

      同樣,增加一個conf文件,表示自定義參數

      # cd /etc/zabbix/zabbix_agentd.d
      # touch userparameter_gc_status.conf
      # vim userparameter_gc_status.conf
      jvm.gc.status[*] /data/zabbix/monitor_gc.py $1 $2
      UserParameter=jvm.gc.status[*], /data/zabbix/monitor_gc.py $1 $2

      jvm.gc.status[*] 表示可以使用參數。其中$1表示參數1,即容器名稱;$2表示參數2,需要查看哪項GC信息,$1 $2都是通過Zabbix配置時傳遞的。

    5. 在Zabbix server上測試自定義參數

      為zabbix sever安裝zabbix-get

      # yum install -y zabbix-get

      測試自定義參數,如果有權限問題,可以參考

      # zabbix_get -s 192.168.152.142 -p 10050 -k docker.container
      # zabbix_get -s 192.168.152.142 -p 10050 -k "jvm.gc.status['tomcat', 9]"

    六.Zabbix模板增加自動發現規則

    上述配置中,已經可以通過腳本獲取到已運行的容器信息,此步驟將通過Zabbix配置界面,在模板中添加自動發現規則,以發現被監控主機中正在運行的docker容器,並利用這些獲取的數據進一步監控容器中jvm數據。

    1. 創建自動發現規則

      點擊【配置】-【模板】-【Docker Template】

      點擊【自動發現規則】-【創建發現規則】

      先配置【自動發現規則】

      配置項
      * 名稱 發現正在運行的Docker容器規則
      類型 Zabbix 客戶端
      * 鍵值 docker.container (這是我們上述步驟中自定義的鍵值)
      其他配置 根據需要配置

      鍵值配置項是之前

      再配置【過濾器】

      則配置自定義腳本返回json數據中的

      配置項
      {#CONTAINERNAME}
    2. 添加監控項原型

      點擊新建的自動發現規則的【監控項原型】-【創建監控項原型】

      輸入參數

      配置項
      * 名稱 Tomcat Full GC次數監控項
      類型 Zabbix 客戶端
      * 鍵值 jvm.gc.status[{#CONTAINERNAME} , 9]
      其他配置項 根據需要填寫

      鍵值是定義的參數,{#CONTAINERNAME} 是jvm.gc.status的參數1,使用了自動發現規則,發現到的docker容器名稱(本文中即是 tomcat);參數2 9 則是表示需要查看FullGC次數,FGC列(第9列)

      除此之外,還可以添加Old老年代(對應第4列),Full GC時間(對應第10列)等監控項,這裏就不一一添加了,和上述過程基本一致,只需修改參數2即可(也可以利用剛新建的監控項原型進行【克隆】)。

    七.鏈接模板

    將上述鏈接到Server-A主機

    八.DashBoard添加可視化圖形

    回到Zabbix首頁可以為新增的自定義監控項,增加圖形(添加圖形步驟可以參考)

    九.其他

    部署問題

    • zabbix在執行腳本時,是使用的zabbix賬戶,因此可能要注意要給zabbix賬號賦予權限。

      例如,zabbix賬戶無法使用docker命令,將zabbix添加到docker組

      # sudo gpasswd -a zabbix docker
    • zabbix server無法執行agent自定義參數中的腳本

      為agent主機設置

      # setenforce 0

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

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

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

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

    小三通海運與一般國際貿易有何不同?

    小三通快遞通關作業有哪些?

  • 數組與鏈表

    數組與鏈表

    前言

    數組和鏈表是兩種數據結構,數組非常簡單易用但是它有兩個非常大的缺點,一個是數組一旦創建無法擴展,另一個則是數組的查找和刪除的速度很慢.

    鏈表改善了一些數組的缺點,但是同樣的鏈表自身也存在一些自己的缺點.

    本篇博客將為大家介紹一下這數組和鏈表特點及各自的優缺點.

    閱讀前的準備工作

    ,一種粗略的評價計算機算法效率的方法.後面的內容會用到表示效率的方法.

    1. 數組

    我們按數組中的數組是否排序對數組進行劃分,將數組分為無序數組和有序數組.無序數組中的數組是無序的,而有序數組中的數據則是升序或者降序排序的.

    1.1 無序數組

    因為無序數組中的數據是無序的,往數組中添加數據時不用進行比較和移動數據,所以往無序數組裡面添加數據很快.無論是添加第一個數據還是第一萬個數據所需的時間是相同的,效率為O(1).

    至於查找和刪除速度就沒有那麼快了,以數組中有一萬個數據項為例,最少需要比較1次,最多則需要比較一萬次,平均下來需要比較5000次,即N/2次比較,N代表數據量,大O表示法中常數可以忽略,所以效率為O(N).

    結論:

    1. 插入很快,因為總是將數據插入到數組的空餘位置.
    2. 查找和刪除很慢,假設數組的長度為N,那麼平均的查找/刪除的比較次數為N/2,並且還需要移動數據.

    1.2 有序數組

    無序數組中存放的數據是無序的,有序數組裡面存放的數據則是有序的(有可能是升序有可能是降序).

    因為有序數組中的數據是按升序/降序排列的,所以插入的時候需要進行排序並且移動數據項,所有有序數組的插入速度比無序數組慢. 效率為O(N).

    刪除速度和無序數組一樣慢 效率為O(N).

    有序數組的查找速度要比無序數組快,這是因為使用了一個叫做二分查找的算法.

    二分查找: 二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。但是,折半查找要求線性表必須採用順序存儲結構,而且表中元素按關鍵字有序排列.

    有一個關於二分查找的形象類比 -> 猜數遊戲

    假設要在0-100之間猜一個數,那麼你第一個要猜的数字就是100的一半50的時候,你的朋友會告訴你這個数字比要猜的数字是大還是小,如果比数字大,你接下來要猜的数字就是50的一半25,你的朋友說比這個数字要大,那麼你下面要猜的数字就是25-50中間的那個數37,以此類推…

    使用二分查找可極大的提高查找的效率,假設一個有序數組有十億個數據,那麼查找到所需的数字,最多只需比較30次.

    有序數組使用二分查找的效率為O(logN).有序數組也可以通過二分查找來新增和刪除數據以提高效率,但是依然需要在新增/刪除后移動數據項,所以效率依然會有影響.

    總結:

    1. 有序數組的查找速度比無序數組高,效率為O(logN)
    2. 有序數組的刪除和新增速度很慢,效率為O(N)

    1.3 數組總結

    數組雖然簡單易用,但是數組有兩個致命的缺點:

    1. 數組存儲的數量有限,創建的過大浪費資源,創建的過小溢出
    2. 數組的效率比其他數據結構低
    • 無序數組插入效率為O(1)時間,但是查找花費O(N)時間
    • 有序數組查找花費O(logN)時間,插入花費O(N)時間
    • 刪除需要移動平均半數的數據項,所以刪除都是O(N)的時間

    2. 鏈表

    數組一經創建大小就固定住了,無法修改,鏈表在這方面做出了改善,只要內存夠用就可以無限制的擴大.

    鏈表是繼數組之後應用最廣泛的數據結構.

    2.1 鏈表的特點

    鏈表為什麼叫鏈表呢? 因為它保存數據的方式就像一條鎖鏈

    鏈表保存數據的方式很像上面的這一條鎖鏈,每一塊鎖鏈就是一個鏈節點,鏈節點保存着自己的數據同時通過自己的next()方法指向下一個鏈節點. 鏈表通過鏈節點不斷地調用next()方法就可以遍歷鏈表中的所有數據.

    在鏈表中,每個數據項都被包含在”鏈節點”(link)中,一個鏈結點是某個類的對象,這個類可以叫做Link.因為一個鏈表中有許多類似的鏈結點,所以有必要用一個不同於鏈表的類來表達鏈結點.

    每個Link對象中都包含一個對下一個鏈結點引用的字段(通常叫做next).

    鏈表本身的對象中有一個字段指向對第一個鏈結點的引用.

    數據與鏈表查找數據的區別: 在數組中查找數據就像在一個大倉庫裏面一樣,一號房間沒有,我們去二號房間,二號房間沒有我們去三號房間,以此類推.. 按照地址找完所有房間就可以了.

    而在鏈表中查找數據就像單線彙報的地下工作者,你是孤狼你想要彙報點情報給你的頂級上司毒蜂,但是你必須先報告給你的接頭人豬剛鬣,豬剛鬣在報告給它的單線接頭人土行孫,最後由土行孫報告給毒蜂.只能一個找一個,這樣最終完成任務.

    2.2 Java代碼

    鏈節點類:

    
    /**
     * @author liuboren
     * @Title: 鏈節點
     * @Description:
     * @date 2019/11/20 19:30
     */
    public class Link {
        //  保存的數據
        public int data;
    
        // 指向的下一個鏈節點
        public Link nextLink;
    
        public Link(int data) {
            this.data = data;
        }
    
        public int getData() {
            return data;
        }
    
        public void setData(int data) {
            this.data = data;
        }
    
        public Link getNextLink() {
            return nextLink;
        }
    
        public void setNextLink(Link nextLink) {
            this.nextLink = nextLink;
        }
    }
    

    鏈表類

    
    /**
     * @author liuboren
     * @Title: 鏈表類
     * @Description:
     * @date 2019/11/20 19:31
     */
    public class LinkList {
        private Link first;
    
        public LinkList() {
            first = null;
        }
    
        // 新增鏈節點方法
        public void insertFirst(int data) {
            Link link = new Link(data);
            link.setNextLink(first);
            first = link;
        }
    }
    

    在新增節點的時候,新增的link的next方法指向原來的first節點,並將鏈表類的first指向新增的節點.

    2.4 其他鏈表

    剛剛介紹的鏈表是單向鏈表,只能從后往前遍歷,其他的鏈表還有雙端鏈表、雙向鏈表、有序鏈表.

    再簡單介紹一下雙端鏈表吧.

    雙端鏈表就是在單向鏈表的基礎上,新增一個成員變量指向鏈表的最後一個對象.

    雙端鏈表代碼:

    /**
     * @author liuboren
     * @Title: 鏈表類
     * @Description:
     * @date 2019/11/20 19:31
     */
    public class LinkList {
        private Link first;
        private Link last;
    
        public LinkList() {
            first = null;
        }
    
        public boolean isEmpty() {
            return first == null;
        }
    
        // 新增鏈節點方法
        public void insertFirst(int data) {
            Link newLink = new Link(data);
            newLink.setNextLink(first);
            if (isEmpty()) {
                last = newLink;
            }
            first = newLink;
    
        }
    }
    

    雙向鏈表則是可以從first和last兩個方向進行遍歷,有序鏈表的數據都是按照關鍵字的順序排列的,本文不再展開了.

    2.5 鏈表的效率

    鏈表的效率:

    • 表頭插入和刪除速度都很快,花費O(1)的時間.
    • 平均起來,查找&刪除&插入在制定鏈節點後面都需要搜索一半的鏈節點需要O(N)次比較,雖然數組也需要O(N)次比較,但是鏈表讓然要快一些,因為不需要移動數據(只需要改變他們的引用)

    3. 總結

    鏈表解決了數組大小不能擴展的問題,但是鏈表自身依然存在一些問題(在鏈表的鏈節點後面查找&刪除&插入的效率不高),那麼有沒有一種數據結構即擁有二者的優點又改善了二者的缺點呢,答案是肯定的,下篇博客將為您介紹這種優秀的數據結構,敬請期待.

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

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    小三通物流營運型態?

    ※快速運回,大陸空運推薦?

  • 021.掌握Pod-Pod調度策略

    021.掌握Pod-Pod調度策略

    一 Pod生命周期管理

    1.1 Pod生命周期

    Pod在整個生命周期過程中被系統定義了如下各種狀態。

    狀態值 描述
    Pending API Server已經創建該Pod,且Pod內還有一個或多個容器的鏡像沒有創建,包括正在下載鏡像的過程。
    Running Pod內所有容器均已創建,且至少有一個容器處於運行狀態、正在啟動狀態或正在重啟狀態。
    Succeeded Pod內所有容器均成功執行退出,且不會重啟。
    Failed Pod內所有容器均已退出,但至少有一個容器退出為失敗狀態。
    Unknown 由於某種原因無法獲取該Pod狀態,可能由於網絡通信不暢導致。

    1.2 Pod重啟策略

    Pod重啟策略(RestartPolicy)應用於Pod內的所有容器,並且僅在Pod所處的Node上由kubelet進行判斷和重啟操作。當某個容器異常退出或者健康檢查失敗時,kubelet將根據RestartPolicy的設置來進行相應操作。
    Pod的重啟策略包括Always、OnFailure和Never,默認值為Always。

    • Always:當容器失效時,由kubelet自動重啟該容器;
    • OnFailure:當容器終止運行且退出碼不為0時,由kubelet自動重啟該容器;
    • Never:不論容器運行狀態如何,kubelet都不會重啟該容器。

           kubelet重啟失效容器的時間間隔以sync-frequency乘以2n來計算,例如1/2/4/8倍等,最長延時5min,並且在成功重啟后的10min后重置該時間。

    Pod的重啟策略與控制方式關聯,當前可用於管理Pod的控制器包括ReplicationController、Job、DaemonSet及直接管理kubelet管理(靜態Pod)。
    不同控制器的重啟策略限制如下:

    • RC和DaemonSet:必須設置為Always,需要保證該容器持續運行;
    • Job:OnFailure或Never,確保容器執行完成后不再重啟;
    • kubelet:在Pod失效時重啟,不論將RestartPolicy設置為何值,也不會對Pod進行健康檢查。








    Pod包含的容器數 Pod當前的狀態 發生事件 Pod的結果狀態
    RestartPolicy=Always RestartPolicy=OnFailure RestartPolicy=Never
    包含1個容器 Running 容器成功退出 Running Succeeded Succeeded
    包含1個容器 Running 容器失敗退出 Running Running Failed
    包括兩個容器 Running 1個容器失敗退出 Running Running Running
    包括兩個容器 Running 容器被OOM殺掉 Running Running Failed

    1.3 Pod健康檢查

    對Pod的健康檢查可以通過兩類探針來檢查:LivenessProbe和ReadinessProbe。
    LivenessProbe探針:用於判斷容器是否存活(running狀態),如果LivenessProbe探針探測到容器不健康,則kubelet將殺掉該容器,並根據容器的重啟策略做相應處理。若一個容器不包含LivenessProbe探針,kubelet認為該容器的LivenessProbe探針返回值用於是“Success”。
    ReadineeProbe探針:用於判斷容器是否啟動完成(ready狀態)。如果ReadinessProbe探針探測到失敗,則Pod的狀態將被修改。Endpoint Controller將從Service的Endpoint中刪除包含該容器所在Pod的Eenpoint。
    kubelet定期執行LivenessProbe探針來診斷容器的健康狀態,通常有以下三種方式:

    • ExecAction:在容器內執行一個命令,若返回碼為0,則表明容器健康。

    示例:通過執行”cat /tmp/health”命令判斷一個容器運行是否正常。容器初始化並創建該文件,10s后刪除該文件,15s秒通過命令判斷,由於該文件已被刪除,因此判斷該容器Fail,導致kubelet殺掉該容器並重啟。

      1 [root@uk8s-m-01 study]# vi dapi-liveness.yaml
      2 apiVersion: v1
      3 kind: Pod
      4 metadata:
      5   name: dapi-liveness-pod
      6   labels:
      7     test: liveness-exec
      8 spec:
      9   containers:
     10     - name: dapi-liveness
     11       image: busybox
     12       args:
     13       - /bin/sh
     14       - -c
     15       - echo ok > /tmp/health; sleep 10; rm -rf /tmp/health; sleep 600
     16       livenessProbe:
     17         exec:
     18           command:
     19           - cat
     20           - /tmp/health
     21 
     22 [root@uk8s-m-01 study]# kubectl describe pod dapi-liveness-pod

    • TCPSocketAction:通過容器的IP地址和端口號執行TCP檢查,若能建立TCP連接,則表明容器健康。

    示例:

      1 [root@uk8s-m-01 study]# vi dapi-tcpsocket.yaml
      2 apiVersion: v1
      3 kind: Pod
      4 metadata:
      5   name: dapi-healthcheck-tcp
      6 spec:
      7   containers:
      8     - name: nginx
      9       image: nginx
     10       ports:
     11       - containerPort: 80
     12       livenessProbe:
     13         tcpSocket:
     14           port: 80
     15         initialDelaySeconds: 30
     16         timeoutSeconds: 1
     17 
     18 [root@uk8s-m-01 study]# kubectl create -f dapi-tcpsocket.yaml


    提示:對於每種探測方式,都需要設置如下兩個參數,其包含的含義如下:

    initialDelaySeconds:啟動容器後進行首次健康檢查的等待時間,單位為s;

    timeoutSeconds:健康檢查發送請求后等待響應的超時時間,單位為s,當超時發生時,kubelet會認為容器已經無法提供服務,將會重啟該容器。

    二 Pod調度

    Kubernetes中,Pod通常是容器的載體,一般需要通過Deployment、DaemonSet、RC、Job等對象來完成一組Pod的調度與自動控制功能。

    2.1 Depolyment/RC自動調度

    Deployment或RC的主要功能之一就是自動部署一個容器應用的多份副本,以及持續監控副本的數量,在集群內始終維持用戶指定的副本數量。
    示例:

      1 [root@uk8s-m-01 study]# vi nginx-deployment.yaml
      2 apiVersion: apps/v1beta1
      3 kind: Deployment
      4 metadata:
      5   name: nginx-deployment-01
      6 spec:
      7   replicas: 3
      8   template:
      9     metadata:
     10       labels:
     11         app: nginx
     12     spec:
     13       containers:
     14       - name: nginx
     15         image: nginx:1.7.9
     16         ports:
     17         - containerPort: 80
     18 
     19 [root@uk8s-m-01 study]# kubectl get deployments
     20 NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
     21 nginx-deployment-01   3/3     3            3           30s
     22 [root@uk8s-m-01 study]# kubectl get rs
     23 NAME                             DESIRED   CURRENT   READY   AGE
     24 nginx-deployment-01-5754944d6c   3         3         3       75s
     25 [root@uk8s-m-01 study]# kubectl get pod | grep nginx
     26 nginx-deployment-01-5754944d6c-hmcpg   1/1     Running     0          84s
     27 nginx-deployment-01-5754944d6c-mcj8q   1/1     Running     0          84s
     28 nginx-deployment-01-5754944d6c-p42mh   1/1     Running     0          84s

    2.2 NodeSelector定向調度

    當需要手動指定將Pod調度到特定Node上,可以通過Node的標籤(Label)和Pod的nodeSelector屬性相匹配。
    # kubectl label nodes <node-name> <label-key>=<label-value>
    node節點創建對應的label后,可通過在定義Pod的時候加上nodeSelector的設置實現指定的調度。
    示例:

      1 [root@uk8s-m-01 study]# kubectl label nodes 172.24.9.14 speed=io
      2 node/172.24.9.14 labeled
      3 [root@uk8s-m-01 study]# vi nginx-master-controller.yaml
      4 kind: ReplicationController
      5 metadata:
      6   name: nginx-master
      7   labels:
      8     name: nginx-master
      9 spec:
     10   replicas: 1
     11   selector:
     12     name: nginx-master
     13   template:
     14     metadata:
     15       labels:
     16         name: nginx-master
     17     spec:
     18       containers:
     19       - name: master
     20         image: nginx:1.7.9
     21         ports:
     22         - containerPort: 80
     23       nodeSelector:
     24         speed: io
     25 
     26 [root@uk8s-m-01 study]# kubectl create -f nginx-master-controller.yaml
     27 [root@uk8s-m-01 study]# kubectl get pods -o wide
     28 NAME                READY   STATUS    RESTARTS    AGE    IP            NODE
     29 nginx-master-7fjgj  1/1     Running   0           82s    172.24.9.71   172.24.9.14


    提示:可以將集群中具有不同特點的Node貼上不同的標籤,實現在部署時就可以根據應用的需求設置NodeSelector來進行指定Node範圍的調度。

    注意:若在定義Pod中指定了NodeSelector條件,但集群中不存在符合該標籤的Node,即使集群有其他可供使用的Node,Pod也無法被成功調度。

    2.3 NodeAffinity親和性調度

    親和性調度機制極大的擴展了Pod的調度能力,主要增強功能如下:

    1. 更具表達力,即更精細的力度控制;
    2. 可以使用軟限制、優先採用等限制方式,即調度器在無法滿足優先需求的情況下,會使用其他次條件進行滿足;
    3. 可以依據節點上正在運行的其他Pod的標籤來進行限制,而非節點本身的標籤,從而實現Pod之間的親和或互斥關係。

    目前有兩種節點親和力表達:
    requiredDuringSchedulingIgnoredDuringExecution:硬規則,必須滿足指定的規則,調度器才可以調度Pod至Node上(類似nodeSelector,語法不同)。
    preferredDuringSchedulingIgnoredDuringExecution:軟規則,優先調度至滿足的Node的節點,但不強求,多個優先級規則還可以設置權重值。
    IgnoredDuringExecution指:如果一個Pod所在的節點在Pod運行期間標籤發生了變化,不再符合該Pod的節點親和性需求,則系統將忽略Node上Label的變化,該Pod能繼續在該節點運行。
    示例:
    條件1:只運行在amd64的節點上;盡量運行在ssd節點上。

      1 [root@uk8s-m-01 study]# vi nodeaffinity-pod.yaml
      2 apiVersion: v1
      3 kind: Pod
      4 metadata:
      5   name: with-node-affinity
      6 spec:
      7   affinity:
      8     nodeAffinity:
      9       requiredDuringSchedulingIgnoredDuringExecution:
     10         nodeSelectorTerms:
     11         - matchExpressions:
     12           - key: kubernetes.io/arch
     13             operator: In
     14             values:
     15             - amd64
     16       preferredDuringSchedulingIgnoredDuringExecution:
     17       - weight: 1
     18         preference:
     19           matchExpressions:
     20           - key: disk-type
     21             operator: In
     22             values:
     23             - ssd
     24   containers:
     25   - name: with-node-affinity
     26     image: gcr.azk8s.cn/google_containers/pause:2.0


    NodeAffinity操作語法;In、NotIn、Exists、DoesNotExist、Gt、Lt。NotIn和DoesNotExist可以實現互斥功能。
    NodeAffinity規則設置注意事項:

    • 若同時定義nodeSelector和nodeAffinity,則必須兩個條件都滿足,Pod才能最終運行指定在Node上;;
    • 若nodeAffinity指定多個nodeSelectorTerms,則只需要其中一個能夠匹配成功即可;
    • 若nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行該Pod。

    2.4 PodAffinity親和性調度

    PodAffinity根據節點上正在運行的Pod標籤而不是Node標籤來判斷和調度,要求對節點和Pod兩個條件進行匹配。
    規則描述為:若在具有標籤X的Node上運行了一個或多個符合條件Y的Pod,則Pod應該(或者不應該)運行在這個Node上。
    X通常為Node節點的機架、區域等概念,Pod是屬於某個命名空間,所以條件Y表達的是一個或全部命名空間中的一個Label Selector。
    Pod親和性定義與PodSpec的affinity字段下的podAffinity字段里,互斥性定義於同一層次的podAntiAffinity子字段中。
    舉例:

      1 [root@uk8s-m-01 study]# vi nginx-flag.yaml	#創建名為pod-flag,帶有兩個標籤的Pod
      2 apiVersion: v1
      3 kind: Pod
      4 metadata:
      5   name: pod-affinity
      6 spec:
      7   affinity:
      8     podAffinity:
      9       requiredDuringSchedulingIgnoredDuringExecution:
     10       - labelSelector:
     11           matchExpressions:
     12           - key: security
     13             operator: In
     14             values:
     15             - S1
     16         topologyKey: kubernetes.io/hostname
     17   containers:
     18   - name: with-pod-affinity
     19     image: gcr.azk8s.cn/google_containers/pause:2.0

      1 [root@uk8s-m-01 study]# vi nginx-affinity-in.yaml	#創建定義標籤security=S1,對應如上Pod “Pod-flag”。
      2 apiVersion: v1
      3 kind: Pod
      4 metadata:
      5   name: pod-affinity
      6 spec:
      7   affinity:
      8     podAffinity:
      9       requiredDuringSchedulingIgnoredDuringExecution:
     10       - labelSelector:
     11           matchExpressions:
     12           - key: security
     13             operator: In
     14             values:
     15             - S1
     16         topologyKey: kubernetes.io/hostname
     17   containers:
     18   - name: with-pod-affinity
     19     image: gcr.azk8s.cn/google_containers/pause:2.0
     20 
     21 [root@uk8s-m-01 study]# kubectl create -f nginx-affinity-in.yaml
     22 [root@uk8s-m-01 study]# kubectl get pods -o wide


    提示:由上Pod親和力可知,兩個Pod處於同一個Node上。

      1 [root@uk8s-m-01 study]# vi nginx-affinity-out.yaml	#創建不能與參照目標Pod運行在同一個Node上的調度策略
      2 apiVersion: v1
      3 kind: Pod
      4 metadata:
      5   name: anti-affinity
      6 spec:
      7   affinity:
      8     podAffinity:
      9       requiredDuringSchedulingIgnoredDuringExecution:
     10       - labelSelector:
     11           matchExpressions:
     12           - key: security
     13             operator: In
     14             values:
     15             - S1
     16         topologyKey: failure-domain.beta.kubernetes.io/zone
     17     podAntiAffinity:
     18       requiredDuringSchedulingIgnoredDuringExecution:
     19       - labelSelector:
     20           matchExpressions:
     21           - key: security
     22             operator: In
     23             values:
     24             - nginx
     25         topologyKey: kubernetes.io/hostname
     26   containers:
     27   - name: anti-affinity
     28     image: gcr.azk8s.cn/google_containers/pause:2.0
     29 
     30 [root@uk8s-m-01 study]# kubectl get pods -o wide	#驗證

    2.5 Taints和Tolerations(污點和容忍)

    Taint:使Node拒絕特定Pod運行;
    Toleration:為Pod的屬性,表示Pod能容忍(運行)標註了Taint的Node。
    Taint語法:$ kubectl taint node node1 key=value:NoSchedule
    解釋:為node1加上一個Taint,該Taint的鍵為key,值為value,Taint的效果為NoSchedule。即除非特定聲明可以容忍此Taint,否則不會調度至node1上。
    Toleration示例:

      1 tolerations:
      2 - key: "key"
      3   operator: "Equal"
      4   value: "value"
      5   effect: "NoSchedule"

      1 tolerations:
      2 - key: "key"
      3   operator: "Exists"
      4   effect: "NoSchedule"

    注意:Pod的Toleration聲明中的key和effect需要與Taint的設置保持一致,並且滿足以下條件:

    • operator的值是Exists(無須指定value);
    • operator的值是Equal並且value相等;
    • 空的key配合Exists操作符能夠匹配所有的鍵和值;
    • 空的effect匹配所有的effect。


    若不指定operator,則默認值為Equal。
    taint說明:系統允許在同一個Node上設置多個taint,也可以在Pod上設置多個toleration。Kubernetes調度器處理多個taint和toleration的邏輯順序:首先列出節點中所有的taint,然後忽略pod的toleration能夠匹配的部分,剩下的沒有忽略掉的taint就是對pod的效果。以下是幾種特殊情況:
    若剩餘的taint中存在effect=NoSchedule,則調度器不會把該Pod調度到這一節點上;
    若剩餘的taint中沒有NoSchedule效果,但有PreferNoSchedule效果,則調度器會嘗試不把這個Pod指派到此節點;
    若剩餘taint的效果有NoSchedule,並且這個Pod已經在該節點上運行,則會被驅逐,若沒有在該節點上運行,也不會再被調度到該節點上。
    示例:

      1 $ kubectl taint node node1 key=value1:NoSchedule
      2 $ kubectl taint node node1 key=value1:NoExecute
      3 $ kubectl taint node node1 key=value2:NoSchedule
      4 tolerations:
      5 - key: "key1"
      6   operator: "Equal"
      7   value: "value"
      8   effect: "NoSchedule"
      9 tolerations:
     10 - key: "key1"
     11   operator: "Equal"
     12   value: "value1"
     13   effect: "NoExecute"


    釋義:此Pod聲明了兩個容忍,且能匹配Node1的taint,但是由於沒有能匹配第三個taint的toleration,因此此Pod依舊不能調度至此Node。若該Pod已經在node1上運行了,那麼在運行時設置了第3個taint,它還能繼續在node1上運行,這是因為Pod可以容忍前兩個taint。
    通常,若node加上effect=NoExecute的taint,那麼該Node上正在運行的所有無對應toleration的Pod都會被立刻驅逐,而具有相應toleration的Pod則永遠不會被驅逐。同時,系統可以給具有NoExecute效果的toleration加入一個可選的tolerationSeconds字段,表明Pod可以在taint添加到Node之後還能在此Node運行多久。

      1 tolerations:
      2 - key: "key1"
      3   operator: "Equal"
      4   value: "value"
      5   effect: "NoSchedule"
      6   tolerationSeconds: 3600

    釋義:若Pod正在運行,所在節點被加入一個匹配的taint,則這個pod會持續在該節點運行3600s后被驅逐。若在此期限內,taint被移除,則不會觸發驅逐事件。
    Taints和Tolerations常用場景:

    • 獨佔節點:

    給特定的節點運行特定應用。
    $ kubectl taint nodes 【nodename】 dedicated=groupName:NoSchedule
    同時在Pod中設置對應的toleration配合,帶有合適toleration的Pod允許同時使用其他節點一樣使用有taint的節點。

    • 具有特殊硬件設備的節點

    集群中部分特殊硬件(如安裝了GPU),則可以把不需要佔用GPU的Pod禁止在此Node上調度。

      1 $ kubectl taint nodes 【nodename】 special=true:NoSchedule
      2 $ kubectl taint nodes 【nodename】 special=true:PreferNoSchedule

    • 定義Pod驅逐行為

    NoExecute的taint對節點上正在運行的Pod有以下影響:

      1. 沒有設置toleration的pod會被立刻驅逐;
      2. 配置了對應toleration的pod,若沒有為tolerationSeconds賦值,則會一直保留在此節點中;
      3. 配置了對應toleration的pod,且為tolerationSeconds賦值,則在指定時間后驅逐。

    2.6 DaemonSet

    DaemonSet是在每個Node上調度一個Pod的資源對象,用於管理集群中每個Node僅運行一份Pod的副本實例。
    常見場景:
    在每個Node上運行一個GlusterFS存儲的Daemon進程;
    在每個Node上運行一個日誌採集程序,例如Fluentd;
    在每個Node上運行一個性能監控程序,採集該Node的運行性能數據,例如Prometheus。
    示例:

      1 [root@uk8s-m-01 study]# vi fluentd-ds.yaml
      2 apiVersion: extensions/v1beta1
      3 kind: DaemonSet
      4 metadata:
      5   name: fluentd-cloud-logging
      6   namespace: kube-system
      7   labels:
      8     k8s-app: fluentd-cloud-logging
      9 spec:
     10   template:
     11     metadata:
     12       namespace: kube-system
     13       labels:
     14         k8s-app: fluentd-cloud-logging
     15     spec:
     16       containers:
     17       - name: fluentd-cloud-logging
     18         image: gcr.azk8s.cn/google_containers/fluentd-elasticsearch:1.17
     19         resources:
     20           limits:
     21             cpu: 100m
     22             memory: 200Mi
     23         env:
     24         - name: FLUENTD_ARGS
     25           value: -q
     26         volumeMounts:
     27         - name: varlog
     28           mountPath: /var/log
     29           readOnly: false
     30         - name: containers
     31           mountPath: /var/lib/docker/containers
     32           readOnly: false
     33       volumes:
     34       - name: containers
     35         hostPath:
     36           path: /var/lib/docker/containers
     37       - name: varlog
     38         hostPath:
     39           path: /var/log

    2.7 Job批處理調度

    通過Kubernetes Job資源對象可以定義並啟動一個批處理任務,批處理任務通過并行(或者串行)啟動多個計算進程去處理一批工作項。根據批處理方式不同,批處理任務可以分為如下幾種模式:
    Job Template Expansion模式:一個Job對象對應一個待處理的Work item,有幾個work item就產生幾個獨立的Job。通常適合Work item數量少、每個Work item要處理的數據量比較大的場景。
    Queue with Pod Per Work Item模式:採用一個任務隊列存放Work item,一個Job對象作為消費者去完成這些Work item。此模式下,Job會啟動N個Pod,每個Pod都對應一個Work item。
    Queue with Variable Pod Count模式:採用一個任務隊列存放Work item,一個Job對象作為消費者去完成這些Work item,但此模式下Job啟動的數量是可變的。
    Kubernetes將Job氛圍以下三類:

    • Non-parallel Jobs

    通常一個Job只啟動一個Pod,除非Pod異常,才會重啟該Pod,一旦此Pod正常結束,Job將結束。

    • Parallel Jobs with a fixed completion count

    并行Job會啟動多個Pod,此時需要設定Job的.spec.completions參數為一個正數,當正常結束的Pod數量達至此參數設定的值后,Job結束。同時.spec.parallelism參數用來控制并行度,即同時啟動幾個Job來處理Work Item。

    • Parallel Jobs with a work queue

    任務隊列方式的并行Job需要一個獨立的Queue,Work Item都在一個Queue中存放,不能設置Job的.spec.completions參數,此時Job具有以下特性:

      1. 每個Pod都能獨立判斷和決定是否還有任務項需要處理;
      2. 如果某個Pod正常結束,則Job不會再啟動新的Pod;
      3. 如果一個Pod成功結束,則此時應該不存在其他Pod還在工作的情況。它們應該都處於即將結束、退出的狀態;
      4. 如果所有Pod都結束了,且至少有一個Pod成功結束,則整個Jod成功結束。

    2.8 Cronjob定時任務

    表達式:Minutes Hours DayofMonth Month DayofWeek Year
    Minutes:可出現”,”、”_”、”*”、”/”,有效範圍為0~59的整數;
    Hours:出現”,”、”_”、”*”、”/”,有效範圍為0~23的整數;
    DayofMonth:出現”,”、”_”、”*”、”/”、”L”、”W”、”C”,有效範圍為0~31的整數;
    Month:可出現”,”、”_”、”*”、”/”,有效範圍為1~12的整數或JAN~DEC;
    DayofWeek:出現”,”、”_”、”*”、”/”、”L”、”W”、”C”、”#”,有效範圍為1~7的整數或SUN~SAT;
    *: 表示匹配該域的任意值, 假如在Minutes域使用“*”, 則表示每分鐘都會觸發事件。
    /: 表示從起始時間開始觸發, 然後每隔固定時間觸發一次,例如在Minutes域設置為5/20, 則意味着第1次觸發在第5min時, 接下來每20min觸發一次, 將在第25min、 第45min等時刻分別觸發。
    示例:*/1 * * * * #每隔1min執行一次任務

      1 [root@uk8s-m-01 study]# vi cron.yaml
      2 apiVersion: batch/v2alpha1
      3 kind: CronJob
      4 metadata:
      5   name: hello
      6 spec:
      7   schedule: "*/1 * * * *"
      8   jobTemplate:
      9     spec:
     10       template:
     11         spec:
     12           containers:
     13           - name: hello
     14             image: busybox
     15             args:
     16             - /bin/sh
     17             - -c
     18             - date; echo Hello from the Kubernetes cluster
     19           restartPolicy: OnFailure

      1 [root@master study]# kubectl create -f cron.yaml
      2 [root@master study]# kubectl get cronjob hello
      3 NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
      4 hello   */1 * * * *   False     0        <none>          29s
      5 [root@master study]# kubectl get pods
      6 NAME                     READY   STATUS      RESTARTS   AGE
      7 hello-1573378080-zvvm5   0/1     Completed   0          68s
      8 hello-1573378140-9pmwz   0/1     Completed   0          8s
      9 [root@node1 ~]# docker logs c7					#node節點查看日誌
     10 Sun Nov 10 09:31:13 UTC 2019
     11 Hello from the Kubernetes cluster
     12 [root@master study]# kubectl get jobs				#查看任務
     13 NAME               COMPLETIONS   DURATION   AGE
     14 hello-1573378500   1/1           8s         3m7s
     15 hello-1573378560   1/1           4s         2m7s
     16 hello-1573378620   1/1           6s         67s
     17 hello-1573378680   1/1           4s         7s
     18 [root@master study]# kubectl get pods -o wide | grep hello-1573378680	#以job任務查看對應的pod
     19 [root@master study]# kubectl delete cj hello			#刪除cronjob

    2.9 初始化容器

    在很多應用場景中, 應用在啟動之前都需要進行如下初始化操作。

    • 等待其他關聯組件正確運行( 例如數據庫或某個後台服務) 。
    • 基於環境變量或配置模板生成配置文件。
    • 從遠程數據庫獲取本地所需配置, 或者將自身註冊到某个中央數據庫中。
    • 下載相關依賴包, 或者對系統進行一些預配置操作。

    示例:以Nginx應用為例, 在啟動Nginx之前, 通過初始化容器busybox為Nginx創建一個index.html主頁文件。同時init container和Nginx設置了一個共享的Volume, 以供Nginx訪問init container設置的index.html文件。

      1 [root@uk8s-m-01 study]# vi nginx-init-containers.yaml
      2 apiVersion: v1
      3 kind: Pod
      4 metadata:
      5   name: nginx
      6   annotations:
      7 spec:
      8   initContainers:
      9   - name: install
     10     image: busybox
     11     command:
     12     - wget
     13     - "-O"
     14     - "/work-dir/index.html"
     15     - http://kubernetes.io
     16     volumeMounts:
     17     - name: workdir
     18       mountPath: "/work-dir"
     19   containers:
     20   - name: nginx
     21     image: nginx:1.7.9
     22     ports:
     23     - containerPort: 80
     24     volumeMounts:
     25     - name: workdir
     26       mountPath: /usr/share/nginx/html
     27   dnsPolicy: Default
     28   volumes:
     29   - name: workdir
     30     emptyDir: {}

      1 [root@uk8s-m-01 study]# kubectl get pods
      2 NAME    READY   STATUS     RESTARTS   AGE
      3 nginx   0/1     Init:0/1   0          2s
      4 [root@uk8s-m-01 study]# kubectl get pods
      5 NAME    READY   STATUS    RESTARTS   AGE
      6 nginx   1/1     Running   0          13s
      7 [root@uk8s-m-01 study]# kubectl describe pod nginx		#查看事件可知會先創建init容器,名為install


    init容器與應用容器的區別如下。
    (1) init container的運行方式與應用容器不同, 它們必須先於應用容器執行完成, 當設置了多個init container時, 將按順序逐個運行, 並且只有前一個init container運行成功后才能運行后一個init container。 當所有init container都成功運行后, Kubernetes才會初始化Pod的各種信息, 並開始創建和運行應用容器。
    (2) 在init container的定義中也可以設置資源限制、 Volume的使用和安全策略, 等等。 但資源限制的設置與應用容器略有不同。

    • 如果多個init container都定義了資源請求/資源限制, 則取最大的值作為所有init container的資源請求值/資源限制值。
    • Pod的有效(effective) 資源請求值/資源限制值取以下二者中的較大值。
      • 所有應用容器的資源請求值/資源限制值之和。
      • init container的有效資源請求值/資源限制值。
    • 調度算法將基於Pod的有效資源請求值/資源限制值進行計算,即init container可以為初始化操作預留系統資源, 即使後續應用容器無須使用這些資源。
    • Pod的有效QoS等級適用於init container和應用容器。
    • 資源配額和限制將根據Pod的有效資源請求值/資源限制值計算生效。
    • Pod級別的cgroup將基於Pod的有效資源請求/限制, 與調度機制

    一致。
    (3) init container不能設置readinessProbe探針, 因為必須在它們成功運行后才能繼續運行在Pod中定義的普通容器。在Pod重新啟動時, init container將會重新運行, 常見的Pod重啟場景如下。

    • init container的鏡像被更新時, init container將會重新運行, 導致Pod重啟。 僅更新應用容器的鏡像只會使得應用容器被重啟。
    • Pod的infrastructure容器更新時, Pod將會重啟。
    • 若Pod中的所有應用容器都終止了, 並且RestartPolicy=Always, 則Pod會重啟。

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

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

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

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

    小三通海運與一般國際貿易有何不同?

    小三通快遞通關作業有哪些?

  • Spring Boot2 系列教程(二十四)Spring Boot 整合 Jpa

    Spring Boot2 系列教程(二十四)Spring Boot 整合 Jpa

    Spring Boot 中的數據持久化方案前面給大夥介紹了兩種了,一個是 JdbcTemplate,還有一個 MyBatis,JdbcTemplate 配置簡單,使用也簡單,但是功能也非常有限,MyBatis 則比較靈活,功能也很強大,據我所知,公司採用 MyBatis 做數據持久化的相當多,但是 MyBatis 並不是唯一的解決方案,除了 MyBatis 之外,還有另外一個東西,那就是 Jpa,松哥也有一些朋友在公司里使用 Jpa 來做數據持久化,本文就和大夥來說說 Jpa 如何實現數據持久化。

    Jpa 介紹

    首先需要向大夥介紹一下 Jpa,Jpa(Java Persistence API)Java 持久化 API,它是一套 ORM 規範,而不是具體的實現,Jpa 的江湖地位類似於 JDBC,只提供規範,所有的數據庫廠商提供實現(即具體的數據庫驅動),Java 領域,小夥伴們熟知的 ORM 框架可能主要是 Hibernate,實際上,除了 Hibernate 之外,還有很多其他的 ORM 框架,例如:

    • Batoo JPA
    • DataNucleus (formerly JPOX)
    • EclipseLink (formerly Oracle TopLink)
    • IBM, for WebSphere Application Server
    • JBoss with Hibernate
    • Kundera
    • ObjectDB
    • OpenJPA
    • OrientDB from Orient Technologies
    • Versant Corporation JPA (not relational, object database)

    Hibernate 只是 ORM 框架的一種,上面列出來的 ORM 框架都是支持 JPA2.0 規範的 ORM 框架。既然它是一個規範,不是具體的實現,那麼必然就不能直接使用(類似於 JDBC 不能直接使用,必須要加了驅動才能用),我們使用的是具體的實現,在這裏我們採用的實現實際上還是 Hibernate。

    Spring Boot 中使用的 Jpa 實際上是 Spring Data Jpa,Spring Data 是 Spring 家族的一個子項目,用於簡化 SQL、NoSQL 的訪問,在 Spring Data 中,只要你的方法名稱符合規範,它就知道你想幹嘛,不需要自己再去寫 SQL。

    關於 Spring Data Jpa 的具體情況,大家可以參考

    工程創建

    創建 Spring Boot 工程,添加 Web、Jpa 以及 MySQL 驅動依賴,如下:

    工程創建好之後,添加 Druid 依賴,完整的依賴如下:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.28</version>
        <scope>runtime</scope>
    </dependency>

    如此,工程就算創建成功了。

    基本配置

    工程創建完成后,只需要在 application.properties 中進行數據庫基本信息配置以及 Jpa 基本配置,如下:

    # 數據庫的基本配置
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.url=jdbc:mysql:///test01?useUnicode=true&characterEncoding=UTF-8
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    
    # JPA配置
    spring.jpa.database=mysql
    # 在控制台打印SQL
    spring.jpa.show-sql=true
    # 數據庫平台
    spring.jpa.database-platform=mysql
    # 每次啟動項目時,數據庫初始化策略
    spring.jpa.hibernate.ddl-auto=update
    # 指定默認的存儲引擎為InnoDB
    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

    注意這裏和 JdbcTemplate 以及 MyBatis 比起來,多了 Jpa 配置,Jpa 配置含義我都註釋在代碼中了,這裏不再贅述,需要強調的是,最後一行配置,默認情況下,自動創建表的時候會使用 MyISAM 做表的引擎,如果配置了數據庫方言為 MySQL57Dialect,則使用 InnoDB 做表的引擎。

    好了,配置完成后,我們的 Jpa 差不多就可以開始用了。

    基本用法

    ORM(Object Relational Mapping) 框架表示對象關係映射,使用 ORM 框架我們不必再去創建表,框架會自動根據當前項目中的實體類創建相應的數據表。因此,我這裏首先創建一個 User 對象,如下:

    @Entity(name = "t_user")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;
        @Column(name = "name")
        private String username;
        private String address;
        //省略getter/setter
    }

    首先 @Entity 註解表示這是一個實體類,那麼在項目啟動時會自動針對該類生成一張表,默認的表名為類名,@Entity 註解的 name 屬性表示自定義生成的表名。@Id 註解表示這個字段是一個 id,@GeneratedValue 註解表示主鍵的自增長策略,對於類中的其他屬性,默認都會根據屬性名在表中生成相應的字段,字段名和屬性名相同,如果開發者想要對字段進行定製,可以使用 @Column 註解,去配置字段的名稱,長度,是否為空等等。

    做完這一切之後,啟動 Spring Boot 項目,就會發現數據庫中多了一個名為 t_user 的表了。

    針對該表的操作,則需要我們提供一個 Repository,如下:

    public interface UserDao extends JpaRepository<User,Integer> {
        List<User> getUserByAddressEqualsAndIdLessThanEqual(String address, Integer id);
        @Query(value = "select * from t_user where id=(select max(id) from t_user)",nativeQuery = true)
        User maxIdUser();
    }

    這裏,自定義 UserDao 接口繼承自 JpaRepository,JpaRepository 提供了一些基本的數據操作方法,例如保存,更新,刪除,分頁查詢等,開發者也可以在接口中自己聲明相關的方法,只需要方法名稱符合規範即可,在 Spring Data 中,只要按照既定的規範命名方法,Spring Data Jpa 就知道你想幹嘛,這樣就不用寫 SQL 了,那麼規範是什麼呢?參考下圖:

    當然,這種方法命名主要是針對查詢,但是一些特殊需求,可能並不能通過這種方式解決,例如想要查詢 id 最大的用戶,這時就需要開發者自定義查詢 SQL 了。

    如上代碼所示,自定義查詢 SQL,使用 @Query 註解,在註解中寫自己的 SQL,默認使用的查詢語言不是 SQL,而是 JPQL,這是一種數據庫平台無關的面向對象的查詢語言,有點定位類似於 Hibernate 中的 HQL,在 @Query 註解中設置 nativeQuery 屬性為 true 則表示使用原生查詢,即大夥所熟悉的 SQL。上面代碼中的只是一個很簡單的例子,還有其他一些點,例如如果這個方法中的 SQL 涉及到數據操作,則需要使用 @Modifying 註解。

    好了,定義完 Dao 之後,接下來就可以將 UserDao 注入到 Controller 中進行測試了(這裏為了省事,就沒有提供 Service 了,直接將 UserDao 注入到 Controller 中)。

    @RestController
    public class UserController {
        @Autowired
        UserDao userDao;
        @PostMapping("/")
        public void addUser() {
            User user = new User();
            user.setId(1);
            user.setUsername("張三");
            user.setAddress("深圳");
            userDao.save(user);
        }
        @DeleteMapping("/")
        public void deleteById() {
            userDao.deleteById(1);
        }
        @PutMapping("/")
        public void updateUser() {
            User user = userDao.getOne(1);
            user.setUsername("李四");
            userDao.flush();
        }
        @GetMapping("/test1")
        public void test1() {
            List<User> all = userDao.findAll();
            System.out.println(all);
        }
        @GetMapping("/test2")
        public void test2() {
            List<User> list = userDao.getUserByAddressEqualsAndIdLessThanEqual("廣州", 2);
            System.out.println(list);
        }
        @GetMapping("/test3")
        public void test3() {
            User user = userDao.maxIdUser();
            System.out.println(user);
        }
    }
    

    如此之後,即可查詢到需要的數據。

    好了,本文的重點是 Spring Boot 和 Jpa 的整合,這個話題就先說到這裏。

    多說兩句

    在和 Spring 框架整合時,如果用到 ORM 框架,大部分人可能都是首選 Hibernate,實際上,在和 Spring+SpringMVC 整合時,也可以選擇 Spring Data Jpa 做數據持久化方案,用法和本文所述基本是一樣的,Spring Boot 只是將 Spring Data Jpa 的配置簡化了,因此,很多初學者對 Spring Data Jpa 覺得很神奇,但是又覺得無從下手,其實,此時可以回到 Spring 框架,先去學習 Jpa,再去學習 Spring Data Jpa,這是給初學者的一點建議。

    相關案例已經上傳到 GitHub,歡迎小夥伴們們下載:

    掃碼關注松哥,公眾號後台回復 2TB,獲取松哥獨家 超2TB 學習資源

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

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    小三通物流營運型態?

    ※快速運回,大陸空運推薦?

  • 從最近面試聊聊我所感受的職業天花板

    ## 特別特別嚴肅的申明 (正經的)

    未免引起誤解,標題已修改。

    我一開始寫這篇文章,也純粹是有感而發。實在沒想到會引起如此多的關注。甚至還被社區大佬翻牌。說實話,誠惶誠恐。

    再次申明一遍,我寫的也僅僅只是我個人的感受,我就是萬萬千千的普通碼農中的一個,所寫文章也僅僅是從自我角度出發。

    不具備任何普適性參考性。請大家看清標題,只是個人感受,不適用.net整個行業。尤其請大家不要拿我的經歷作為語言選擇的參考。

    。net也好,java也好,每個語言都有自己的生態,選擇語言之前請先確認自己的能力,請不要抱怨語言害了你,請先審視自己是否一直在努力進步,還是只是在隨大流。

    博主就是一個普通碼農,太高端的層面很難觸及,找工作的途徑也只有朋友內推和招聘網站。

    那麼我在這兩種途徑下所接觸到的信息,就是我目前的薪資已經到了這兩種渠道下的頂薪。所以,我自我感覺是我現在觸到我的天花板。

    那麼我向上突破的方法,要麼向社區大佬學習,努力突破到那個圈子,但是對於這個自己實在沒底,大佬的圈子太高,感覺自己能力不夠,對自己實在沒信心。

    第二種就是多語言發展,修鍊技術內功,管理內功,我覺着在努努力踮踮腳還是能夠到30K、40K月薪的小尾巴。

    最後奉勸各位園友,語言從來都不是決定自己前途的關鍵因素,更多的還是要修鍊自己的內功不斷向上突破。

    博主寫這篇文章的初衷只是想表述自己目前所面臨的職業困境,實在沒想到會有如此多的關注,用詞上的不當,給大家造成困擾,萬分抱歉。

     

    #0 前言

    入職新公司沒多久,閑來無事在博客園閑逛,看到園友分享的面試經歷,正好自己這段時間面試找工作,也挺多感想的,乾脆趁這個機會總結整理一下。

    博主13年開始實習,14年畢業。到現在也工作五六年了。今年面試最大的感受就是觸及了.net的天花板。坐標,杭州。

     #1 背景

    今年九月份從一家創業公司離職,原因么自然是公司創業失敗倒閉。

    當初以技術合伙人的身份進入,雄心勃勃,然後挨了一頓社會毒打,從此老實做人,面朝黃土背朝天,老老實實去搬磚。

    九月份出來,已經是中旬,開始刷新簡歷,準備穩坐釣魚台,等着電話信息轟炸。然後,等了两天,等了一首涼涼。直到這個時候博主才意識到,形式不對。

    我的思維還停留在兩三年前,工 作遍地,只要更新下簡歷就會有無數的面試邀請。同志門,情況變了呀,行業寒冬真不只是說說而已。

    沒辦法,只好花錢,刷新下簡歷,瀏覽崗位,主動出擊。中間接到了好幾個獵頭電話, 但特么都是java。好想吐槽一下,簡歷上.net辣么大的字,你們真的不識字么,21世紀了啊喂。

    #2 某建築類軟件公司

    主營業務:建築軟件,公司已上市。

    技術框架:.net平台,具體的不是特別了解

    招聘崗位:.net高級開發工程師

    面試:一共四輪面試。

    第一輪:就是HR了,簡單聊了下情況,為什麼離職,之前薪資多少,期望薪資多少。

    第二輪:他們某業務線的部門經理和技術主管共同面試。

    基本面試情況就是我在說他們在聽,我主要講解了項目的設計方案,使用的技術,遇到的困難,最終的解決方案。

    技術面試官就問了兩個問題,一是從.net升級到netcore中間碰到過哪些問題。

    第二個基於rabbitmq的分佈式事務是怎麼做的。

    然後他們部門經理問了些團隊管理的問題。如何做團隊成員的任務分配,有團隊成員向你提出離職或者漲薪你怎麼處理,團隊的代碼質量如果管控

    第三輪:他們的CTO,然後開始又是自我介紹。

    只好把之前的又重複一遍,巴拉巴拉。最後就問了一個分佈式事務的解決方案有那些,平時是怎麼使用的。

    最後聊了一下我的定位,就是進去是負責他們的平台架構,包括一些公用業務的架構封裝,老架構的netcore升級

    第四輪:最後是他們的公司董事長,上來又是先自我介紹。然後問了下職業規劃。

    接着就是拿着我的簡歷說這個工作跳動比較頻繁,尤其是從上一家比較大的公司跳槽到一個創業公司是基於一個什麼樣的考慮呢,感覺個人穩定性和職業性規劃都不夠。

    博主當時內心的os是黑人問號臉??????我能是基於什麼樣的考慮,我為了世界和平好不好。

    然後被大佬教育了一頓,灌輸了一些個人和公司共同體,什麼共贏發展什麼共同成長的理念。

    結果:通過,HR小姐姐來談薪資。

    只能給到20K,然後還是18k基本工資+2K的級別補貼,說是我進去之後定的級別是T3,

    然後每年三四月份和九十月份可以申請調薪調級,強制要求995?????? 我特么跳槽不漲薪就算了你還給我降薪,還995,PASS。

    #3 某醫美集團下轄子公司

    主營業務:醫美行業的sass軟件

    技術框架:GRPC

    面試:一輪,技術主管。

    招聘崗位:.net架構師

    主要問題:依賴注入的生命周期,在框架設計中的應用場景有那些。

    在技術選型時主要考慮的因素。

    在框架設計時會應用到那些設計模式,主要應用場景是什麼。

    對於netcore中間件的理解。

    應對系統高併發的解決方案。

    聊一聊對微服務的理解,基於netcore的微服務架構是怎麼設計的。

    面試結果:通過。但薪資只有20K,哎呦喂,你都對不起你招聘崗位的名字呀。

    #4 某物業管理軟件公司

    主營業務:做小區物業管理軟件,公司兩百多人。

    技術框架:.net mvc 三層

    招聘崗位:.net副總監

    面試:一輪。總監面試,但是木有問任何技術問題,也木有問任何團隊管理問題。逮者我之前的離職原因各種問。

    面試結果:未通過。一臉懵逼的出來,都不知道為啥沒通過。老子也是信了你的邪。

    #5 某電商初創企業。

    主營業務:拍賣類的電商平台。公司是初創,技術團隊都沒組建完整。

    面試:兩輪。

    第一輪是他們的一個技術負責人,只是看看了簡歷,然後問了一個讓我哭笑不得問題,就是如果你進入公司,發現周圍人技術都比較菜的時候,你是不是會看不起別人。 笑哭!!!

    第二輪是老闆,老闆就是主要負責畫大餅,聊前景,聊機遇。

    結果:通過。工資待遇給到稅前24K。

    但是我了解到老闆之前做互金,然後平台清盤。具體情況不清楚,大佬,惹不起,躲了躲了。

    在這裏一定奉勸各位園友,互金平台或者老闆有互金背景的千萬小心。

    我身邊已經不少朋友,被坑到,即使現在沒事,也說不定什麼時候就會被警察找上門。

    就有朋友,剛入職公司沒多久,而且公司業務也不是做互金的,結果沒幾天,警察上門,老闆帶走就因為老闆之前做互金,還是出事兒了。

    #6 某社交類公司

    主營業務:付費社交app,主打東南亞市場

    技術框架:.net 三層

    招聘崗位:.net高級開發工程師

    面試:三輪。

    第一輪:部門的CTO面試,互相聊得挺愉快。

    主要問了之前的項目微服務怎麼做的,服務拆分的粒度怎麼規劃,整個服務的架構怎麼規劃用到哪些技術。

    然後問了數據庫方面的分庫分表怎麼做的,用的什麼中間件,分庫分表後主鍵id如何生成。

    應對高併發架構上是怎麼處理的。如何保證redis的高併發高可用。面對緩存穿透、雪崩、擊穿怎麼解決的。

    消息隊列的高可用、消息的冪等性,面對消息積壓如何處理。

    接着就是聊團隊管理,還是人員管理,任務分配,質量保證這些問題。

    接手一個新團隊后如何摸清各成員能力,不同能力的人工作上應該怎麼安排。

    還有一個,就是你作為團隊主管你的工作時間是碎片化的,但同時你作為技術leader又要把控技術方案,而做技術是需要時間的連續性,你如何協調這兩者之間的衝突。

    挺有意思,只有技術管理一肩挑的團隊才會遇到這種問題了。

    最後介紹了一下團隊目前的組織架構,技術方向。嗯,要做.net升級,要做微服務。嗯,最後要轉java。誒,是不是有什麼奇怪的東西,.netcore它不香么。

    第二輪:人事面試。嗯,就是問問離職原因,然後介紹了下公司業務發展,前景規劃,入職后的主要工作職能,然後談了下期望薪資。

    第三輪:boos面。老闆,沒問什麼問題,就是聊了聊職業規劃,然後么他介紹公司發展方向,前景規劃,我作為一個負責任的捧哏, 當然舔着嘍。

    面試結果:通過。薪資談到稅前24K。但五險一金都是最低標準繳納。年終獎說是0到12個月,看績效。

    #7 某汽車製造公司的外包崗

    面試:外包公司有個技術經理做了一個簡單電話面試。然後就約着到甲方的公司進行面試。面試兩輪,是甲方的兩個平台架構師。問題都大同小異,不贅述了。

    面試結果:通過。但博主內心相當糾結,因為對於外包,網上實在是沒有好的評價,但是和兩個面試官聊得蠻愉快。

    當初去面試了,也純粹是因為好奇,反正當時面試邀請也少,閑着也是閑着么。

    薪資談到23k,對方說還是走了一個特別申請,甲方那邊兒再高給不了。五險一金都是最低標準。

    但是HR說這個崗位是甲方為了儲備人才招聘的,我當天面試過後,甲方就把這個崗位招聘關了,只招我一個,等到明年三四月份內部編製出來,我是妥妥轉到甲方。

    而且進去之後的工作也是和面試我的那個架構師一起工作,負責他們平台架構規劃。

    一開始去面試之前我都說了工資要求和最低標準,滿口說沒問題,結果面試完了就又不行了。你個糟老頭子,壞的很,我信你個鬼。

    #8 寫在最後

      中間也還有面試有其他幾家公司,套路問題都差不多,就不在寫出來了。找工作一共花費兩周時間,面試了也有八九家,但真正能給到期望工資的就那麼兩三家。這之間自己在網上主動投遞過,但基本都沒有回信。兩周過去,在回過頭來看,卻發現網上再找不到其他合適的崗位了,不是已經面試過,就是投遞了沒反應。到最後發現,我能選擇的就只有那麼幾家公司。而且,最嚴重的一個感受就是,我翻遍了所有的招聘網站,我目前所要的工資,已經是.net行業的天花板,往上沒有空間了。.net高級開發也好、.net架構師也好、技術經理也罷,能給到工資25K就已經是到頂了,而且崗位特別少。然後做cs方向的,價格開的比bs方向的還能高一些,頂薪能到三萬。做服務的.net被java搶佔了太多市場,即便有很多公司,初期是用.net做的,即便現在netcore已經跨平台,但公司做微服務還是要轉java,我真的好想問一句netcore它不香么,vs它不香么,都咋想的。

    #9 尾篇

      最後的最後。整理一下博主在做netcore微服務所用到的相關技術,做個整體的總結。後續會一點一點具體介紹,希望能形成一個系列,希望最後能堅持寫完。

      服務註冊/發現:consul或zookeeper,各有優劣,個人傾向consul

      分佈式通訊:restful api形式或rpc。

      分佈式事件總線:推薦使用cap。cap同時支持 RabbitMQ,Kafka,Azure Service Bus 等進行底層之間的消息發送,同時內置了TCC實現。

           網關、熔斷、降級、限流:ocelot網關,應該是當下netcore平台下最火熱的網關開源項目了。同時集成了polly來滿足熔斷、降級、限流的功能要求。

      配置中心:攜程的開源項目Apollo。博主之前是為了業務需求自己寫的,不具通用性。

      微服務監控:分佈式調用鏈跟蹤zipkin和skywalking,同時還可監控服務性能。推薦使用skywalking,對代碼無侵入。

            日誌監控ELK,這個不需要多介紹了,文章太多了。

      持續集成自動部署:GitLab+Jenkins+k8s

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

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包"嚨底家"

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

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

    小三通海運與一般國際貿易有何不同?

    小三通快遞通關作業有哪些?

  • .NET Core 3 WPF MVVM框架 Prism系列之數據綁定

    .NET Core 3 WPF MVVM框架 Prism系列之數據綁定

     一.安裝Prism

     

    1.使用程序包管理控制台

    Install-Package Prism.Unity -Version 7.2.0.1367

    也可以去掉‘-Version 7.2.0.1367’獲取最新的版本

     2.使用管理解決方案的Nuget包

     

    在上面或許我們有個疑問?為啥安裝prism會跟Prism.Unity有關係,我們知道Unity是個IOC容器,而Prism本身就支持IOC,且目前官方支持幾種IOC容器:

    1.且unity由於是微軟官方的,且支持prism的組件化,由此我推薦使用prism.unity,在官方文檔中prism7不支持prism.Mef,Prism 7.1將不支持prism.Autofac 2.安裝完prism.unity就已經包含着所有prism的核心庫了,架構如下:

    二.實現數據綁定

    我們先創建Views文件夾和ViewModels文件夾,將MainWindow放在Views文件夾下,再在ViewModels文件夾下面創建MainWindowViewModel類,如下:

     

    xmal代碼如下:

    <Window x:Class="PrismSample.Views.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:prism="http://prismlibrary.com/"
            xmlns:local="clr-namespace:PrismSample"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800" prism:ViewModelLocator.AutoWireViewModel="True">
        <StackPanel>
            <TextBox Text="{Binding Text}" Margin="10" Height="100" FontSize="50" Foreground="Black" BorderBrush="Black"/>
            <Button  Height="100" Width="300" Content="Click Me" FontSize="50" Command="{Binding ClickCommnd}"/>
        </StackPanel>
    </Window>

     

    ViewModel代碼如下:

    using Prism.Commands;
    using Prism.Mvvm;
    
    namespace PrismSample.ViewModels
    {
       public class MainWindowViewModel:BindableBase
        {
            private string _text;
            public string Text
            {
                get { return _text; }
                set { SetProperty(ref _text, value); }
            }
    
            private DelegateCommand _clickCommnd;
            public DelegateCommand ClickCommnd =>
                _clickCommnd ?? (_clickCommnd = new DelegateCommand(ExecuteClickCommnd));
    
            void ExecuteClickCommnd()
            {
                this.Text = "Click Me!";
            }
    
            public MainWindowViewModel()
            {
                this.Text = "Hello Prism!";
            }
        }
    }

     

    啟動程序:

      點擊 click Me 按鈕:

    可以看到,我們已經成功的用prism實現數據綁定了,且View和ViewModel完美的前後端分離

    但是現在我們又引出了另外一個問題,當我們不想按照prism的規定硬要將View和ViewModel放在Views和ViewModels裏面,又或許自己的項目取名規則各不相同怎麼辦,這時候就要用到另外幾種方法:

    1.更改命名規則

    如果,公司命名規則很變態,導致項目結構變成這樣(這種公司辭職了算了):

    首先我們在App需要引入prism,修改‘Application’為‘prism:PrismApplication’且刪除StartupUri xmal代碼如下:  

    <prism:PrismApplication x:Class="PrismSample.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:prism="http://prismlibrary.com/"
                 xmlns:local="clr-namespace:PrismSample">
        <Application.Resources>
             
        </Application.Resources>
    </prism:PrismApplication>

      cs後台代碼如下:

    using Prism.Unity;
    using Prism.Ioc;
    using Prism.Mvvm;
    using System.Windows;
    using PrismSample.Viewsb;
    using System;
    using System.Reflection;
    
    namespace PrismSample
    {
        /// <summary>
        /// Interaction logic for App.xaml
        /// </summary>
        public partial class App : PrismApplication
        {
            //設置啟動起始頁
            protected override Window CreateShell()
            {
                return Container.Resolve<MainWindow>();
            }
    
            protected override void RegisterTypes(IContainerRegistry containerRegistry)
            {
    
            }
    
            //配置規則
            protected override void ConfigureViewModelLocator()
            {
                base.ConfigureViewModelLocator();
                ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
                {
                    var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");
                    var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
                    var viewModelName = $"{viewName}Test, {viewAssemblyName}";
                    return Type.GetType(viewModelName);
                });
            }
        }
    }

     

    上面這兩句是關鍵:

    “.Viewsb.” 表示View所在文件夾namespace,”.ViewModelsa.OhMyGod.” 表示ViewModel所在namespace

    var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");
    

      

    Test表示ViewModel後綴

    var viewModelName = $"{viewName}Test, {viewAssemblyName}";

     

    2.自定義ViewModel註冊

    我們新建一個Foo類作為自定義類,代碼如下:

    using Prism.Commands;
    using Prism.Mvvm;
    
    namespace PrismSample
    {
       public class Foo:BindableBase
        {
    
            private string _text;
            public string Text
            {
                get { return _text; }
                set { SetProperty(ref _text, value); }
            }
    
            public Foo()
            {
                this.Text = "Foo";
            }
    
            private DelegateCommand _clickCommnd;
            public DelegateCommand ClickCommnd =>
                _clickCommnd ?? (_clickCommnd = new DelegateCommand(ExecuteClickCommnd));
    
            void ExecuteClickCommnd()
            {
                this.Text = "Oh My God!";
            }
        }
    }

     

    修改App.cs代碼:

    protected override void ConfigureViewModelLocator()
            {
                base.ConfigureViewModelLocator();
                ViewModelLocationProvider.Register<MainWindow, Foo>();
                //ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
                //{
                //    var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");
                //    var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
                //    var viewModelName = $"{viewName}Test, {viewAssemblyName}";
                //    return Type.GetType(viewModelName);
                //});
            }

     

      運行:   點擊按鈕:  

    就算是不註釋修改命名規則的代碼,我們發現運行結果還是一樣,因此我們可以得出結論,

    這種直接的,不通過反射註冊的自定義註冊方式優先級會高點,在官方文檔也說明這種方式效率會高點

    且官方提供4種方式,其餘三種的註冊方式如下:

    ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(MainWindowTest)); 
    ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), () => Container.Resolve<Foo>());
    ViewModelLocationProvider.Register<MainWindow>(() => Container.Resolve<Foo>());

     

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

    【其他文章推薦】

    ※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

    ※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

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

    ※帶您來看台北網站建置台北網頁設計,各種案例分享

    小三通物流營運型態?

    ※快速運回,大陸空運推薦?

  • Java開發者學習技術體系

    Java開發者學習技術體系

    01基礎技術體系

    我認為知識技能體系化是判斷技術是否過關的第一步。知識體系化包含兩層含義:

    1、 能夠知道技術知識圖譜(高清版圖譜掃文末二維碼)的內容

    比如分佈式系統中常用的RPC技術,其背後就涉及到網絡IO(Netty)、網絡協議、服務發現(Zookeeper配置中心)、RPC服務治理(限流、熔斷、降級)、負載均衡等。

    2、 能夠理清各類技術概念之間的區別和聯繫

    在分佈式系統領域中,有很多相似的概念,但又分佈在不同的產品或層級中。比如負載均衡這個詞,DNS、LVS、Ngnix、F5等產品都能實現,而且在大型分佈式系統中他們會同時存在,那麼就要搞清楚他們各自的位於什麼層級,解決了什麼問題。

    再比如緩存這項技術,有分佈式緩存、本地緩存、數據庫緩存,在往下還有硬件層級的緩存。同樣都是緩存,他們之間的區別又是什麼?

    如果你仔細去觀察,大廠的後端開發工程師總是能對整個技術體系了如指掌,從而在系統設計與技術選型階段就能夠做出較為合理的架構。 

    02實踐經驗的積累

           能否快速解決實戰中的業務問題是判斷技術是否過關的第二步。
           大家在面試的過程中,都會有一種體會:我的知識體系已經建立了,但在回答面試官問題的時候,總感覺像在背答案,而且也沒有辦法針對性的回答面試官問題。比如在面試官問到這些問題時:

    1. 我們知道消息隊列可應用於耦系統,應對異步消費等場景,那如何在網絡不可靠的場景下保證業務數據處理的正確性?
    2. 我們都知道在分佈式系統會用到緩存,那該如何設置緩存失效機制才能避免系統出現緩存雪崩?
    3. 我們都或多或少的知道系統發布上線的流程,但在大流量場景下採用何種發布機制才能盡可能的做到平滑?

    能完善的解決這些問題是區分一個程序員是否有經驗的重要標誌,知識的體系化是可以從書本不斷的凝練來獲得,但經驗的積累需要通過實戰的不斷總結

    對很多人來說很為難的一點是,平時寫着的業務代碼,很少有機會接觸到大廠的優秀實踐,那麼這時候更需要從如下兩個角度逼問:

    1、當流量規模再提高几個量級,那麼我的系統會出現什麼問題?

    2、假如其中一個環節出現了問題,那麼該怎麼保證系統的穩定性?

    03技術的原理

    上面的提到都是將技術用於業務實踐,以及高效的解決業務中出現的問題。但這是否就意味着自己的技術已經過關了呢?我認為還不能。

    判斷技術是否過關的第三步是能否洞察技術背後的設計思想和原理。

    如果你參加過一些大廠面試,還會問到一些開放性的問題:

    1、 寫一段程序,讓其運行時的表現為觸發了5次Young GC、3次Full GC、然後3次Young GC;

    2、 如果一個Java進程突然消失了,你會怎麼去排查這種問題?

    3、 給了一段Spring加載Bean的代碼片段,闡述一下具體的執行流程?

           是不是看上去很難,是不是和自己準備的“題庫”中的問題不一樣?不知道從何處下手?如果你有這種感覺,那麼說明你的技術還需要繼續修鍊。

           你要明白的是這種開放性的問題,提問的角度千變萬化,但最終落腳點卻都是基本原理。如果你不了解GC的觸發條件,你就肯定無法答出第一題;同樣,如果你對Spring啟動機制了解的很清楚,那麼無論他給出的是什麼樣的代碼,你都能回答出代碼經歷的過程。如果你能以不變應萬變,那麼恭喜你,你的技術過關了。

           上面提到了很多技術問題,這裏我不做詳細的解釋,都能在下面的技術圖譜中找到答案:

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

    【其他文章推薦】

    台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

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

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