Prometheus 介紹

Prometheus 簡介

我們在 SoundCloud 的官方博客中可以找到一篇關於他們爲什麼需要新開發一個監控系統的文章 Prometheus: Monitoring at SoundCloud,在這篇文章中,他們介紹到,他們需要的監控系統必須滿足下面四個特性:

簡單來說,就是下面四個特性:

  • 多維度數據模型
  • 方便的部署和維護
  • 靈活的數據採集
  • 強大的查詢語言

實際上,多維度數據模型和強大的查詢語言這兩個特性,正是時序數據庫所要求的,所以 Prometheus 不僅僅是一個監控系統,同時也是一個時序數據庫。那爲什麼 Prometheus 不直接使用現有的時序數據庫作爲後端存儲呢?這是因爲 SoundCloud 不僅希望他們的監控系統有着時序數據庫的特點,而且還需要部署和維護非常方便。

此外,Prometheus 數據採集方式也非常靈活。要採集目標的監控數據,首先需要在目標處安裝數據採集組件,這被稱之爲 Exporter,它會在目標處收集監控數據,並暴露出一個 HTTP 接口供 Prometheus 查詢,Prometheus 通過 Pull 的方式來採集數據,這和傳統的 Push 模式不同。

不過 Prometheus 也提供了一種方式來支持 Push 模式,你可以將你的數據推送到 Push Gateway,Prometheus 通過 Pull 的方式從 Push Gateway 獲取數據。目前的 Exporter 已經可以採集絕大多數的第三方數據,比如 Docker、HAProxy、StatsD、JMX 等等,官網有一份 Exporter 的列表。

Prometheus 的整體架構圖


從上圖可以看出,Prometheus 生態系統包含了幾個關鍵的組件:Prometheus server、Pushgateway、Alertmanager、Web UI 等,但是大多數組件都不是必需的,其中最核心的組件當然是 Prometheus server,它負責收集和存儲指標數據,支持表達式查詢,和告警的生成。

使用 Prometheus自定義指標為 Kubernetes 做 HPA 縮放

使用套件

  1. Prometheus
  2. Prometheus Operator
  3. K8S
  4. Rancher

步驟一、設定自訂義指標

1. 設定Exporter,這邊有許多官方提供的函式庫
https://prometheus.io/docs/instrumenting/clientlibs/
2. 設定該export的service名為my-export

apiVersion: v1
kind: Service
metadata:
  labels:
    app: my-export
  name: my-export
  namespace: default
spec:
  clusterIP: None
  clusterIPs:
  - None
  ports:
  - name: my-export
    port: 7979
    protocol: TCP
    targetPort: 7979
  selector:
    prometheus-customized-metrix: my-export
  type: ClusterIP

設定Service Monitors

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  labels:
    app: my-export
  name: my-export
  namespace: default
spec:
  endpoints:
  - interval: 30s
    params:
      module:
      - default
      target:
      - http://127.0.0.1:1985/api/v1/streams/
    path: /probe
    port: my-export
  jobLabel: jobLabel
  namespaceSelector:
    matchNames:
    - default
  selector:
    matchLabels:
      app: my-export

步驟二、設定自訂義規則

增加Prometheus Rules

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    app: rancher-monitoring
    app.kubernetes.io/instance: rancher-monitoring
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/part-of: rancher-monitoring
    app.kubernetes.io/version: 16.6.1_up16.6.0
    chart: rancher-monitoring-16.6.1_up16.6.0
    heritage: Helm
    release: rancher-monitoring
  name: my-data
  namespace: default
spec:
  groups:
  - name: my-data
    rules:
    - expr: sum(mydata{container="my-container", name=~".+",namespace=~"default"})
        by (pod)
      labels:
        namespace: default
        service: eventqueue
      record: mydata

設定HPA

在HorizontalPodAutoscaler增加一個設定如下

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: my-hpa
  namespace: default
spec:
  behavior:
    scaleDown:
      policies:
      - periodSeconds: 60
        type: Pods
        value: 1
      selectPolicy: Max
      stabilizationWindowSeconds: 300
    scaleUp:
      policies:
      - periodSeconds: 60
        type: Pods
        value: 1
      selectPolicy: Max
      stabilizationWindowSeconds: 300
  maxReplicas: 2
  metrics:
  - object:
      describedObject:
        apiVersion: v1
        kind: Service
        name: eventqueue
      metric:
        name: mydata
      target:
        type: Value
        value: 1k
    type: Object
  minReplicas: 1
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-container

參考資料

  1. https://docs.openshift.com/container-platform/4.9/nodes/pods/nodes-pods-autoscaling.html
  2. https://www.padok.fr/en/blog/scaling-prometheus-rabbitmq

K8S裡CPU和MEMORY的計算單位

如何獲取和讀取 K8s 的資源利用率指標

在K8S裡面我們可以對資源做resource isolation,限制pod所使用的資源或者設立HPA去決定何時要自動擴展/縮小

所以要了解一下K8S裡面所用的度量單位的意義

使用kubectl下指令讀取pod內資源使用狀況

kubectl top pod srs-core1-dbbb776bd-5s9rz -n srs3
會得到下面的回應
NAME CPU(cores) MEMORY(bytes)
srs-core1-dbbb776bd-5s9rz 3m 73Mi

確認Pod裡面不同的Container所使用的資源
kubectl top pod srs-core1-dbbb776bd-5s9rz -n srs3 –containers
會得到以下回應
POD NAME CPU(cores) MEMORY(bytes)
srs-core1-dbbb776bd-5s9rz filebeat 1m 60Mi
srs-core1-dbbb776bd-5s9rz json-exporter 2m 7Mi
srs-core1-dbbb776bd-5s9rz logrotate 1m 0Mi
srs-core1-dbbb776bd-5s9rz srs-core1 1m 5Mi

取得Node資訊

kubectl top node qatk8sworker01 -n srs3
會得到以下回應
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
qatk8sworker01 1280m 32% 3713Mi 48%

了解指標所代表的意思 – CPU

其中設定的單位是 m,每 1000m = 1 vCore,也可以使用分數,因此設定的方式可以是:

  • 1 (相當於 1000m)
  • 0.5 (相當於 500m)
  • 300m (相當於 0.3)

從上面取得node的直可以看到CPU的資訊是
1280m 32%
代表總共有4000m = 4 Core CPU
PS:設定 1m 是不被允許的,官方建議最低從 100m 開始

了解指標所代表的意思 – Memory

Memory 設定的單位最低則是從 byte 開始,而使用的單位可以是單一字母的 E, P, T, G, M, K,也可以是雙字母的 Ei, Pi, Ti, Gi, Mi, Ki(比較常見),以下是幾個設定範例:

  • 104857600 (相當於 100 MB = 10010241024)
  • 100M
  • 100Mi

128974848 = 129e6 = 129M = 123Mi
123Mi * 1024 * 1024 = 128974848 bytes
129 MB * 1000 * 1000 = 128974848 bytes
怎麼將Mi轉成Mb?
3713Mi * 1024 * 1024 / 1000 / 1000 = 3893MB

prometheus執行時更新config的方式

參考官方文件的教學如下:
https://prometheus.io/docs/prometheus/latest/configuration/configuration/

Prometheus can reload its configuration at runtime. If the new configuration is not well-formed, the changes will not be applied. A configuration reload is triggered by sending a SIGHUP to the Prometheus process or sending a HTTP POST request to the /-/reload endpoint (when the –web.enable-lifecycle flag is enabled). This will also reload any configured rule files.

而實際的應用方式則是:

  • 第一種,向prometheus進行發信號
    kill -HUP pid
  • 第二種,向prometheus發送HTTP請求
    curl -XPOST http://127.0.0.1:9090/-/reload
    但是會需要先設定--web.enable-lifecycle參數

     template:
        metadata:
          labels:
            ...
            prometheus: rancher-monitoring-prometheus
        spec:
          containers:
          - args:
            - --web.enable-lifecycle
            image: rancher/mirrored-prometheus-prometheus:v2.27.1
            imagePullPolicy: IfNotPresent
            name: prometheus
            ....

Dockerfile簡單範例

如何製作docker image

  1. 到docker hub尋找適合的基礎容器或官方提供的映像檔
  2. 自行撰寫需要客製化的部分
  3. 撰寫Dockerfile內容
  4. 執行command line,指向專案資料夾
  5. docker build –tag NAME .

  6. 上傳映像檔至儲存庫

Dockerfile的指令介紹

範例:

  1. FROM: 從某個別人建好的容器開始製作自己的容器。如centos:6.7
  2. ENV: 定義一些變數後面可使用
  3. ARG: 在BUILD IMAGE時可帶入參數
    docker build –build-arg SCRIPT=tmp.js .
  4. WORKDIR: 指定下指令的位置
  5. RUN: 於CONTAINER下指令
  6. COPY: 複製檔案進去
  7. CMD: 最後要開始主程式的指令
  8. ENTRYPOINT:與CMD相同,差在不會被docker run時帶的指令蓋掉,而是相加

[LeetCode] Maximum Value of K Coins From Piles

Maximum Value of K Coins From Piles

這是遞迴方式的寫法, 但我可能存太多垃圾資訊,當k值變大之後,會發生heap allocation錯誤的問題,也受限於遞迴的限制當k變大效率非常差…..
看來又要動態規劃(哭), 晚點再來補上改善版

/**
* @param {number[][]} piles
* @param {number} k
* @return {number}
*/
var maxValueOfCoins = function (piles, k) {
let rootNode = new node(piles.length, k);
let maxResult = addAllChildrenForThisNode(rootNode, piles, 0);
console.log(rootNode.toObject())
return maxResult
};
function addAllChildrenForThisNode(node, piles, maxResult) {
for (let i = 0; i < node.pilesPointer.length; i++) {
if (node.pilesPointer[i] + 1 < piles[i].length) {
let y = node.pilesPointer[i] + 1;
let newNode = node.addChild(piles[i][y], i, y);
console.log(newNode.deep)
if(newNode.deep < newNode.maxSelectNum){
maxResult = addAllChildrenForThisNode(newNode, piles, maxResult)
}else{
maxResult = Math.max(newNode.currentValue, maxResult)
}
}
}
return maxResult
}
function node(pilesNum, maxSelectNum) {
this.currentValue = 0;
//樹的鏈結資料
this.deep = 0;
this.parent = undefined;
this.children = [];
//x代表在哪個piles, y代表在該piles的深度
this.indexX = undefined;
this.indexY = undefined;
//用來儲存這個node位置所有的piles的y座標
this.pilesPointer = new Array(pilesNum).fill(-1);
this.maxSelectNum = maxSelectNum;
this.addChild = function (num, indexX, indexY) {
let child = new node(this.pilesPointer.length, this.maxSelectNum);
child.deep = this.deep + 1;
child.parent = this;
child.currentValue = this.currentValue + num;
child.indexX = indexX;
child.indexY = indexY;
child.pilesPointer = this.pilesPointer.slice(0);
child.pilesPointer[child.indexX] = indexY;
this.children.push(child);
return child
}
this.toObject = function () {
let children = [];
for (let child of this.children) {
children.push(child.toObject())
}
return {deep:this.deep, value: this.currentValue , children: children}
}
}

console.log(maxValueOfCoins([[80,62,78,78,40,59,98,35],[79,19,100,15],[79,2,27,73,12,13,11,37,27,55,54,55,87,10,97,26,78,20,75,23,46,94,56,32,14,70,70,37,60,46,1,53]],5))

[LeetCode] Coin Change 2

Coin Change2

這也是一題動態規劃的題目,但是比起上一題,上一題每一個暫時儲存的東西是有意義的,我們可以了解說每一個的暫時狀態是某個數字用所給的硬幣列表裡,能用最少數量達成答案的數目,但是這一題的中間狀態所儲存的真的就是『中間的狀態』,我是看著別人的答案去回推理論的,真的很難想像在遇到這樣的問題時,該用什麼角度去把複雜的問題拆分,並找尋出重複步驟並找到可暫存狀態來計算出最終結果。

這是最後的結果

var change = function(amount, coins) {
let dp = new Array(amount+1).fill(0);
dp[0]=1;
for(let coin of coins){
for(let i=coin;i<=amount;i++){ dp[i]+=dp[i-coin]; } } return dp[amount] }; [/code] 大概解釋一下解題的思緒,首先就是最重要的,先設定一個暫存動態編程的序列

dp

,這裡面的值只是儲存一個暫時的狀態,讓我們在計算下一個值時可以拿前一個運算到一半的值來繼續運算,長度為amount+1(這樣才存的到

dp[amount]

)。

接下來很重要的是把

dp[0]=1

, 這是所有計算的起點, 代表說在一個分解狀態下,若自己可以被自己整除,那就可以有一種解法

若題目是coins=[2,5,8], amount=16時:

我們可以先觀察在

coins:[2], amount:16

時,
這樣的半狀態會得到:

dp = [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1]

這個的意思是,若是coins只有2時,可以用2組成0, 2, 4, 6, 8, 10, 12, 14, 16,皆只有一種組法。

接下來我們再把5加進去,但是因為以coins=[2,5]來說,我們可以把任務拆細,若是要組成16,我們要避免掉重覆的狀態,也就是說
我們可以思考,因為5,5,2,2,2和2,2,5,5,2其實是相同的答案,以2,2,2,5,5來說,其實是單純用2coin*3個=6和單純用5coin*2個=10,
那麼就可以開始計算,用5和2共同組成的狀況下,五的分佈是如何呢?

amount為16,則5有可能有分成:1個5(這時會需要單純用2組成11)和2個5(這時會需要用2組成6)和3個5(這時會需要用2組成1)三種可能性,這時參照上面coins=[2]的dp,會知道用2組成11的狀況和用2組成1狀況是0個,代表只會增加2個5的狀況。

但是動態編程當然沒這麼容易思考(真哭),因為這邊的dp存的是一個暫時半狀態的對照表,會需要算出從5~16所有可用[2,5]組成的,需要較完整的對照表。

首先很重要的,為什麼要從五開始,因為一定要大於五才有可能可以用五組成結果,並且如同dp[0]一樣,dp[5]因為coins有5,一定會多一種5的組合法。
從上面的推論我們可以觀查到要知道有沒有機會使用5這個coins來組成結果,主要要觀察『要組成總數』減掉現有coin的面額的數字,能不能用2組成

所以若要知道6能不能用[5,2]組成,就要查coins:[2]所暫存的表的

dp[6(要組數字)-5(現有硬幣)]=dp[1](能不能用2組成1) = 0

,可得知是0種可能,以此類推。
這邊非常重要的是一定要從小到大,因為才可以讓狀態累加,我們先得知5可以組成5,把dp[5]=1(本來只有coins:2時是0),而在算10時,才能得到dp[10-5]=1(得知可以使用5來組成10),外加單純用2組成10的可能性(當coins=[2]時dp[10]為1),可知10這個數字可單純用5組成也可用[2,5]組成,所以共有2種可能性,然後把dp[10]更新為2

接著在算dp[15]時才能夠利用dp[15-5]=dp[10]=2,再加上當coins=[2]時的dp[15]=0,得知dp[15]為2

以下為coins=[2,5]時的dp對照表

dp= [ 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 2, 2]

接下來就是再相同的步驟再把coin 8加進coins列表裡。以同樣的步驟和概念,就可以得到

dp=[1, 0, 1, 0, 1, 1, 1, 1, 2, 1, 3, 1, 3, 2, 3, 3, 4]

最後推得用[2,5,8要組成16有四種可能性]

[LeetCode] Coin Change

https://leetcode.com/problems/coin-change

最近開始刷leetcode覺得思考這些邏輯問題還滿好玩的
第一個刷的是這個,他是一個動態規劃的題目

一般我們在思考的時候會去思考以錢幣為基準,例如1,3,5的錢幣要怎麼湊成11元,我們會拿1,3,5去隨機湊硬幣,但是當數值大了以後,要計算最小的錢幣組合就會變成很困難.

像這種極限求值就會需要將思考轉換過來, 我們可以一步步的拆解, 先了解1,3,5,若要組成1是用幾個(1個1),那組成2要用幾個(2個1),若要組成3要用幾個,到3時我們就會發現,3可以用”3個1″或”1個3″組成, 這時候就可以來比較誰用的硬幣比較少,然後把最小可組成的數字”1″存到可組成結果為3的陣列。
接下來在思考4的時候,我們就可以思考4減掉硬幣1,也就是3,的最小使用硬幣數量,那就代表我們使用3,再加上硬幣1,可以組成4。接下來算要組成6要幾個硬幣,6減掉硬幣3,可以拿到硬幣3要用幾個硬幣,所以就是硬幣3使用的硬幣數量+1。
var coinChange = function (coins, amount) {
if (amount == 0) return 0;
let amountRecord = []
amountRecord[0] = 0
lastExistResult = 0
minCoin = Math.min(…coins);
//紀錄這些硬幣能夠組合成的數值所使用的硬幣數, 並用這些數值來推算目標所需的硬幣
for (var currentAmount = 1; currentAmount <= amount; currentAmount++) { amountRecord[currentAmount] = Infinity if (currentAmount + minCoin >= lastExistResult) {
for (var coin of coins) {
if (coin <= currentAmount) {
//尋找這一個數字可不可以用之前可組成的硬幣加上其中一個新的硬幣來滿足(以確認是最小的硬幣數目)
amountRecord[currentAmount] = Math.min(amountRecord[currentAmount], amountRecord[currentAmount – coin] + 1);
}
}
}
if (amountRecord[currentAmount] != Infinity) {
lastExistResult = amountRecord[currentAmount];
}
}
console.log(amountRecord)
return amountRecord[amount] == Infinity ? -1 : amountRecord[amount]
};
這個JS的效能只贏了32.59%的人

覺得不太開心(?)
所以我把console.log拿掉,再把let amountRecord = []; amountRecord[0] = 0;改成一行let amountRecord = [0](是有沒有這麼無聊)

接著我突發奇想,想說若是這個數字可用硬幣湊齊, 下個數字如果小於最小的coins數字的話,可以省略(如硬幣是10,15,18, 但是要組成11,很明顯就不可能會有結果,因為11-10小於10)

PS: 但是測試後其實拿掉console.log影響最大XD
var coinChange = function (coins, amount) {
if (amount == 0) return 0;
let amountRecord = [0]
lastExistResult = 0
minCoin = Math.min(…coins);
//紀錄這些硬幣能夠組合成的數值所使用的硬幣數, 並用這些數值來推算目標所需的硬幣
for (var currentAmount = 1; currentAmount <= amount; currentAmount++) { amountRecord[currentAmount] = Infinity if (currentAmount + minCoin >= lastExistResult) {
for (var coin of coins) {
if (coin <= currentAmount) {
//尋找這一個數字可不可以用之前可組成的硬幣加上其中一個新的硬幣來滿足(以確認是最小的硬幣數目)
amountRecord[currentAmount] = Math.min(amountRecord[currentAmount], amountRecord[currentAmount – coin] + 1);
}
}
if (amountRecord[currentAmount] != Infinity) {
lastExistResult = amountRecord[currentAmount];
}
}
}
return amountRecord[amount] == Infinity ? -1 : amountRecord[amount]
};

結果至少擊敗了72.28%的人,累了…先這樣吧XDD

LBP 區域二值模式

其實會發這一篇文,主要是看到這個博客的文章真的感動到快哭了…

這幾天因為想增加OCR辨識正確率開始與LBP打交道
https://zh.wikipedia.org/wiki/%E5%B1%80%E9%83%A8%E4%BA%8C%E5%80%BC%E6%A8%A1%E5%BC%8F
我找到了一個看起來很強大很棒的函式庫
https://scikit-image.org/docs/stable/api/skimage.feature.html#skimage.feature.local_binary_pattern

網路上有很多教學文章,看起來是很知名的套件
a href=\”https://machine-learning-python.kspax.io/classification/ex1_recognizing_hand-written_digits\”>https://machine-learning-python.kspax.io/classification/ex1_recognizing_hand-written_digits
然後我遇到了和這位博主一樣的問題
https://www.cnblogs.com/ilk123/p/11797261.html
沒錯…….LBP明明出來的應該是1-256的值阿…我也是設定R=1, P=8\r\n這樣用default的LBP出來的應該要是1-256之間的值,但是卻是0和1的二值陣列….

我一直想..這麼偉大的一個scikit-image怎麼可能有錯,一定是我的使用方法有誤…
害我撞頭撞到快崩潰…..
沒想到在此遇到一個和我一樣的苦主
太感動了,特此記錄!

另外,後來我也找到了一個最原始的LBP算法
程式碼下載於 https://github.com/zhongqianli/local_binary_pattern/blob/master/local_binary_pattern.py

def original_lbp(image):
"""origianl local binary pattern"""
rows = image.shape[0]
cols = image.shape[1]

lbp_image = np.zeros((rows - 2, cols - 2), np.uint8)

for i in range(1, rows - 1):
for j in range(1, cols - 1):
code = 0
center_pix = image[i, j]
if image[i - 1, j - 1] > center_pix:
code = code | (1 << 7) if image[i - 1, j] > center_pix:
code = code | (1 << 6) if image[i - 1, j + 1] > center_pix:
code = code | (1 << 5) if image[i, j + 1] > center_pix:
code = code | (1 << 4) if image[i + 1, j + 1] > center_pix:
code = code | (1 << 3) if image[i + 1, j] > center_pix:
code = code | (1 << 2) if image[i + 1, j - 1] > center_pix:
code = code | (1 << 1) if image[i, j - 1] > center_pix:
code = code | (1 << 0) lbp_image[i - 1, j - 1] = code return lbp_image[/code]

WEBM影片格式介紹

WEBM格式是一種媒體文件格式,開源為Web使用設計,主要用於視頻的播放。

WebM簡介

WebM 是一個開源的媒體文件格式,主要用於封裝使用 VP8 或 VP9 編碼的視頻流和使用 Vorbis 或 Opus 編碼的音頻流。這個格式是由 Google 主導開發的,並於 2010 年首次推出。

以下是一些 WebM 格式的特點和詳情:

1. 設計目的

WebM 主要設計用於在線流媒體傳輸,特別是作為 HTML5 的 <video> 標籤的一部分。它旨在提供一個開放、高效、免版權費的視頻壓縮方案。

2. 視頻和音頻編碼

  • 視頻:VP8 或 VP9
  • 音頻:Vorbis 或 Opus

3. 優勢

  • 開放和免費:WebM 是一個完全開源和免費的格式,這意味著任何人都可以使用和分發它,無需支付任何費用。
  • 高效壓縮:使用 VP9 編碼的 WebM 文件可以提供與 H.264 相似的視頻質量,但文件大小通常更小。
  • 廣泛支持:大部分主流瀏覽器,如 Chrome、Firefox 和 Opera,都支持 WebM 格式的播放。

4. 缺點

  • 兼容性問題:一些瀏覽器(如 Safari)和一些媒體播放器可能不原生支持 WebM 格式。
  • 硬體支持限制:與某些其他視頻格式相比,硬體支持可能較少。

5. 適用場景

由於 WebM 的高效壓縮和開放性質,它特別適合用於網頁視頻、視頻會議、流媒體服務等場景。

6. 文件結構

WebM 使用 Matroska 容器格式,這是一個流行的開源媒體容器格式,可以容納多種編碼的音頻和視頻流。

可使用的傳輸協議

  1. HTTP/HTTPS:作為最常見的Web傳輸協議,HTTP和HTTPS可用於傳輸WEBM文件。這是在網頁中嵌入和播放WEBM視頻的標準方法。
  2. RTSP (Real-Time Streaming Protocol):用於控制多媒體流的傳輸,可以用於WEBM格式的傳輸。
  3. HLS (HTTP Live Streaming):由Apple開發的基於HTTP的流媒體通信協議,也可用於傳輸WEBM格式。
  4. DASH (Dynamic Adaptive Streaming over HTTP):另一種基於HTTP的適應流媒體傳輸協議,支持WEBM格式。
  5. FTP (File Transfer Protocol):用於在客戶端和服務器之間傳輸文件的協議,可以用於傳輸WEBM文件。
  6. WebSocket:允許在Web瀏覽器和服務器之間建立全雙工通信通道,也可用於傳輸WEBM數據。
  7. WebRTC:允許Web瀏覽器進行即時通信,也可以用來傳輸WEBM格式的視頻。

優缺點分析

優點:

  1. 開放標準: WEBM是一個免費並開源的格式,這意味著它不受專利限制,可以自由使用。
  2. 高質量和高效編碼: WEBM使用VP8/VP9視頻編碼,這些編碼器提供了與其他流行格式相當的視頻質量,但文件大小更小。
  3. 廣泛支持: 大多數現代Web瀏覽器都支持WEBM格式,使其成為網絡視頻的理想選擇。
  4. 支持HTML5: WEBM被設計為與HTML5 <video> 標籤完全兼容,使其在網頁中的集成變得簡單。
  5. 支持透明度: VP8/VP9支持透明度(Alpha Channel),允許視頻有透明背景。

缺點:

  1. 軟件兼容性: 雖然大多數現代瀏覽器支持WEBM,但一些舊的或非主流的瀏覽器和媒體播放器可能不支持。
  2. 專業編輯支持有限: 相比其他格式如MP4,WEBM在專業視頻編輯軟件中的支持可能較少。
  3. 不是所有設備都支持: 一些移動設備和媒體播放器可能不支持WEBM格式。
  4. 沒有廣泛的工業標準: 雖然WEBM在Web環境中表現出色,但它還沒有像MP4那樣成為廣泛接受的工業標準。
  5. 音頻格式限制: WEBM通常使用Opus或Vorbis作為音頻編碼,這可能不是所有應用的最佳選擇。

由Google開發的其他格式

WEBP 是一種圖像格式,用於同時提供有損和無損壓縮。同樣也是由Google開發,目的是加速圖片在網頁上的加載速度。

要把.jpg轉成.webp可使用下面的語法

ffmpeg -i input.jpg -c:v libwebp output.webp

QUIC

  • QUIC則是一個多路復用的傳輸層協議,使用UDP進行數據傳輸。
  • 它的目的是減少連接建立的延遲,並且改善在不可靠網絡中的數據傳輸性能。
  • QUIC還包括了一個內置的TLS,增強了安全性。

WEBM和QUIC解決了網絡中不同的問題。WEBM專注於視頻編碼和播放,而QUIC則專注於連接和數據傳輸的效率和可靠性。Google作為一個網絡技術的領先公司,一直在推動和創造各種新的技術標準,以改進整個互聯網的性能和體驗。