【機器學習】算法原理詳細推導與實現(二):邏輯回歸

【機器學習】算法原理詳細推導與實現(二):邏輯回歸

在上一篇算法中,線性回歸實際上是 連續型 的結果,即 \(y\in R\) ,而邏輯回歸的 \(y\) 是離散型,只能取兩個值 \(y\in \{0,1\}\),這可以用來處理一些分類的問題。

logistic函數

我們可能會遇到一些分類問題,例如想要劃分 鳶尾花 的種類,嘗試基於一些特徵來判斷鳶尾花的品種,或者判斷上一篇文章中的房子,在6個月之後能否被賣掉,答案是 或者 ,或者一封郵件是否是垃圾郵件。所以這裡是 \(x\) ,這裡是 \(y\) 在一個分類問題中,\(y\) 只能取兩個值0和1,這就是一個二元分類的問題,如下所示:

可以使用線性回歸對以上數值進行劃分,可以擬合出如下那麼一條線,用 \(y=0.5\) 作為臨界點,如果 \(x\) 在這個臨界點的右側,那麼 \(y\) 的值就是1,如果在臨界點的左側,那麼 \(y\) 的值就是0,所以確實會有一些人會這麼做,用線性回歸解決分類問題:

線性回歸解決分類問題,有時候它的效果很好,但是通常用線性回歸解決像這樣的分類問題會是一個很糟糕的主意,加入存在一個額外的訓練樣本 \(x=12\),如果現在對這個訓練集合做線性擬合,那麼可能擬合出來那麼一條直線:

這時候\(y\)的臨界點估計已經不太合適了,可以知道線性回歸對於分類問題來說,不是一個很好的方法。

假設 \(h_\theta(x) \in [0,1]\),當如果已知 \(y\in \{0,1\}\),那麼至少應該讓假設 \(h_\theta(x)\) 預測出來的值不會比1大太多,也不會比0小太多,所以一般不會選擇線性函數作為假設,而是會選擇一些稍微不同的函數圖像:

\[ g(z)=\frac{1}{1+e^{-z}} \]

\[ h_\theta(x)=g(\theta^Tx)=\frac{1}{1+e^{-\theta^Tx}} \]

\(g(z)\) 被稱為 sigmoid函數 ,也通常被稱為 logistic函數,它的函數圖像是:

\(z\) 變得非常小的時候,\(g(x)\) 會趨向於0,當\(z\)變得非常大的時候,\(g(x)\) 會趨向於1,它和縱軸相較於0.5。

邏輯回歸

那麼我們的假設\(h_\theta(x)\) 要嘗試估計 \(y\in \{0,1\}\) 的概率,即:

\[ P(y=1|x;\theta)=h_\theta(x) \]

\[ P(y=0|x;\theta)=1-h_\theta(x) \]

以上可以把兩個公式合併簡寫為(如果\(y=1\)那麼公式為\(h_\theta(x)\);如果\(y=0\)那麼公式為\(1-h_\theta(x)\)):

\[ P(y|x;\theta)=(h_\theta(x))^y(1-h_\theta(x))^{1-y} \]

如果對《概率論和數理統計》學得好的人不難看出,以上函數其實就是 伯努利分佈 的函數。

對於每一個假設值\(h_\theta(x)\),為了使每一次假設值更準確,即當 \(y=1\) 時估計函數 \(P(y=1|x;\theta)=h_\theta(x)\) 趨向於1,當\(y=0\) 時估計函數 \(P(y=0|x;\theta)=1-h_\theta(x)\) 趨向於0。則對於每一個\((x_i,y_i)\),參數 \(\theta\) 的似然估計 \(L(\theta)\)為:

\[ \begin{split} L(\theta)&=P(\vec{y}|X;\theta) \\ &=\prod_{i=1}^mP(y^{(i)}|x^{(i)};\theta) \\ &=\prod_{i=1}^m(h_\theta(x^{(i)}))^{y^{(i)}}(1-h_\theta(x^{(i)}))^{1-{y^{(i)}}} \end{split} \]

如果每一個\((x_i,y_i)\)都準確,即 \(P(y|x;\theta)\) 趨向於1,則應該使似然估計 \(L(\theta)\) 最大化,也就是轉化成熟悉的問題:求解 \(L(\theta)\) 的極大似然估計

為了調整參數 \(\theta\) 使似然估計 \(L(\theta)\) 最大化,推導如下(取 \(log\) 是為了去掉疊乘方便計算):

\[ \begin{split} l(\theta)&=logL(\theta) \\ &=\sum_{i=1}^m{y^{(i)}logh(x^{(i)})+(1-y^{(i)})log(1-h(x^{(i)}))} \end{split} \]

為了使這個函數最大,同樣可以使用前面學習過的梯度下降算法使對數似然估計最大化。之前學習的是要使誤差和 最小化,所以梯度下降的公式為:

\[ \theta:=\theta-\alpha\frac{\partial J(\theta)}{\partial\theta}=>\theta:=\theta-\alpha\nabla_\theta J(\theta) \]

而本次為了求解似然估計最大化,使用的是梯度上升:

\[ \theta:=\theta+\alpha\nabla_\theta l(\theta)=>\theta:=\theta+\alpha\frac{\partial l(\theta)}{\partial\theta} \]

對數似然性是和 \(\theta\) 有關,同樣的為了計算 梯度上升 最快的方向,要對上述公式求偏導得到極值,即是上升最快的方向:

\[ \begin{split} \frac{\partial l(\theta)}{\partial\theta_j}&=(y\frac{1}{g(\theta^Tx)}-(1-y)\frac{1}{1-g(\theta^Tx)})\frac{\partial}{\partial\theta_j}g(\theta^Tx) \\ &=(y\frac{1}{g(\theta^Tx)}-(1-y)\frac{1}{1-g(\theta^Tx)})g(\theta^Tx)(1-g(\theta^Tx))\frac{\partial}{\partial\theta_j}\theta^Tx \\ &=(y(1-g(\theta^Tx))-(1-y)g(\theta^Tx))x_j \\ &=(y-g(\theta^Tx))x_j \\ &=(y-h_{\theta}(x))x_j \end{split} \]

則對於 m 個樣本,則有:

\[ \frac{\partial l(\theta)}{\partial\theta_j}=\sum_{i=1}^m{(y-h_{\theta}(x))x_j} \]

\[ \theta_j:=\theta_j+\sum_{i=1}^m{(y^{(i)}-h_{\theta}(x^{(i)}))x^{(i)}_j} \]

所以總結來說:

邏輯回歸假設數據服從伯努利分佈,通過極大化似然函數的方法,運用梯度下降來求解參數,來達到將數據二分類的目的。

鳶尾花分類

為了劃分 鳶尾花 的種類,嘗試基於一些特徵來判斷鳶尾花的品種,選取100條鳶尾花數據集如下所示:

花萼長度(單位cm) 花萼寬度(單位cm) 種類
5.1 3.5 0
4.9 3.0 0
4.7 3.2 0
7.0 3.2 1
6.4 3.2 1

其中:

種類 含義
0 山鳶尾(setosa)
1 變色鳶尾(versicolor)
2 維吉尼亞鳶尾(virginica)

數據集的圖像分佈為:

計算損失函數:

# 損失函數
def computeCost(theta, X, y):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)
    first = np.multiply(-y, np.log(sigmoid(X * theta.T)))
    second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))
    return np.sum(first - second) / (len(X))

梯度下降函數為:

# 梯度下降
def gradient(theta, X, y):
    theta = np.matrix(theta)
    X = np.matrix(X)
    y = np.matrix(y)

    parameters = int(theta.ravel().shape[1])
    grad = np.zeros(parameters)

    error = sigmoid(X * theta.T) - y

    for i in range(parameters):
        term = np.multiply(error, X[:, i])
        grad[i] = np.sum(term) / len(X)

    return grad

最終預測準確率為:

accuracy = 99%

結果分類的圖像為:

數據和代碼下載請關注公眾號【 TTyb 】,後台回復【 機器學習 】即可獲取:

【精選推薦文章】

智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

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

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

Amzaon EC2虛擬化技術演進:從 Xen 到 Nitro

  今年2月,由光環新網運營的 AWS 中國(北京)區域和由西雲數據運營的 AWS 中國 (寧夏)區域發布新的實例類型,新的實例類型包括 C5、C5d、R5、R5d。除了這四種之外,在AWS國外部分區域還上線了最新的C5n。       這些新實例類型個個都具有鮮明的特徵,我簡單整理歸納如下:

  • C5實例:性價比顯著提升(與 C4 實例相比,C5 實例提供了更高的內存與 vCPU 比率,並且性價比提高了 25%,某些應用程序提高了 50% 以上),更大的實例大小(C5 實例新的更大的實例 c5.18xlarge提供了 72 個 vCPU 和 144 GiB 內存並提供了 25 Gbps 的網絡帶寬)。
  • C5d實例:基於本地 NVMe 的 SSD 磁盤將被物理連接到主機服務器,提供與C5實例的生命周期相耦合的塊級存儲。c5d.18xlarge 規格的實例支持2塊900GB的NVMe SSD作為本地存儲。
  • C5n實例:這是C5 系列的最新成員,其c5n.18xlarge規格可提供高達 100Gbps 的網絡吞吐量。
  • R5實例:其最大實例規格支持96 vCPU、768 GiB內存和25 Gbps 網絡帶寬。
  • R5d實例:R5d 實例與 R5 實例規格相同,它還包括高達 3.6 TB 的本地 NVMe 存儲。

這些實例類型之所以如此實力超群,我認為主要歸功於兩點:

  • 處理器升級

C5 實例配備 Intel Xeon Platinum 8000 系列 (Skylake-SP) 處理器,它發佈於2017/Q3,具有高達 3.4GHz 的穩定全核 Turbo CPU 時鐘速度,並使用 Intel Turbo Boost Technology 來允許單個核心睿頻高達3.5GHz。C5 實例為新的 Intel 高級矢量擴展 512 (AVX-512) 指令集提供了支持,與上一代 C4 實例相比,矢量和浮點計算性能提高最高可達2倍。
而發佈於2015年的C4 實例類型,配備Intel Xeon E5-2666 v3 (Haswell) 處理器。其時鐘頻率為2.9 GHz,配合Intel® Turbo Boost后最高可達3.5 GHz。

  • 採用了AWS Nitro 虛擬化平台

AWS Nitro 將是這篇文章的主角。本文會從它的發展歷程、架構、所創造的價值等方面進行分析和介紹,試圖總結出AWS上虛擬化基礎平台發展的脈絡。

AWS EC2虛擬化發展歷程

下錶總結了AWS曾經採用的虛擬化技術,以及這些技術之間的性能對比:

 

  • #1是全模擬技術。這種虛擬化方式能支持未修改的客戶機操作系統,但速度會嚴重下降。典型產品是VMware 在1986年發布的虛擬化產品。AWS 並沒有採用這種虛擬化技術,放在表格中只是為了做對比用。
  • #2 是基於Xen的半虛擬化技術(Paravirtualization,PV)。PV 要求修改客戶機內核和驅動。EC2第一個採用半虛擬化的實例類型是 m1.small。
  • #3 到 #6 是基於Xen和CPU硬件的全虛擬化技術(Hardware-assisted virtualization,HVM)。採用Xen HVM 技術的虛擬機運行在具有CPU和內存(VT-x)硬件虛擬化能力的處理器上,並使用半虛擬化驅動程序用於網絡和存儲設備。HVM 3.0 中尚未實現中斷和定時器半虛擬化,但在4.0中已有改善。
  • #7 和 #8 則是AWS Nitro技術,這是AWS 研發的一種新虛擬化平台。後面會有詳細介紹。

過去幾年中,Xen是AWS上虛擬化技術的主體,業已成為業界標準之一,已經非常成熟。那麼,為什麼AWS要從Xen 向 Nitro 發展呢?這得從Xen 的架構說起。

從上圖可以看出,Xen 實現了虛擬機的CPU 和內存虛擬化,但是虛擬機的I/O 訪問,包括網絡和存儲等,都是通過虛擬機中的前端模塊和 dom0 中的後端模塊通信,然後由dom0 中的後端模塊通過設備驅動實現的。這I/O路徑太長,這降低了I/O性能,而且dom0還會和業務虛擬機搶佔宿主機資源,很難實現管理虛機和業務虛機之間的平衡,以及避免抖動。

2013年,AWS 採用 Xen PV虛擬化技術的cr1.8xlarge 實例的架構如下圖所示:

這是嚴格意義上未採用Nitro技術的最後一個EC2型號。簡要說明:

  1. 圖中的硬件(Hardware),是運行虛擬機的物理服務器,採用了當時很強大的標準的10Gbps網卡,以及管理一些本地磁盤的存儲HBA卡。Hardware上既運行用戶的業務虛擬機,還運行Xen的dom0虛擬機。
  2. VMM採用Xen項目的PV模式。
  3. 圖中 Amzon Linux 代表Xen dom0,它負責訪問硬件,向虛擬機提供I/O 能力。

圖中 cr1.8xlarge 代表一個這種規格的虛擬機,它的本地存儲、EBS卷和VPC網絡訪問都是通過Xen管理的dom0 虛擬機實現的。

Nitro起源和發展

針對傳統虛擬化架構存在的問題,從2012年開始,AWS EC2虛擬化團隊就開始思考以下問題:

  1. 能做出比純軟件架構更好的hypervisor嗎?
  2. 設備模型本身很複雜,而且它會和業務虛擬機競爭CPU和系統資源,同時技術上它很難避免抖動發生
  3. hypervisor太重了,能將hypervisor 和它周邊的組件解耦嗎?

  從成立之日起,AWS就善於聽取客戶的呼聲和建議,並不斷進行迭代式改進,而不是大刀闊斧地從頭設計一個新架構。根據該原則,AWS團隊首先從最難的網絡部分着手,其位置就是上圖中的金黃色虛線框所示位置。從2013年開始,一些EC2實例類型開始支持網絡接口的硬件虛擬化:單根I/O虛擬化(SR-IOV),而第一個是2013年1月發布的C3,它首次採用了AWS增強型網絡(enhanced networking)。這最初是通過ixgbe驅動程序實現的,速度高達10 Gbps。   c3.8xlarge的架構如下圖所示:

c3.8xlarge的架構與cr1.8xlarge相比,在宿主機上增加了一塊新網卡,這塊網卡和原有的標準網絡通過一個迴環線(loopback cable)連接起來。虛機VPC網絡功能不再通過Xen 的dom0 實現,而是直接訪問宿主機上的這塊硬件網卡。C3 是AWS EC2 歷史上增長最快的幾個實例類型之一,它尤其以控制性能抖動和持續的網絡性能著稱。這可以看做Nitro思想的發源,那就是將軟件功能卸載到專有硬件上。

  下一個改進方向是EBS存儲訪問性能提升。   2015年,AWS推出了C4實例類型,它針對EBS卷使用了硬件虛擬化技術。c4.8xlarge的架構如下圖所示。仔細對比能發現,這個新架構與C3中的網絡架構改進有些不同。在虛擬機中,還保留了“前端-後端”這種Xen傳統架構,這是當時為了兼容性和穩妥新考慮,因為NVMe在當時來說還是一種非常新的技術。在宿主機上,採用了新收購的Annapurna Labs公司開發一種卡(下圖中黃色虛線框內),它能將遠端存儲以NMVe形式呈現給虛擬機。

這個改進的結果是,宿主機上的CPU被Xen佔用得少了,能更多地被虛機使用了。

  2016年5月發布的X1 是第一個支持ENA的實例類型。ENA是增強型網絡的最新實現,速度高達25 Gbps。ENA,全稱是Elastic Network Adapter,它正是Nitro項目的一部分,它是由Annapurna Labs公司開發的。

現在的ENA,能用於虛擬機和物理機,它以開源項目形式發布在github上。ENA 是AWS網絡虛擬化一關鍵技術,它使得虛擬機能夠繞過內核和用戶空間網絡處理程序,直接操作網卡硬件,這顯著提升了網絡效率。

從用戶使用角度,也許只是用了一個新網卡驅動。但是其底層採用了Annapurna Labs公司開發的定製網絡ASIC硬件卡。這是Nitro第一款真正的專用硬件卡。它不僅卸載了VPC網絡功能,還卸載了EBS 存儲網絡功能。因此這是一種完全的網絡負載卸載硬件。

 

下一步的優化方向在實例存儲上。2017年,AWS發布了存儲優化實例類型i3,它使用了SR-IOV和NVMe存儲驅動。這是AWS首次採用Annapurna Labs研發的Nitro存儲卡40202所管理的SSD磁盤,這些磁盤被直接映射給虛擬機,虛擬機通過NVME驅動來使用宿主機上的SSD磁盤。這能實現磁盤300萬以上的IOPS性能。Nitro 芯片負責包括磁盤監控、加密、QoS等職責。  

 

  顯然,到這時候為止,仍然剩下的問題只能是Xen 自身,以及它的管理功能部分了。Xen過於笨重,因為作為傳統 Hypervisor,它必須做很多事情 – 它必須保護物理硬件和 BIOS,它必須虛擬化 CPU,虛擬化存儲,虛擬化網絡,並提供豐富的管理功能。其管理性dom0虛擬機會搶佔業務虛機的系統資源。那到底能不能把Xen徹底替換掉呢?答案是肯定的,因為AWS在技術上從來沒讓人失望過。   2017年11月,AWS發布了C5 實例類型。它使用基於KVM的Nitro hypervisor 替換了Xen,hypervisor 軟件大大被簡化,Xen 所用的 dom0 也不需要了。其架構示意圖如下:

 

AWS Nitro 則重新構建了EC2虛擬化基礎架構。Nitro 系統將存儲、網絡和安全功能卸載(offload)到專用的硬件(Nitro卡)上,帶來的好處是虛擬化實例幾乎可以為客戶機操作系統提供主機的所有 CPU 和內存,同時Hypervisor 的功能也因此大大減弱。   Nitro 還被用到2017年發布的AWS 首個物理機實例類型 i3.metal中。下圖是i3.metal架構示意圖:

在i3.metal 中,Nitro 發揮了基礎性作用。它的安全芯片通過提供硬件保護和固件驗證功能為I3實例提供安全保障;它的各種卡,使得I3實例具備基於非易失性存儲器標準 (NVMe) SSD 的實例存儲,通過ENA支持高達 25Gbps 的聚合網絡帶寬。 

Nitro 架構

AWS Nitro 系統是模塊化組件的集合,可以使用廣泛的計算、存儲、內存和網絡選項來設計 EC2 實例,為新一代EC2實例提供動力。它包括三大部分:

 

Nitro 卡

 

這些Nitro 卡是硬件,插入到宿主機的PCIe卡槽中,採用SR-IOV 直通(passthrough)技術將這些卡呈現給實例。包括:

  • VPC Data Plane(用於VPC訪問的Nitro卡):本質上是一塊通過PCIe附加到宿主機上的一塊定製網卡,支持網絡封包和解包、安全組、限速器和路由等功能。實例通過ENA驅動和它通信。同時,該卡還帶有一些網絡加速功能。以限速器為例,每個Nitro支持的實例,不管它在哪個區域哪個數據中心哪個宿主機上,都會有一致的性能,這對分佈式應用非常重要。
  • EBS Data Plane(用於EBS卷訪問的Nitro卡):本質上是一塊通過PCIe附加到宿主機上的一塊定製卡。通過該卡,遠端存儲被以NVMe設備形式展現給實例,實例通過標準NVMe驅動程序訪問該卡。它首次被用在C4中。支持卷加密、存儲加速;支持I3裸機實例。
  • Instance Storage Data Plane(用於實例存儲訪問的Nitro卡):通過該卡,本地磁盤被以NVMe設備形式展現給實例,實例通過標準NVMe驅動程序訪問這些磁盤。支持加密、限速器和本地磁盤監控。

除了卡之外,Nitro 還提供卡控制器(Card Controller)。它提供API端點,負責協調所有Nitro卡、Nitro Hypervisor和Nitro安全芯片。它還利用Nitro安全芯片實現了Hardware Root Of Trust(硬件信任根),支持實例監控、計量和認證。它還為Nitro EBS卡實現了NVMe控制器。

Nitro 安全芯片

Nitro安全芯片整合到宿主機主板中,控制對所有非易失性存儲的訪問,持續監控和保護硬件資源,並在每次系統啟動時獨立驗證固件。

Nitro hypervisor

Nitro hypervisor位於極簡化的定製的Linux 內核中,基於KVM,帶有定製的VMM和小用戶空間應用。它只負責管理內存和CPU分配,將Nitro卡虛擬功能分配給實例,監控和計量硬件等,不再需要提供任何網絡功能。因此它只需執行虛擬機所需指令,快速而且簡單,在大多數工作負載中能提供接近裸機的性能。 Nitro 各組件之間的關係如下圖所示:

 

Nitro 帶來的豐富價值

更高網絡訪問性能

利用Nitro提供的新一代 Elastic Network Adapter (ENA) 和 NVM Express (NVMe) 技術,C5 實例提供了高達 25 Gbps 的網絡帶寬和更低延遲及抖動。2018年發布的更強大變體 C5n 實例,支持網絡帶寬高達 100 Gbps,用戶的仿真、內存緩存、數據湖以及其他通訊密集型應用運行得將比以往更好。   採用Nitro增強網絡功能后的網絡延遲對比:

(Series 1:cc2.8xlarge,2:c3.8xlarge,3:c4.8xlarge,4:c5.18xlarge,5:c5.18xlarge(採用ENAv2))

網絡和存儲帶寬對比:   (1:c3.8xlarge,2:c4.8xlarge,3:c5.18xlarge,4:c5n.18xlarge. Series1:網絡,Series2:存儲)

更高EBS和本地存儲訪問性能

Nitro 使得實例可通過物理方式連接到主機服務器的基於 NVMe 的本地 SSD 塊級存儲,以及將遠端存儲以NVMe設備的形式呈現給實例。 2019年3月,由Nitro支撐的新計算密集型 C5 和 C5d 實例已經在AWS 北京和寧夏區域推出。C5實例支持高達9Gbps 的專用 Amazon EBS 帶寬。而 C5d 最大實例規格則可使用兩塊900G的NVMe SSD。這些實例非常適合需要訪問高速、低延遲的本地存儲的應用程序。

更大實例大小和CPU內存比率

由Nitro支撐的C5實例,其實例的CPU和內存比率,由C4的1:1.875上升到1:2;實例的最大規格,從C4的36vCPU/60Gib內存,上升到72vCPU/144Gib內存。

更低虛擬化花銷

Nitro Hypervisor 是一款輕薄的靜態的虛擬機管理程序,可管理虛擬機的內存和CPU分配,並提供與大多數工作負載無法區分的性能。據Netflix公司Brendan Gregg 觀察,Nitro Hypervisor的性能損耗非常小,通常不到1%,他的結論是 Nitro提供的虛擬化性能接近裸設備。

更低Hypervisor抖動

有了Nitro后,就不再需要為存儲和網絡I/O再預留CPU和內存資源了。這不僅使得可以向EC2實例分配更多資源,為更大的實例規格提供了可能,還為實現一個簡單的輕量的hypervisor提供了可能,而這就為實現更低hypervisor抖動創造了條件。   下圖是一AWS 客戶在三種EC2實例上採用對延遲要求極低的一實時應用做的對比測試。藍色是C5,紅色是i3.metal,黃色是C4。SLA 是用於測試的實時應用所能忍受的最高延遲。

 

從上圖中的測試結果看,C5 相對裸機只有一點極小的附加開銷,而且性能非常平穩,幾乎沒有波動,能完全滿足應用的SLA需求。而C4則有相對較大的波動,只能大概滿足70的SLA。

更多實例類型

AWS發布了基於Nitro的實例存儲實例類型 C5d,M5d 和 R5d,提供低延遲高吞吐的基於NVMe的實例存儲。 AWS在2017 re:Invent上宣布了基於Nitro的AWS EC2 Bare Metal實例 I3.metal。它沒有性能開銷,能夠運行你喜歡的任何東西,比如Xen,KVM,容器,ESXi,FireCracker微虛機等;支持非虛擬化環境,支持容器環境,同時還能繼續使用比如EBS、ELB和VPC等基礎服務;支持比如SAP HANA和其它內存型應用。 AWS還基於Nitro發布了採用AMD EPYC處理器的系列實例R5,M5和T3,最高可降低10%成本。 AWS發布了基於Nitro的具有100Gbps網絡帶寬的實例類型C5n,這是運行HPC和分佈式機器學習負載的理想類型。 AWS發布了基於Nitro的採用AWS Graviton(基於ARM)處理器的實例類型A1,最高可降低45%成本。

更低價格、更高性價比

下錶显示了AWS 北京(BJS)和中衛(ZHY)區域的4代和5代EC2實例的價格比較,你可以看到實實在在的價格下降:  

 

目前,Nitro支撐的C5 實例提供了 EC2 產品系列中最佳的價格/計算性能比。與C4實例相比,其性價比提高了49% 。 與R4實例相比,由Nitro支撐的R5實例為每個vCPU提供額外5%的內存,且每 GiB 價格低50%。R5實例非常適用於高性能數據庫、分佈式內存緩存、內存數據庫和大數據分析等應用程序。

為更多性能優化提供了可能

對於需要深度定製化EC2 的用戶而言,Nitro 還帶了了另外的好處:對於EC2 更深入的監控和優化。在由Nitro支撐的C5實例中,你可以得到數百個PMC 計數器(Performance Monitoring Counters ,性能監控計數器)。作為對比,以前的實例類型中,你只能看到區區7個PMCs。更多的PMC計數器,為性能優化提供了更多可能。

小結

亞馬遜 AWS CTO 沃納·威格爾(Werner Vogels)曾經說過,“在亞馬遜 AWS,我們90%到95%的新項目都是基於客戶給我們的反饋,剩下5%也是從客戶角度出發所做得創新嘗試。”而Nitro 正是這種項目之一,它誕生於2013年,成年於2017年,現在還在不斷成長中。Nitro 正在作為AWS核心虛擬化架構平台,推動着AWS最核心的EC2產品家族不斷往更大(單實例的vCPU和內存更大)、更快(I/O速度更快)、更安全(採用Nitro安全芯片)、更穩定(Hypervisor抖動更低)、更多類型、更高性價比方向演進,支撐越來越多用戶越來越多的業務場景,創造着越來越大的業務價值。     主要參考文檔:

  1. AWS re:Invent 2018: Powering Next-Gen EC2 Instances: Deep Dive into the Nitro System (CMP303-R1)
  2. AWS re:Invent 2017: C5 Instances and the Evolution of Amazon EC2 Virtualization (CMP332)
  3. AWS re:Invent 2018: Deep Dive on Amazon EC2 Instances & Performance Optimization Best Practices (CMP307)
  4. AWS re:Invent 2018:Optimizing Network Performance for Amazon EC2 Instances (CMP308-R1) 

感謝您的閱讀,歡迎關注我的微信公眾號:

 

【精選推薦文章】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

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

反射機制 小小談

反射機制(Reflection)

何為反射

反射是在兩種物質分界面上改變傳播方向返回原來物質中的現象
反射是生物體對外界刺激做出應激行為的過程,根據產生的原因分為條件反射非條件反射等,典型的實驗案例包括巴甫洛夫的狗……
反射是一些面向對象程序設計語言提供的針對對象元數據(Metadata)的一種訪問機制

元……數據??什麼高深莫測的武功??

啊,誠然,一旦涉及到“元XXX”事情通常就開始變得無比抽象,以至於我不禁念叨起那句訣

太極生兩儀,兩儀生四象,四象生八卦……

不過元數據這個概念在數據庫里還是比較常見的,比如,某個關係型數據庫里有張表:

水果

編號 名字 數量
1 蘋果 6
2 香蕉 3
3 5
4 橘子 3
5 菠蘿 2

數據,就是存在表裡的一條一條的記錄,(1,蘋果,6),(3,梨,5)都是數據,那麼,元數據就是凌駕於這些數據之上的用於描述數據數據,對於這張表而言,也就是這張表的表頭(關係數據理論里稱之為關係模式):(編號,名稱,數據)

划重點
元數據(Metadata):用於描述數據的數據

好像有些明朗了,但那關面向對象什麼事呢

眾所周知,類(Class)是面向對象的一個重要概念,儘管,針對於數據庫來說,對象模型和關係模型是不同的概念(上文提到的是關係模型的一個例子),但是,對象模型中的對象和關係模型中的關係,其級別是等同的。

關係……又對象……越來越聽不懂了

好吧,我們先把關係放在一邊,我們只把上邊的東西看做一張表。

難道你就沒有把它改寫成如下形式的衝動嗎??

public class Fruit
{
    public int no;
    public string name;
    public int count;
    
    public Fruit(int no, string name, int count)
    {
        // ...
    }
}

好了,上面的類定義的語義就是

有這樣一類東西,我們稱呼這類東西為水果,結構如下……

那麼,這樣一來,我們就可以定義一個no為9,name叫做“西瓜”,count為5的一個對象,這個對象具有具體的數據。

而上面的類定義代碼,包含的就是這個類的元數據

說的再直白點吧

以人為例,數據注重的是這人的臉長啥樣,而元數據注重的是這人有沒有臉(好像不太對……)

好吧差不多了解了,但元數據和反射有什麼關係呢

反射是一些面向對象程序設計語言提供的針對對象元數據(Metadata)的一種訪問機制

本文一開始就說了,罰站20年

不過在此之前先解釋一件事,元數據在哪

任何一個面向對象的程序設計語言,其類類型都具備一個元數據的存儲,至少程序會使用這個元數據能夠動態地構造此類的對象。但不同的語言機制不同,比如C++這種的,因為直接和系統進行愉♂快的互♂動,因此元數據就直接使用系統的內存地址了,這種數據使用是很不直觀的,同時也不使用任何託管機製做後援(巨硬魔改的C++/CLI不在討論範圍內),因此這種貼近底層的語言不支持反射機制,雖然可以通過強行向程序代碼中通過工廠類模式強行注入可讀的元信息(方法參見這位大佬的文章)。

但是,正如前面所說的,如果元數據在託管編譯或解釋的狀態下會保留一份可讀的版本,這是提供給解釋器或者託管平台用的,當然,這種情況下語言一般會提供一個較為完善的元數據訪問機制,這就是反射。這類語言典型的代表就是C#(.NET託管)、Java(JVM虛擬機)、Python(解釋器提供)等。

那……反射是如何運作的呢??

反射嘛。那還不容易,拿個鏡子就可以了呀!
或者用羊角錘偷襲的方式砸膝蓋什麼的也是很容易的呀!
不過這麼說來,拿羊角錘偷襲鏡子豈不是更棒!!

正如之前所說,反射機制是對類的元數據的獲取和操縱,因此,一個重要的前提就是:

這個程序設計語言的運作機制當中,類的元數據必須是可見的,如果可讀的話那更好

只有當類的元數據是可見的,反射機制才有訪問它們的可能,但是元數據的可讀性會決定反射機制訪問它們的難易程度。

這裏補充一句,有人會說,在使用IDE或者代碼編輯器的時候,我們寫object.property這種訪問方式的時候編譯器不就直接告訴我們了么??
關於這一點,這裏暫時只說一個前提:

反射機制的實際動作是聚焦於運行時(Runtime)的。

在程序代碼編譯之前我們恣意地書寫這MyObject.id.hashCode.getFlush().balabala的時候,這是預編譯的過程,預編譯的時候當然這些元數據都是以字面形式給出的(因為你的代碼里寫了這個類的定義),你可以非常愉悅地Ctrl+C Ctrl+V或者享受着IntelliSense帶給你的N倍快樂,這個時候再談反射就沒什麼意義了,因此,反射機制訪問元數據都是在編譯后運行時發生的。

明明都是面向對象,為什麼偏偏C++不支持這個東西呢

以C++為例,這些元數據是否可見?答案是肯定的,那為什麼不支持反射機制呢,因為這些元數據是以指針的方式給出的,指針在已編譯的C++程序中的存在形式就是地址,說的再粗暴點,就是4或8字節的二進制數……
也就是說,在已經編譯完成的C++程序的眼裡,類的元數據已經變成二進制的地址碼了,如果某人在沒有源代碼的情況下想給這個項目寫一個反射機制,那麼他將不得不面對一大堆的:

0xb08dfe231a1c002e
0xb08dfe231bc128f6
0xb08dfe2417a90f5d
......

看到這些,他長舒了一口氣,優雅地點燃了一根香煙,然後毫不猶豫地戳到電腦屏幕上:

鬼知道這是什麼玩意啊!!

如果原項目加個殼、模板元編一下再做個混淆加密的話那更沒法看了,因此如果一定要實現反射機制,一般都是把反射機制直接囊括到項目開發過程當中(就像上面那位大佬的文章中提到的那樣,原項目的作者也是反射機制的構造者)。
這樣的話就會存在一個上上上個世紀汽車行業出現的問題:

這輛車的件無法用到另外一輛車上!
這個反射機制無法用到別的項目上!

當然,這樣說可能有些絕對,但以C++的方式實現一個能夠廣泛用於所有項目的反射機制應該是極端困難的。
上面大佬的文章當中,這個C++的項目要使用反射機制,是藉助工廠模式實現的,關於這些的實現方法,詳見大佬文章(當然我自己也沒完全看懂)

那託管語言又如何呢

C#、Java,這兩種語言都是託管代碼的(C#使用.NET進行託管,Java則交給了JVM虛擬機)。

與C++不同的是,他們並不直接接觸系統底層,而是通過中間代碼訪問底層的。

中間代碼由誰處理呢,C#是通過.NET提供的CLR,產生的中間語言是程序集,而Java靠的是JVM,其中間產物是class文件。
如果有幸使用一些IDE打開這兩個文件往裡窺探一遭的話,我們應當不難從中找到這些元數據的信息。

這就好像,一群孩子進了幼兒園,一個託管老師全程進行看護。

把拔碼麻區上辦,我區悠貳園吶

當然,託管老師肯定是知道孩子叫什麼名的,訪問他們自然也是很容易的。同理,託管環境(或虛擬環境)也是一樣的,因為銜接上下兩層,因此把底層的元數據和上層的可讀文本構造反射的橋樑是很容易辦到的,因此,C#和Java都提供了一套非常完善的反射庫,他們可以被用於使用這兩種語言寫的任意一個類當中。

好了,道理我都懂,但為什麼要反射呢?

反射能幹什麼呢

舉個最簡單的例子

我……我有一個夢想,我想要這樣一個函數,能夠返回Person類是否有我所說的方法,但是我不知道Person類里有什麼,比如我想問他有沒有Eat()方法,它返回true,我問他有沒有Fly()方法,它能返回false

好了,換作是你,你會怎麼實現這樣一個函數呢??

而反射機制恰恰做到了!
你提供給反射機制一個字符串形式的函數名,反射機制不僅可以得知這個函數是否存在,甚至能幫助你去執行這個函數(Invoke)。

什麼,你不好問它有沒有某個函數??好啊,反射機制甚至可以告訴你這個類都有哪些屬性哪些函數,繼承自誰,可見性如何,是否抽象等等。

那反射在什麼時候比較好用呢

上面那個例子其實就是一個經典的用途。

或者,我們可以考慮另外一個場景。

你寫了某個函數接受了一個抽象為Object的對象,你希望,如果Object的對象存在方法Grow則調用之,否則什麼也不做。

這個時候首先可以通過反射機制確定方法是否存在,但即便方法已經存在,我們是無法直接調用的,因為對象已經抽象為Object,而Object並不存在方法Grow,所以直接調用就洗洗睡了。

我們不能具象回來么??

如果我們知道類在抽象之前是什麼類型的時候,那當然可以具象化回來。
但是抽象雖然發生於編譯時或運行時(動態創建的對象),但具象類型的獲知卻是在編譯之前的代碼源文件,而且還有些時候你根本無法知道原類型,那也沒辦法拆箱。


這裏面我為了方便,也是想不出啥更好的詞
這裏我稱派生類基類的多態轉化為抽象
反過來的過程稱為具象

那我還怎麼調用Grow

反射機制可以獲取到完整的可用方法的列表,我們在列表中找到了Grow,存在形式為Method/MethodInfo對象或乾脆就是個字符串。

但無論是哪種,obj.Grow();是不可能了,好在反射機制連這件事都考慮在內了——Invoke調用!!

反射機制不僅知道你想要什麼方法,還可以幫助你調用這個方法,這個調用就通過一個叫做Invoke的方法完成。

不同語言對Invoke的定義不盡相同但功能上大同小異,通過Invoke調用某方法的過程實質上是轉調回調(或者是間接調用)。
間接調用比直接調用更加的強大靈活,但繞了遠路。

還有什麼比較宏大一點的應用么??

宏大一點……好吧,其實每一個磅礴的工程都是從一點一滴做起的。

一個很經典的案例,就是上文那篇大佬文章里的一個常用功能——序列化(Serialization)
雖然C#和Java本身就有可以用於序列化的一些結構和功能庫(Serializable接口之類的),但是有些時候我們對序列化機制如果有更高的可定製性要求的時候,我們往往傾向於自己構建一套心儀的序列化功能庫。

於是乎就有一個最簡單的問題擺在面前:

現在有Class1類的對象,還有Class2類的對象,還有Class3類的一些對象想要轉化成可解析的內容,以供發送或保存(當然這也就意味着,這些對象的所有屬性和狀態都要保存),但是這老大老二老三一家一個樣,屬性也各不相同,我又不想挨個單獨寫,那該怎麼辦呢??

現在有了反射機制,問題就很容易解決了。三胞胎嫌分起來麻煩??反射機制可以把他們安排的明明白白!!你可以向反射類提供一個完整的類名,反射機制就能保證給你這個類對應的可用屬性的列表,以及一整套處理方案(Get和Set),之後還不是想來啥來啥,美滋滋~~

當然,以上都是反射機制用途中小的不能再小的冰山一角,比如我還可以通過反射機制根據我的輸入創建我想要的類型的對象等等。

哇,反射這麼強大??我要滿地反射!!

冷靜點!任何事物都有多面性,反射也不例外,我們看看反射機制有什麼特點,它到底是否適合所有情形。

極致靈動(Flexi Frenzy) 稀有屬性

反射機制可以讓你的代碼非常靈活,以不變應萬變。
這也正是反射機制帶來的最大的好處。

未卜先知(Fortune Tell) 普通屬性

反射機制是在運行時起作用,當然,運行期間發生什麼,編譯之前是無法獲知的,反射就是處理這件事的。

效率捉急(Emaciated Efficiency) 糟糕屬性

反射機制最大的問題!

反射機制的效率是十分低下的,首先在運行時獲取元數據再轉化成可讀形式就不是一個很快的過程,而反射的Invoke調用是個不折不扣的間接調用。

不當地使用大量反射會導致程序效率的急劇下降。

代碼膨脹(Code Expansion)

顯然,用反射進行調用的代碼往往比直接調用寫起來複雜,所以除非你寫代碼是按行數計工資,否則能直接調用就不要反射。

健壯風險(Robustness Risk)

反射機制一般允許用戶傳入字符串……

然後就是萬劫不復深淵之伊始

這時候用戶傳的字符串就可以非常的五花八門了,就好像一個動物園裡,反射機制是一個可愛的小動物,而遊客開始不分青紅皂白地對它投各種食,良莠不齊,可是你的反射機制很脆弱,它可禁不起這折騰,吃到不好的東西就會生病罷工(拋異常,然後中止),因此你這當奶媽奶爸就要多操心,幫它收拾(捕獲),告訴他如何分辨食物(預先判斷)……

不過呢,有些時候引入反射機制恰恰就是出於健壯性的考慮……

如果我養的不是個反射機制而是一隻熊貓的話我會上天的!!

總結

反射是個強大的武器,但使用應多加謹慎!

以上

【精選推薦文章】

智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

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

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

用象棋的思維趣說IT人的職業發展和錢途,在上海軟件行業,我見到的年入50萬的眾生相——我們該如何努力從而達到這個目標

    最近我花了不少功夫在學習象棋,也學習了王天一等高手的棋路,感覺IT人的職業和下棋一樣,往好了講,爭主動權爭實惠只爭朝夕,往壞了講,一步走錯得用多步來彌補,如果錯誤太大未必能彌補回來。在本文里,就用下棋這種比較輕鬆的話題來聊聊程序員該如何經營自己的職業。

1 對手是誰,如何算輸贏

    做任何事情都要明確對象和目標,下棋時,對手和目標都很明確,但在職業規劃里,對手是誰?如何算輸贏?

    對手從小了講,是自己,畢竟除山中賊易,除心中賊難,往大了講,是其它IT人。

    如何算輸贏?這有很多標準,往大了講,達到財務自由或者“掙到一個億”算贏,往中了講,有房有車有孩子,或者達到中產水平,往小了講,能在社會上立足,收入在平均水平以上。在本文里,不說過於遠大的目標,倒也不是遙不可及,而是再遠大的目標也是得靠腳踏實地,也不說“收入超平均水平”,畢竟這還是比較容易的,就算“達到中產水平”為贏。

    再具體點,如何算中產?我找了上海2018年中產的標準如下。

    1,有兩套及以上住房(不含和父母共有的),至少一套達非普標準;

    2,沒有房貸,或各項負債合計低於總資產30%。

    3,家庭年收入(不含父母)達50萬以上。

    之前本人寫過篇博文,在上海軟件行業,我見到的年入50萬的眾生相——我們該如何努力從而達到這個目標,年入50萬也算是中產吧。 

2 少走緩手棋

    一盤象棋有60個回合不算長,算下從大學畢業到退休,大致有30年吧,大概平攤下來,半年時間能算一個回合,也就是說,用半年的努力,自己職業上應該有顯著的效果。

    下棋時不怕局勢一般,就怕下緩手棋,高手之間過招,2步緩手足以輸棋,一般的人下棋,也經不起3步以上的緩手。

    那麼職業乃至人生的棋盤上,什麼叫緩手呢?

    1 在公司里得過且過,不主動追求技術進步,導致半年左右技術等方面沒進步。

    2 自己的技能已經得到提升,但出於安逸,沒有追求更高的工資或者更高級的職位。

    3 當工資收入達到一定水準后,不思進取,不積極探索新的掙錢渠道和掙錢模式。

    那麼在工作中,一旦下緩手棋會有什麼後果呢?

    1 半年不進步,看似沒什麼影響,但由奢入儉難,一旦得過且過的日子過慣了,再想上進就難了。

    2 如果一年不進步,技術馬上會落後於平均水平。

    3 一年半以上的不進步,就不說跳槽難了,這已經能導致在項目組裡日子難過(因為別人都在進步),更有甚者,如果公司動蕩,這批混日子而且技術不行的人,估計會第一批被淘汰,淘汰后甚至後面工作也難找。 

3 只爭朝夕,爭主動權更得靠效率

    和“少走緩手棋”相對的是“力爭主動權”。

    象棋里主動權直觀表現為,我可以從容調度子力進攻,能從容圍剿對方的子力從而得到子力優勢。在職業規劃里,主動權表現為,我不僅能從容應付當前的工作,而且由於我的技術以及能力在不斷提升,後繼我的技術發展方向和公司選型,我都掌握主動。從實惠角度來講,增加收入的主動權在自己手裡,在當前公司,我可以通過晉陞提升收入,我也可以通過跳槽提升收入,還可以通過各種額外手段提升收入。

    象棋里爭奪主動權靠積極和效率,所謂用最小的“度數”(棋子的移動步數)把子力放置到(給對方造成威脅最大的)積極位置。平時工作中,爭奪主動權的方式也是如此。

    怎麼算積極呢?列下我見到的比較積極的大牛事例。    

    1 態度端正,一天當两天用,在工作中,也絕無看網頁等做和工作無關事情的情況,有問題也是馬上確認積極解決,絕無拖沓。

    2 盡可能地利用各種時間碎片幹活或提升技術,比如我公司里的大牛中午休息時間也在看技術文章,博客園裡的一些大牛也是利用早上上班前或下班回家后的時間寫技術博客,總之積極地盡一切可能提升自己。

    3 從來不停止提升自己,比如我之前互聯網公司的一位大牛,Spring方面在業內非常出名,但平時也時一有時間就看Spring文章,一有可能就出書出視頻教程。

    而提升工作效率除了不斷總結之外,還得盡可能減少不必要的休閑娛樂時間,比如我之前互聯網公司的多位大牛,都是手機上沒有遊戲app,也沒聽說過追劇。

    知易行難,其實道理也很通俗,做起來並不容易,我的體會是,在開始階段稍微逼下自己,比如早起寫博客,工作時盡量不看無關事,平時積極些,可能最多一個月,當形成習慣時,想改也難。 

4 勢在子先,首先得提升自己的掙錢能力

    象棋里有寧失一子,不失一先的說法。如果把象棋中的形勢比作個人技能綜合能力(把握主動權的能力),那麼“子力”就好比掙到的錢。

    也就是說,能力比錢重要,一方面我們應該踏踏實實地提升能力,排除短期跳槽帶來的金錢誘惑,另一方面,在必要時,可以用錢買技能,比如在必要的時候買收費專欄里的知識,甚至參加培訓班。

    我見到的反面例子是,在之前的外企里,某人本身能力也就一般,但還在外面干兼職,這就屬於要錢不要技能,結果短時間內錢確實掙到了,但由於不注意提升能力,最後被迫離開了項目組。而正面的例子就比較多了,不少人在進項目組時能力一般,但平時通過看各種(免費和收費)資料,最後成為項目組內的棟樑。

    再說下應該重視哪些能力?

    1 對底層代碼的理解以及分析能力。

    2 能在短時間內全局掌握系統架構的能力。

    3 比較值錢的,比如大數據機器學習和分佈式的技能。

    4 帶團隊的能力,比如對外能和客戶方溝通,在公司內能和其它組協調扯皮,在組內能合理分派活,合理監管質量同時保證進度。 

5 優勢情況下更不能大意

   下棋時,我經常遇到如下的場景,我或者對手優勢很明顯,但由於一步走錯,局勢逆轉,對此象棋有“臨殺誤急“和“贏棋不鬧事”的說法。

    大家在工作中,這種情況也不能說沒,比如發布項目,什麼工作都準備好了,看似勝利在望,但在發布時,由於大意導致操作事務,最後出現產線問題, 

    象棋在沒贏前,任何走法都得反覆斟酌,同樣在發布項目等工作沒通過驗證前,也不能放鬆,這不僅得到主觀上態度端正,更得“未慮勝,先慮敗” ,盡量把可能導致失敗的因素都考慮全,並針對性地做預案或補償措施。

    我見過不少下棋的人,只會一廂情願,或者沉溺於自己的優勢中,或者主觀上忽視對方的反擊手段,這種人下棋贏了是運氣,輸了是必然,而且這樣下能力也不會提升。同樣,在做項目等工作時,寧可做好針對最壞情況的準備,比如發布時做好,甚至操練好回退預案,寧可用不到。這樣的話,一方面能確保勝局,另一方由於考慮周全,技能上一定也會有提升。 

6 取勝得靠進攻手段,IT人掙錢也得積極

    象棋中取勝一般有兩種方法,一種是確保自己不犯錯然後坐等對方走錯,另一種是積極主動擴大主動權,積優勢為勝勢。

    對應IT人掙錢方式,一種是干好手頭的活,確保不出問題,然後循例升職和加工資,另一種則是積極擴大自己的品牌,不斷探索新的掙錢方式,相比之下,後者更加積極,掙錢效率應該也優於前者。

    正如特級大師的擴大先手和進攻手段得靠慢慢積累,IT人掙錢的方式也得從小做起。比如小到通過寫博客積累,然後可以開專欄出視頻教程,再大點可以通過各種渠道找些項目,再大些可以做自己得產品。

    說起來容易做起來難,但一旦有積極想法了,而不是坐等工資等穩定收入,其它不敢說,至少自己的格局能不斷變廣,掙錢的機會也會越來越多。 

7 逆勢中不能自暴自棄,只要努力,就有翻盤可能

    下棋時不可能老是贏,有不少時候局面會很難看,只能苦苦支撐。相比之下,工作中也不可能一帆風順,比如工作氛圍不好比較壓抑,有996工作壓力大,或者錢少,這種時候絕不能自暴自棄。

    特級大師之間,出現翻盤的案例也不少,更何況業餘的,比如有10盤逆勢棋,如果自暴自棄亂下,估計最多一兩盤能下翻盤,但如果咬牙堅持每步都下好,翻盤的可能性就大很多。

    對應的在工作中,哪怕情況再差,每天也得儘力做好自己的事,必要時更得提升自己的能力,指不定哪天就時來運轉了,或者這個公司沒機會,由於自己一刻也沒放鬆反而在不斷提升自己的實力,在下家公司里就能春風得意了。

8 總結:人生棋局裡,一時輸贏不能代表今後的輸贏

     大家經常能看到,某人前幾年由於混日子,活得沒指望,但突然想明白了,只用了半年就完成了逆轉,也就是說,雖然一步走錯需要用更大的代價來彌補,但一時的輸贏絕不能代表一世的得失。所以,在任何時候都得積極向上力爭主動。本文也算戲說,大家在一笑之餘如果感到有意思,或者有收穫,請幫忙推薦下本文,謝謝大家。

版權說明:

    有不少網友轉載和想要轉載我的博文,本人感到十分榮幸,這也是本人不斷寫博文的動力。關於本文的版權有如下統一的說明,抱歉就不逐一回復了。

    1 本文可轉載,無需告知,轉載時請用鏈接的方式,給出原文出處,別簡單地通過文本方式給出,同時寫明原作者是hsm_computer。

    2 在轉載時,請原文轉載 ,謝絕洗稿。否則本人保留追究法律責任的權利。

【精選推薦文章】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

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

附004.Kubernetes Dashboard簡介及使用

一 Kubernetes dashboard簡介

1.1 Web UI簡介

dashboard是基於Web的Kubernetes用戶界面。可以使用dashboard將容器化應用程序部署到Kubernetes集群,對容器化應用程序進行故障排除,以及管理集群資源。可以使用dashboard來概述群集上運行的應用程序,以及創建或修改單個Kubernetes資源(例如部署、任務、守護進程等)。可以使用部署嚮導擴展部署,啟動滾動更新,重新啟動Pod或部署新應用程序。
dashboard還提供有關群集中Kubernetes資源狀態以及可能發生的任何錯誤的信息。

二 dashboard部署

2.1 下載yaml

  1 [root@master ~]# mkdir dashboard					#建議將yaml存儲到本地
  2 [root@master ~]# cd dashboard/
  3 [root@master dashboard]# wget https://raw.githubusercontent.com/kubernetes/dashboard/master/aio/deploy/recommended/kubernetes-dashboard.yaml

 

2.2 修改為國內源

  1 [root@master ~]# cd dashboard/
  2 [root@master dashboard]# vi kubernetes-dashboard.yaml
  3 ……
  4 image: mirrorgooglecontainers/kubernetes-dashboard-amd64:v1.10.1
  5 ……

 
提示:將yaml文件中的image字段修改為mirrorgooglecontainers/kubernetes-dashboard-amd64:v1.10.1。

2.3 安裝

  1 [root@master dashboard]# kubectl apply -f kubernetes-dashboard.yaml
  2 [root@master ~]# kubectl get pod --all-namespaces -o wide| grep kubernetes-dashboard			#確認驗證
  3 kube-system	kubernetes-dashboard-68ddcc97fc-c5thv	0/1	Running	0	30s	<none>	node2	<none>	<none>

 

三 dashboard訪問方式

3.1 訪問方式概述

安裝dashboard后,需要為用戶配置對群集資源的訪問控制。從版本1.7開始,dashboard不再具有默認授予的完全管理員權限。默認所有權限都被撤銷,並且只授予了使Dashboard工作所需的最小權限。
提示:本說明僅針對使用Dashboard 1.7及更高版本的用戶。如果確信dashboard需要授予管理員權限,可參考:《附006.Kubernetes身份認證》
通常,其他應用程序不應直接訪問dashboard。
dashboard有以下三種訪問方式:
kubectl proxy:只能在localhost上訪問。訪問地址:http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
NodePort:編輯 kubernetes-dashboard.yaml文件中,將 type: ClusterIP 改為 type: NodePort,確認dashboard運行在哪個節點后。訪問地址:https://<node-ip>:<nodePort>
apiserver:需要在瀏覽器中安裝用戶證書。訪問地址: https://<master-ip>:<apiserver-port>/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
提示:kubectl proxy方式不推薦,建議使用有效證書來建立安全的HTTPS連接。

3.2 kubectl proxy

  1 [root@master ~]# kubectl proxy
  2 [root@master ~]# curl http://127.0.0.1:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/	#訪問

 
提示:建議通過後端形式,並且允許所有主機訪問的方式:

  1 [root@master ~]# nohup kubectl proxy --address='0.0.0.0' --accept-hosts='^*$' &

3.3 NodePort

NodePort訪問儀錶板的方式僅建議用於單節點設置中的Kubernetes環境。

  1 [root@master ~]# kubectl -n kube-system edit service kubernetes-dashboard
  2 ……
  3    type: NodePort
  4 ……
  5 #將type: ClusterIP  修改為 type: NodePort。

 
提示:以上操作也可通過以下命令一步完成:

  1 [root@master ~]# kubectl get pods --namespace=kube-system | grep dashboard
  2 kubernetes-dashboard-68ddcc97fc-c5thv   1/1     Running   0          3h14m
  3 [root@master ~]# kubectl describe pod kubernetes-dashboard-68ddcc97fc-c5thv --namespace=kube-system | grep Node
  4 Node:               node2/172.24.8.73

 
測試訪問:
瀏覽器訪問:http://172.24.8.73:30343/
提示:若部署的Kubernetes集群為多節點集群,需要通過以上方式查找dashboard所在的node節點,若為單節點集群,則直接訪問http://<master>:<port>即可。

3.4 apiserver

若Kubernetes API服務器公開並可從外部訪問,可瀏覽器直接訪問:https://172.24.8.71:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
注意:apiserver默認情況下使用system:anonymous用戶進行訪問,因此沒有權限打開相應資源。只有在選擇在瀏覽器中安裝用戶證書時,才能使用這種訪​​問儀錶板的方式。
NodePort和apiserver都需要配置相應的認證才可訪問,確定某種方式方式后需要配置認證類型。

3.5 Ingress

dashboard也可以使用ingress進行資源公開。
可參考:https://kubernetes.io/docs/concepts/services-networking/ingress/

四 dashboard驗證方式

瀏覽器訪問的時候需要加載相應證書,部署完成后默認已經創建相應證書,可參考附01進行導出。由於Kubernetes默認證書可能過期導致無法訪問dashboard,本實驗在已成功部署Kubernetes後手動重新創建證書。

4.1 創建證書

  1 [root@master ~]# mkdir /etc/kubernetes/dash_pki
  2 [root@master ~]# cd /etc/kubernetes/dash_pki/
  3 [root@master dash_pki]# openssl genrsa -out ca.key 2048				#生成一個 2048 bit 的 ca.key
  4 [root@master dash_pki]# openssl req -x509 -new -nodes -key ca.key -subj "/CN=172.24.8.71" -days 10000 -out ca.crt	                #根據 ca.key 生成一個 ca.crt(使用 -days 設置證書的有效時間)
  5 [root@master dash_pki]# openssl genrsa -out server.key 2048			        #生成一個 2048 bit 的 server.key
  6 [root@master dash_pki]# openssl req -new -key server.key -subj "/CN=172.24.8.71" -out server.csr			                #根據 server.key 生成一個 server.csr
  7 [root@master dash_pki]# openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 10000	#根據 ca.key、ca.crt 和 server.csr 生成 server.crt
  8 subject=/CN=172.24.8.71
  9 Getting CA Private Key
 10 [root@master dash_pki]# openssl x509  -noout -text -in ./server.crt		        #查看證書

 

4.2 修改默認證書配置

  1 [root@master ~]# cd dashboard/
  2 [root@master dashboard]# kubectl delete -f kubernetes-dashboard.yaml		#刪除使用默認證書所創建的dashboard
  3 [root@master dashboard]# ll /etc/kubernetes/dash_pki/
  4 [root@master dashboard]# kubectl create secret generic kubernetes-dashboard-certs --from-file="/etc/kubernetes/dash_pki/server.crt,/etc/kubernetes/dash_pki/server.key" -n kube-system	#掛載新證書到dashboard
  5 [root@master dashboard]# kubectl get secret kubernetes-dashboard-certs -n kube-system -o yaml	#查看新證書

 

4.3 重新部署dashboard

  1 [root@master dashboard]# kubectl apply -f kubernetes-dashboard.yaml
  2 [root@master dashboard]# kubectl get pods --namespace=kube-system | grep dashboard		#確認驗證

 

4.4 導入證書

將server.crt導入IE瀏覽器,導入操作略。

4.5 訪問測試

本試驗基於apiserver訪問方式+Kubeconfig身份驗證進行登錄。
通過apiserver形式訪問:https://172.24.8.71:6443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
提示:dashboard登錄整個流程可參考:https://www.cnadn.net/post/2613.htm
提示:apiserver方式見3.4,Kubeconfig驗證方式見《附006.Kubernetes身份認證》中的3.5。  

附001:導出當前Kubernetes證書

[root@master ~]# grep ‘client-certificate-data’ ~/.kube/config | head -n 1 | awk ‘{print $2}’ | base64 -d >> kubecfg.crt
[root@master ~]# grep ‘client-key-data’ ~/.kube/config | head -n 1 | awk ‘{print $2}’ | base64 -d >> kubecfg.key
[root@master ~]# openssl pkcs12 -export -clcerts -inkey kubecfg.key -in kubecfg.crt -out k8s.crt -name “kubernetes-client”
Enter Export Password:[x120952576]
Verifying – Enter Export Password:[x120952576]
使用相應的密碼,將k8s.crt導入IE瀏覽器,導入操作略。    
我的博客即將同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=20stclch1nfo4

【精選推薦文章】

智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

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

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

20年研發管理經驗談(十一)

本文繼20年研發管理經驗談(十)。

此文是對我個人測試思想的一個總結,由於經驗不夠,知識淺薄,如果有什麼不合理的地方請一笑了之。

一、面向對象的概念
  所謂的面向對象是軟件開發的一種重要的思維方式,是把軟件開發過程中出現的事物,用一個個的對像來分析.一般一張數據表可以封裝為一個對像。用個形象的比喻:我們現在要做一張桌子,首先我們考慮到的是我們要做的是什麼?是桌子;桌子是用來干什麼的呢?是用來吃飯、喝茶、看書、打麻將的;然後就要考慮桌子由哪些部分組成?由桌面和桌腿來組成;接着我們需要考慮我們採用什麼材料呢?紙?不行…那可什麼都幹不成,OK,用木頭;接着就可以開始把組成桌子的組件做為對象開始分析–桌面如何做是用刀砍的還是用刨子刨呢?桌腿又如何做…
  一套完整的方法成形了就可以具體實現了,在做的過程中桌面要做多大,桌腿要做多長都要事先考慮到是不是要留出接口,這些就是我們給組成桌子的組件賦予的屬性。OK,現在可以做出具體的實物了,做好實物組件(對象)以後就要將做好的桌面桌腿進行組裝,由於我們事先考慮好了組件的屬性,考慮到了必須預留接口,因此我們可以很輕易的組合成功,桌子做出來了。以上就是面向對象的思想的一個簡要的比喻

  了解面向對象必須了解的幾個名詞:對象、方法、屬性、繼承、多態。

 

二、遊戲測試
  遊戲測試是整個軟件測試行業中比較特殊的一部份,他有着大多數軟件測試的共性,也具備自身的特性,而相對於許多通用軟件的測試來說,遊戲測試所具備的特性是非常明顯的。現在就簡要的說說上面提到的共性和特性。
共性:
1、測試的目的就是為了盡可能的發現軟件存在和潛在的問題。
2、測試都是需要測試人員按照產品行為描述來實施。產品行為描述可以是書面的規格說明書、需求文檔、產品文件、或是用戶手冊、源代碼、或是工作的可執行程序。
3、每一種測試都需要產品運行於真實的或是模擬環境之下。
4、每一種測試都要求以系統方法展示產品功能, 以證明測試結果是否有效, 以及發現其中出錯的原因, 從而讓程序人員進行改進。
總之,軟件測試就是對產品進行盡可能的全面檢查,盡可能的發掘bug,提高軟件質量,從而為企業創造利潤。

特性:
  網絡遊戲世界從某種意義上說是另一個人類社會,只是人們在網絡遊戲世界中進行着在被允許的範圍內的活動,包括了修鍊、交流、合作、經商、欺詐、情感、衝突等等。而在遊戲製作時這些進行這些行為的部分就是一個個完整的功能,我們在進行測試的時候,需要考慮的不僅僅是能否實現功能,要考慮更多的是人們在進行操作時會如何做,可能有多少種做法,這些做法應該有什麼樣的響應,哪些做法是被禁止的,在進行了被禁止的操作后應該有什麼的響應。因此這裏就是涉及到了遊戲世界的測試方法:
1、遊戲情節的測試,主要指遊戲世界中的任務系統的組成, 有人也稱為遊戲世界的事件驅動, 我喜歡稱為遊戲情感世界的測試。
2、遊戲世界的平衡測試,主要表現在經濟平衡,能力平衡( 包含技能, 屬性等等),保證遊戲世界競爭公平。
3、遊戲文化的測試,比如整個遊戲世界的風格, 是中國文化主導,還是日韓風格等等,大到遊戲整體,小到N P C( 遊戲世界人物) 對話, 比如一個書生,他的對話就必需斯文, 不可以用江湖語言。

以上陳述中關於遊戲特性的部分概念是曾在金山公司的測試人陳衛俊提出來過的,在此引用。

 

三、如何用面向對象的思想進行測試
  上面了解了面向對象的概念以及遊戲測試和通用軟件測試的區別以後我們可以進入正題了—如何用面向對象的思想進行遊戲測試?
  首先,和所有通用軟件以及硬件產品一樣,我們的遊戲是一個產品,是一個存在的實體,因此,我們把這個”實體”當做一個大的對象開始分析,整個遊戲由哪些部分構成,而構成整個遊戲的大的部分又由哪些組件構成,認真分析完這些以後就可以着手進行測試了,注意,這裏說”可以進行測試了”意思不是馬上就能進入測試,聽我慢慢道來。 
  ”工欲善其事,必先利其器”—某位高人說的,我們做測試也是一樣,分析完畢后,我們要做的還是分析 ^_^ 不過這裏的分析和之前的分析有點點區別,這裏我們需要分析的是具體功能的關鍵測試點和風險點,測試不能盲目,打蛇要打七寸…..在這裏我們就是把某個具體的功能作為一個對象,我們要分析組成這個功能的是哪些因素,一共有哪些測試點,哪些測試點是關鍵點,哪些是高風險點,一一列舉出來,這樣我們就一目瞭然了,然後就是我們打算採用何種方式來進行測試,這裏就是方法了.測試的方式可能有很多種(比如在不同的操作系統下進行測試等),因此我們也需要一一列舉,此外我們需要分析的還有測試過程中我們需要用到的具體測試手法、具體的數值、特定的環境等等這些就是屬性,當然這些我們也必須整理出來。
  將以上提到的對象、方法、屬性整理成文檔就是我們測試時所必須的測試用例了。當然,還是老話,測試用例的優劣是以覆蓋面來評判的,這裏就需要經驗了,簡單說就是靠累積以及學習。
  OK,測試用例我們完成了,剩下的就是實施測試了,實施測試時個人覺得一定要按照用例的描述去執行,如果在測試過程中覺得用例不完善可以先更新用例再進行測試,一定不要先測試再補用例!!
  接下來就是測試報告,報告中包含的應該有所有測試點的簡述,包括了通過測試的部分和存在bug的部分。bug管理是很重要的一環,在這裏不詳述。
  關於測試流程在這裏就不做具體說明,在這裏希望闡述的是一種測試的思想,個人覺得測試除了要有紮實的相關基礎知識以便更深入的了解產品以外,更重要的是測試思想,具備了完善的測試思想才能有計劃的完成每一步測試,從而提高測試的效率,保證測試產出的質量,也更好的保證產品的質量。面向對象是一種思想,用面向對象的思想來組織、計劃、實施測試工作,能讓我們在測試工作中有很強的目的性,他能清楚地告訴我們今天要做什麼,明天要做什麼,我們要做的是哪些,說回遊戲測試,遊戲開發是一個迭帶的開發模式,因此測試工作往往會有很大的隨機性,因此當我們接到一個新功能時,首先要明確我們要測得這個功能是做什麼的,有什麼用,這個功能怎麼使用。OK,我們了解了這個功能是什麼,能做什麼就可以開始細化分析了:這個功能共由哪些子功能組成,這些子功能是否有自己的子功能點,一層層的分析下去,然後就是從最底層的功能點分析:這個功能什麼情況下要發揮其功效,發揮其功效的因素有哪些,怎麼樣去發揮具體的功效,該功能有沒有相應的容錯機制,這些就是我們的詳細測試點和測試手法。然後向上一層一層分析,一直到最頂層就是我們的功能完整的測試方針。這樣我們就把面向對象的思想完全用到了測試中。當然,在分析的過程中我們必須考慮到,與遊戲情節、遊戲風格、遊戲平衡、玩家的易用性是否衝突等等因素,適時地給策劃提出正確的建議。

  以上陳述的種種,無非是想將面向對象的思想用到測試中的好處列舉出來,或許經驗淺薄說的有些蒼白,但是我堅信一點,測試是一種思想,是一種絕對不亞於開發思想的學問,要想做好測試就需要具備良好的測試思想,或者良好的測試思想不是一天两天能夠形成的但是相信只要把測試當做一種職業,當作一種事業來做,把自己真正當成保證產品質量的最後一道關卡,成為一個BT(BestTester)就指日可待了!

軟件測試用例的認識誤區

  軟件測試用例是為了有效發現軟件缺陷而編寫的包含測試目的、測試步驟、期望測試結果的特定集合。正確認識和設計軟件測試用例可以提高軟件測試的有效性,便於測試質量的度量,增強測試過程的可管理性。

  在實際軟件項目測試過程中,由於對軟件測試用例的作用和設計方法的理解不同,測試人員(特別是剛從事軟件測試的新人)對軟件測試用例存在不少錯誤的認識,給實際軟件測試帶來了負面影響,本文對這些認識誤區進行列舉和剖析。

 

 

誤區之一:測試輸入數據設計方法等同於測試用例設計方法

  現在一些測試書籍和文章中講到軟件測試用例的設計方法,經常有這樣的表述:測試用例的設計方法包括:等價類、邊界值、因果圖、錯誤推測法、場景設計法等。這種表述是很片面的,這些方法只是軟件功能測試用例設計中如何確定測試輸入數據的方法,而不是測試用例設計的全部內容。

  這種認識的不良影響可能會使不少人認為測試用例設計就是如何確定測試的輸入數據,從而掩蓋了測試用例設計內容的豐富性和技術的複雜性。如果測試用例設計人員把這種認識拿來要求自己,則害了自己;拿來教人,則害了別人;拿來指導測試,則害了測試團隊。聽起來似乎是“小題大做”,但是絕不是“危言聳聽”。

  無疑,對於軟件功能測試和性能測試,確定測試的輸入數據很重要,它決定了測試的有效性和測試的效率。但是,測試用例中輸入數據的確定方法只是測試用例設計方法的一個子集,除了確定測試輸入數據之外,測試用例的設計還包括如何根據測試需求、設計規格說明等文檔確定測試用例的設計策略、設計用例的表示方法和組織管理形式等問題。

  在設計測試用例時,需要綜合考慮被測軟件的功能、特性、組成元素、開發階段(里程碑)、測試用例組織方法(是否採用測試用例的數據庫管理)等內容。具體到設計每個測試用例而言,可以根據被測模塊的最小目標,確定測試用例的測試目標;根據用戶使用環境確定測試環境;根據被測軟件的複雜程度和測試用例執行人員的技能確定測試用例的步驟;根據軟件需求文檔和設計規格說明確定期望的測試用例執行結果。

 

 

誤區之二:強調測試用例設計得越詳細越好

  在確定測試用例設計目標時,一些項目管理人員強調測試用例“越詳細越好”。具體表現在兩個方面:盡可能設計足夠多的設計用例,測試用例的數量閱讀越好;測試用例盡可能包括測試執行的詳細步驟,達到“任何一個人都可以根據測試用例執行測試”,追求測試用例越詳細越好。

  這種做法和觀點最大的危害就是耗費了很多的測試用例設計時間和資源,可能等到測試用例設計、評審完成后,留給實際執行測試的時間所剩無幾了。因為當前軟件公司的項目團隊在規劃測試階段,分配給測試的時間和人力資源是有限的,而軟件項目的成功要堅持“質量、時間、成本”的最佳平衡,沒有足夠多的測試執行時間,就無法發現更多的軟件缺陷,測試質量更無從談起了。

  編寫測試用例的根本目的是有效地找出軟件可能存在的缺陷,為了達到這個目的,需要分析被測試軟件的特徵,運用有效的測試用例設計方法,盡量使用較少的測試用例,同時滿足合理的測試需求覆蓋,從而達到“少花時間多辦事”的效果。

  測試用例中的測試步驟需要詳細到什麼程度,主要取決於測試用例的“最終用戶”(即執行這些測試用例的人員),以及測試用例執行人員的技能和產品熟悉程度。如果編寫測試用例的人員也是測試用例執行人員,或者測試用例的執行人員深刻了解被測軟件,測試用例就沒有必要太詳細。而如果是測試新人執行測試用例,或者軟件測試外包給獨立的第三方公司,那麼測試用例的執行步驟最好足夠詳細。

 

誤區之三:追求測試用例設計“一步到位”

  現在軟件公司都意識到了測試用例設計的重要性了,但是一些人認為設計測試用例是一次性投入,測試用例設計一次就“萬事大吉”了,片面追求測試設計的“一步到位”。

這種認識造成的危害性使設計出的測試用例缺乏實用性,或者誤導測試用例執行人員,誤報很多不是軟件缺陷的“Bug”,這樣的測試用例在測試執行過程中“形同虛設”,難免淪為“垃圾文檔”的地步。

  “唯一不變的是變化”。任何軟件項目的開發過程都處於不斷變化過程中,用戶可能對軟件的功能提出新需求,設計規格說明相應地更新,軟件代碼不斷細化。設計軟件測試用例與軟件開發設計并行進行,必須根據軟件設計的變化,對軟件測試用例進行內容的調整,數量的增減,增加一些針對軟件新增功能的測試用例,刪除一些不再適用的測試用例,修改那些模塊代碼更新了的測試用例。

  軟件測試用例設計只是測試用例管理的一個過程,除此之外,還要對其進行評審、更新、維護,以便提高測試用例的“新鮮度”,保證“可用性”。因此,軟件測試用例也要堅持“與時俱進”的原則。

 

 

誤區之四:讓測試新人設計測試用例

  在與測試同行交流的過程中,不少剛參加測試工作的測試新人經常詢問的一個問題是:“怎麼才能設計好測試用例?”。因為他(她)們以前從來沒有設計過測試用例,面對大型的被測試軟件感到“老虎吃天,無從下口”。

  讓測試新人設計測試用例是一種高風險的測試組織方式,它帶來的不利後果是設計出的測試用例對軟件功能和特性的測試覆蓋性不高,編寫效率低,審查和修改時間長,可重用性差。

  軟件測試用例設計是軟件測試的中高級技能,不是每個人(尤其是測試新人)都可以編寫的,測試用例編寫者不僅要掌握軟件測試的技術和流程,而且要對被測軟件的設計、功能規格說明、用戶試用場景以及程序/模塊的結構都有比較透徹的理解。

  因此,實際測試過程中,通常安排經驗豐富的測試人員進行測試用例設計,測試新人可以從執行測試用例開始,隨着項目進度的不斷進展,測試人員的測試技術和對被測軟件的不斷熟悉,可以積累測試用例的設計經驗,編寫測試用例。

 

 

 

【精選推薦文章】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

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

kubernetes高級之集群中使用sysctls

系列目錄

在linux系統里,sysctls 接口允許管理員在運行時修改內核參數.參數存在於/proc/sys/虛擬進程文件系統里.參數涉及到很多子模塊,例如:

  • 內核(kernel)(常見前綴kernel.)

  • 網絡(networking)(常見前綴net.)

  • 虛擬內存(virtual memory) (常見前綴 vm.)

  • MDADM(常見前綴dev.)

啟用非安全sysctls

sysctls分為安全和非安全的.除了合理地劃分名稱空間外一個安全的sysctl必須在同一個節點上的pod間是隔離的.這就意味着為一個pod設置安全的sysctl需要考慮以下:

  • 必須不能影響同一節點上的其它pod

  • 必須不能危害節點的健康

  • 必須不能獲取自身pod所限制以外的cpu或內存資源

截至目前,大部分名稱空間下的sysctls都不被認為是安全的.以下列出被kubernetes安全支持:

  • kernel.shm_rmid_forced

  • net.ipv4.ip_local_port_range

  • net.ipv4.tcp_syncookies

如果日後kubelete支持更好的隔離機制,這份支持的安全列表將會擴展

所有安全sysctls默認被開啟

所有的非安全sysctls默認被關閉,管理員必須手動在pod級別啟動.包含非安全sysctls的pod仍然會被調度,但是將啟動失敗.

請牢記以上警告,集群管理員可以在特殊情況下,比如為了高性能或者時實應用系統優化,可以啟動相應的sysctls.sysctl可以通過kubelet在節點級別啟動

即需要在想要開啟sysctl的節點上手動啟動.如果要在多個節點上啟動則需要分別進入相應的節點進行設置.

kubelet --allowed-unsafe-sysctls \
  'kernel.msg*,net.ipv4.route.min_pmtu' ...

對於minikube,則可以通過extra-config來配置

minikube start --extra-config="kubelet.allowed-unsafe-sysctls=kernel.msg*,net.ipv4.route.min_pmtu"...

僅有名稱空間的sysctls可以通過這種方式開啟

為pod設置Sysctls

一系列的sysctls被劃分在不同的名稱空間內.這意味着他們可以為節點上的pod單獨地設置.僅有名稱空間的sysctls可以通過pod的securityContext被設置

以下列出的是已知的有名稱空間的.在日後的linux內核版本中可能會改變

  • kernel.shm*,

  • kernel.msg*,

  • kernel.sem,

  • fs.mqueue.*,

  • net.*.

沒有名稱空間的systls被稱作節點級別sysctls.如果你需要設置它們,你必須在每個節點的操作系統上手動設置,或者通過有特權的DaemonSet來設置

使用pod的安全上下文(securityContext)來設置有名稱空間的sysctls.安全上下文對pod內的所有容器都產生效果.

以下示例通過pod的安全上下文來設置一個安全的sysctl kernel.shm_rmid_forced和兩個非安全的sysctls net.ipv4.route.min_pmtu以及kernel.msgmax .在pod的spec裏面,安全的sysctl和非安全的sysctl聲明並沒有區別

在生產環境中,僅僅在你明白了要設置的sysctl的功能時候才進行設置,以免造成系統不穩定.

apiVersion: v1
kind: Pod
metadata:
  name: sysctl-example
spec:
  securityContext:
    sysctls:
    - name: kernel.shm_rmid_forced
      value: "0"
    - name: net.ipv4.route.min_pmtu
      value: "552"
    - name: kernel.msgmax
      value: "65536"
  ...

由於非安全sysctls的非安全特徵,設置非安全sysctls產生的後果將由你自行承擔,可能產生的後果包含pod行為異常,資源緊張或者節點完全崩潰

pod安全策略(PodSecurityPolicy)

你可以通過設置pod安全策略里的forbiddenSysctls(和)或者allowedUnsafeSysctls來進一步控制哪些sysctls可以被設置.一個以*結尾的sysctl,比如kernel.*匹配其下面所有的sysctl

forbiddenSysctlsallowedUnsafeSysctls均是一系列的純字符串sysctl名稱或者sysctl模板(以*結尾).*匹配所有的sysctl

forbiddenSysctls將排除一系列sysctl.你可以排除一系列安全和非安全的sysctls.如果想要禁止設置任何sysctls,可以使用*

如果你在allowedUnsafeSysctls字段設置了非安全sysctls,並且沒有出現在forbiddenSysctls字段里,則使用了此pod安全策略的pods可以使用這個(些)(sysctls).如果想啟用所有的非安全sysctls,可以設置*

警告,如果你通過pod安全策略的allowedUnsafeSysctls把非安全sysctl添加到白名單(即可以執行),但是如果節點級別沒有通過sysctl設置--allowed-unsafe-sysctls,pod將啟動失敗.

以下示例允許以kernel.msg開頭的sysctls被設置,但是禁止設置kernel.shm_rmid_forced

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: sysctl-psp
spec:
  allowedUnsafeSysctls:
  - kernel.msg*
  forbiddenSysctls:
  - kernel.shm_rmid_forced
 ...

【精選推薦文章】

智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

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

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

你知道和你不知道的冒泡排序

這篇文章包含了你一定知道的,和你不一定知道的冒泡排序。

gif看不了可以點擊【原文】查看gif。

1. 什麼是冒泡排序

可能對於大多數的人來說比如我,接觸的第一個算法就是冒泡排序。

我看過的很多的文章都把冒泡排序描述成我們喝的汽水,底部不停的有二氧化碳的氣泡往上冒,還有描述成魚吐泡泡,都特別的形象。

其實結合一杯水來對比很好理解,將我們的數組豎著放進杯子,數組中值小的元素密度相對較小,值大的元素密度相對較大。這樣一來,密度大的元素就會沉入杯底,而密度小的元素會慢慢的浮到杯子的最頂部,稍微專業一點描述如下。

冒泡算法會運行多輪,每一輪會依次比較數組中相鄰的兩個元素的大小,如果左邊的元素大於右邊的元素,則交換兩個元素的位置。最終經過多輪的排序,數組最終成為有序數組。

2. 排序過程展示

我們先不聊空間複雜度和時間複雜度的概念,我們先通過一張動圖來了解一下冒泡排序的過程。

這個圖形象的還原了密度不同的元素上浮和下沉的過程。

3. 算法V1

3.1 代碼實現

private void bubbleSort(int[] arr) {
  for (int i = 0; i < arr.length; i++) {
    for (int j = 0; j < arr.length - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        exchange(arr, j, j + 1);
      }
    }
  }
}

private void exchange(int arr[], int i, int j) {
  int temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

int[] arr = new int[]{5, 1, 3, 7, 6, 2, 4};
bubbleSort(arr);
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5, 6, 7]

3.2 實現分析

各位大佬看了上面的代碼之後先別激動,坐下坐下,日常操作。可能很多的第一個冒泡排序算法就是這麼寫的,比如我,同時還自我感覺良好,覺得算法也不過如此。

我們還是以數組[5, 1, 3, 7, 6, 2, 4]為例,我們通過動圖來看一下過程。

思路很簡單,我們用兩層循環來實現冒泡排序。

  • 第一層,控制冒泡排序總共執行的輪數,例如例子數組的長度是7,那麼總共需要執行6輪。如果長度是n,則需要執行n-1輪
  • 第二層,負責從左到右依次的兩兩比較相鄰元素,並且將大的元素交換到右側

這就是冒泡排序V1的思路。

下錶是通過對一個0-100000的亂序數組的標準樣本,使用V1算法進行排序所總共執行的次數,以及對同一個數組執行100次V1算法的所花的平均時間。

算法執行情況 結果
樣本 [0 – 100000] 的亂序數組
算法 V1 執行的總次數 99990000 次(9999萬次
算法 V1 運行 100 次的平均時間 181 ms

4. 算法V2

4.1 實現分析

仔細看動圖我們可以發現,每一輪的排序,都從數組的最左端再到最右。而每一輪的冒泡,都可以確定一個最大的數,固定在數組的最右邊,也就是密度最大的元素會冒泡到杯子的最上面。

還是拿上面的數組舉例子。下圖是第一輪冒泡之後數組的元素位置。

第二輪排序之後如下。

可以看到,每一輪排序都會確認一個最大元素,放在數組的最後面,當算法進行到後面,我們根本就沒有必要再去比較數組後面已經有序的片段,我們接下來針對這個點來優化一下。

4.2 代碼實現

這是優化之後的代碼。

private void bubbleSort(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {
    for (int j = 0; j < arr.length - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        exchange(arr, j, j + 1);
      }
    }
  }
}

private void exchange(int arr[], int i, int j) {
  int temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

int[] arr = new int[]{5, 1, 3, 7, 6, 2, 4};
bubbleSort(arr);
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5, 6, 7]

優化之後的實現,也就變成了我們動圖中所展示的過程。

每一步之後都會確定一個元素在數組中的位置,所以之後的每次冒泡的需要比較的元素個數就會相應的減1。這樣一來,避免了去比較已經有序的數組,從而減少了大量的時間。

算法執行情況 結果
樣本 [0 – 10000] 的亂序數組
算法 V2 執行的總次數 49995000 次(4999萬次
算法 V2 運行 100 次的平均時間 144 ms
運行時間與 V1 對比 V2 運行時間減少 20.44 %
執行次數與 V1 對比 V2 運行次數減少 50.00 %

可能會有人看到,時間大部分已經會覺得滿足了。從數據上看,執行的次數減少了50%,而運行的時間也減少了20%,在性能上已經是很大的提升了。而且已經減少了7億次的執行次數,已經很NB了。 那是不是到這就已經很完美了呢?

答案是No

4.3 哪裡可以優化

同理,我們還是拿上面長度為7的數組來舉例子,只不過元素的位置有所不同,假設數組的元素如下。

[7, 1, 2, 3, 4, 5, 6]

我們再來一步一步的執行V2算法, 看看會發生什麼。

第一步執行完畢后,數組的情況如下。

繼續推進,當第一輪執行完畢后,數組的元素位置如下。

這個時候,數組已經排序完畢,但是按照目前的V2邏輯,仍然有5輪排序需要繼續,而且程序會完整的執行完5輪的排序,如果是100000輪呢?這樣將會浪費大量的計算資源。

5. 算法V3

5.1 代碼實現

private void bubbleSort(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {
    boolean flag = true;
    for (int j = 0; j < arr.length - 1 - i; j++) {
      if (arr[j] > arr[j + 1]) {
        flag = false;
        exchange(arr, j, j + 1);
      }
    }
    if (flag) {
      break;
    }
  }
}

private void exchange(int arr[], int i, int j) {
  int temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

int[] arr = new int[]{5, 1, 3, 7, 6, 2, 4};
bubbleSort(arr);
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5, 6, 7]

5.2 實現分析

我們在V2代碼的基礎上,在第一層循環,也就是控制總冒泡輪數的循環中,加入了一個標誌為flag。用來標示該輪冒泡排序中,數組是否是有序的。每一輪的初始值都是true。

當第二層循環,也就是冒泡排序的元素兩兩比較完成之後,flag的值仍然是true,則說明在這輪比較中沒有任何元素被交換了位置。也就是說,數組此時已經是有序狀態了,沒有必要再執行後續的剩餘輪數的冒泡了。

所以,如果flag的值是true,就直接break了(沒有其他的操作return也沒毛病)。

算法執行情況 結果
樣本 [0 – 10000] 的亂序數組
算法 V3 執行的總次數 49993775
算法 V3 運行 100 次的平均時間 142 ms
運行時間與 V2 對比 V3 運行時間減少 00.00 %
執行次數與 V2 對比 V3 運行次數減少 00.00 %

5.3 數據分析

大家看到數據可能有點懵逼。

你這個優化之後,運行時間執行次數都沒有減少。你這優化的什麼東西?

其實,這就要說到算法的適用性了。V3的優化是針對原始數據中存在一部分或者大量的數據已經是有序的情況,V3的算法對於這樣的樣本數據才最適用。

其實是我們還沒有到優化這種情況的那一步,但是其實仍然有這樣的說法,面對不同的數據結構,幾乎沒有算法是萬能的

而目前的樣本數據仍然是隨機的亂序數組,所以並不能發揮優化之後的算法的威力。所謂對症下藥,同理並不是所有的算法都是萬能的。對於不同的數據我們需要選擇不同的算法。例如我們選擇[9999,1,2,…,9998]這行的數據做樣本來分析,我們來看一下V3算法的表現。

算法執行情況 結果
樣本 [0 – 10000] 的亂序數組
算法 V3 執行的總次數 19995
算法 V3 運行 100 次的平均時間 1 ms
運行時間與 V3 亂序樣例對比 V3 運行時間減少 99.96 %
執行次數與 V3 亂序樣例對比 V3 運行次數減少 99.29 %

可以看到,提升非常明顯。

5.4 適用情況

當冒泡算法運行到後半段的時候,如果此時數組已經有序了,需要提前結束冒泡排序。V3針對這樣的情況就特別有效。

6. 算法V4

嗯,什麼?為什麼不是結束語?那是因為還有一種沒有考慮到啊。

6.1 適用情況總結

我們總結一下前面的算法能夠處理的情況。

  • V1:正常亂序數組
  • V2:正常亂序數組,但對算法的執行次數做了優化
  • V3:大部分元素已經有序的數組,可以提前結束冒泡排序

還有一種情況是冒泡算法的輪數沒有執行完,甚至還沒有開始執行,後半段的數組就已經有序的數組,例如如下的情況。

這種情況,在數組完全有序之前都不會觸發V3中的提前停止算法,因為每一輪都有交換存在,flag的值會一直是true。而下標2之後的所有的數組都是有序的,算法會依次的冒泡完所有的已有序部分,造成資源的浪費。我們怎麼來處理這種情況呢?

6.2 實現分析

我們可以在V3的基礎之上來做。

當第一輪冒泡排序結束后,元素3會被移動到下標2的位置。在此之後沒有再進行過任意一輪的排序,但是如果我們不做處理,程序仍然會繼續的運行下去。

我們在V3的基礎上,加上一個標識endIndex來記錄這一輪最後的發生交換的位置。這樣一來,下一輪的冒泡就只冒到endIndex所記錄的位置即可。因為後面的數組沒有發生任何的交換,所以數組必定有序。

6.3 代碼實現

private void bubbleSort(int[] arr) {
  int endIndex = arr.length - 1;
  for (int i = 0; i < arr.length - 1; i++) {
    boolean flag = true;
    int endAt = 0;
    for (int j = 0; j < endIndex; j++) {
      if (arr[j] > arr[j + 1]) {
        flag = false;
        endAt = j;
        exchange(arr, j, j + 1);
      }
    }
    endIndex = endAt;
    if (flag) {
      break;
    }
  }
}

private void exchange(int arr[], int i, int j) {
  int temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

int[] arr = new int[]{5, 1, 3, 7, 6, 2, 4};
bubbleSort(arr);
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5, 6, 7]

7. 算法V5

這一節仍然不是結束語…

7.1 算法優化

我們來看一下這種情況。

對於這種以上的算法都將不能發揮其應有的作用。每一輪算法都存在元素的交換,同時,直到算法完成以前,數組都不是有序的。但是如果我們能直接從右向左冒泡,只需要一輪就可以完成排序。這就是雞尾酒排序,冒泡排序的另一種優化,其適用情況就是上圖所展示的那種。

7.2 代碼實現

private void bubbleSort(int[] arr) {
  int leftBorder = 0;
  int rightBorder = arr.length - 1;

  int leftEndAt = 0;
  int rightEndAt = 0;

  for (int i = 0; i < arr.length / 2; i++) {
    boolean flag = true;
    for (int j = leftBorder; j < rightBorder; j++) {
      if (arr[j] > arr[j + 1]) {
        flag = false;
        exchange(arr, j, j + 1);
        rightEndAt = j;
      }
    }
    rightBorder = rightEndAt;
    if (flag) {
      break;
    }

    flag = true;
    for (int j = rightBorder; j > leftBorder; j--) {
      if (arr[j] < arr[j - 1]) {
        flag = false;
        exchange(arr, j, j - 1);
        leftEndAt = j;
      }
    }
    leftBorder = leftEndAt;
    if (flag) {
      break;
    }
  }
}

private void exchange(int arr[], int i, int j) {
  int temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

int[] arr = new int[]{2, 3, 4, 5, 6, 7, 1};
bubbleSort(arr);
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5, 6, 7]

7.3 實現分析

第一層循環同樣用於控制總的循環輪數,由於每次需要從左到右再從右到左,所以總共的輪數是數組的長度 / 2。

內存循環則負責先實現從左到右的冒泡排序,再實現從右到左的冒泡,並且同時結合了V4的優化點。

我們來看一下V5與V4的對比。

算法執行情況 結果
樣本 [2,3,4…10000,1] 的數組
算法 V5 執行的總次數 19995
算法 V5 運行 100 次的平均時間 1 ms
運行時間與 V4 對比 V5 運行時間減少 99.97 %
執行次數與 V4 對比 V5 運行次數減少 99.34 %

8. 總結

以下是對同一個數組,使用每一種算法對其運行100次的平均時間和執行次數做的的對比。

[0 – 10000] 的亂序數組 V1 V2 V3 V4 V5
執行時間(ms) 184 142 143 140 103
執行次數(次) 99990000 49995000 49971129 49943952 16664191
大部分有序的情況 V1 V2 V3 V4 V5
執行時間(ms) 181 141 146 145 107
執行次數(次) 99990000 49995000 49993230 49923591 16675618

而冒泡排序的時間複雜度分為最好的情況和最快的情況。

  • 最好的情況為O($n$). 也就是我們在V5中提到的那種情況,數組2, 3, 4, 5, 6, 7, 1。使用雞尾酒算法,只需要進行一輪冒泡,即可完成對數組的排序。
  • 最壞的情況為O($n^2$).也就是V1,V2,V3和V4所遇到的情況,幾乎大部分數據都是無序的。

往期文章:

  • 聊聊微服務集群當中的自動化工具
  • go源碼解析-Println的故事
  • 用go-module作為包管理器搭建go的web服務器
  • WebAssembly完全入門——了解wasm的前世今身
  • 小強開飯店-從單體應用到微服務

相關:

  • 微信公眾號: SH的全棧筆記(或直接在添加公眾號界面搜索微信號LunhaoHu)

【精選推薦文章】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

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

redis的五種數據類型及應用場景

前言

redis是用鍵值對的形式來保存數據,鍵類型只能是String,但是值類型可以有String、List、Hash、Set、Sorted Set五種,來滿足不同場景的特定需求。

本博客中的示例不是將控制台作為redis的一個客戶端,而是將redis運用在java里進行測試

需要有java redis的驅動包,可以通過引入maven的依賴即可

        <dependency>
            <groupId>org.rarefiedredis.redis</groupId>
            <artifactId>redis-java</artifactId>
            <version>0.0.17</version>
        </dependency>

 

String

String類型是最基礎的一種key-value存儲形式,value其實不僅僅可以是String,也可以是數值類型。常常用來做計數器這類自增自減的功能,可用在粉絲數、微博數等。

示例

 1         //連接本地的 Redis 服務
 2         Jedis jedis = new Jedis("localhost");
 3         System.out.println("連接成功");
 4         //查看服務是否運行
 5         System.out.println("服務正在運行: "+jedis.ping());
 6         //String實例
 7         jedis.set("hello", String.valueOf(1));
 8         jedis.incr("hello");
 9         jedis.set("hello1","word1");
10         System.out.println(jedis.get("hello"));
11         System.out.println(jedis.mget("hello","hello1"));

常用命令

  • set
  • get
  • mget
  • incr
  • decr

 

List

list就是鏈表,在redis實現為一個雙向鏈表,可以從兩邊插入、刪除數據。應用場景可以有微博的關注列表、粉絲列表、消息列表等。

有一個lrange函數,可以從某個元素開始讀取多少個元素,可用來實現分頁功能。

示例

 1         /*list實例,雙向鏈表結構,適合做消息隊列,
 2         但其實真正應用中一般都會用專門做消息隊列的中間件例如RabbitMQ*/
 3         jedis.lpush("201宿舍","hlf");
 4         jedis.lpush("201宿舍","css");
 5         jedis.lpush("201宿舍","ty");
 6         jedis.lpush("201宿舍","jy");
 7         List<String> name = jedis.lrange("201宿舍",0,3);
 8         for (String person:name
 9              ) {
10             System.out.print(person+" ");
11         }

 

常用命令

  •  lpush
  • rpush
  • lpush
  • lpop
  • lrange

 

Hash

hash就是值類型存儲的是一個鍵值對形式,適合存儲對象類型信息,例如個人信息、商品信息等。

示例

 1         //hash實例,適合存儲對象
 2         HashMap<String,String> map = new HashMap<String, String>();
 3         map.put("name","hlf");
 4         map.put("sex","女");
 5         map.put("age","21");
 6         jedis.hmset("hlf",map);
 7         jedis.hset("hlf","major","software");
 8         Map<String,String> map1 = jedis.hgetAll("hlf");
 9         String age = jedis.hget("hlf","age");
10         System.out.println(map1);
11         System.out.println(age);

 

常用命令

  • hset
  • hmset
  • hget
  • hgetAll

 

Set

set表示存儲的一個元素不重合的集合,因為set集合支持查緝、並集操作,因此適合做共同好友等功能

示例

1         //set實例
2         jedis.sadd("set","hhh");
3         jedis.sadd("set","ff");
4         jedis.sadd("set","hhh");
5         System.out.println(jedis.smembers("set"));
6         jedis.sadd("set1","oo");
7         jedis.sadd("set1","ff");
8         System.out.println("交集:"+jedis.sinter("set","set1"));
9         System.out.println("合集:"+jedis.sunion("set","set1"));

 

常用命令

  • sadd
  • spop
  • smembers
  • sunion
  • sinter

 

Sorted Set

相對於Set,Sorted Set多了一個Score作為權重,使集合裏面的元素可以按照score排序,注意它是Set,所以它裏面的元素也不能重複

示例

        //sorted set實例
        jedis.zadd("set2",4,"redis");
        jedis.zadd("set2",3,"mysql");
        jedis.zadd("set2",2,"kk");
        jedis.zadd("set2",1,"redis");
        System.out.println(jedis.zrangeByScore("set2",0,4));

 

常用命令

  • zadd
  • zpop
  • zrangeByScore

 

【精選推薦文章】

智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

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

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

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

雲遊戲流媒體整體架構設計(雲遊戲流媒體技術前瞻,最近雲遊戲概念很火,加之對流媒體技術略有研究,簡單寫一些)

前言:

遙想當年阿法狗戰敗一眾圍棋國手,風氣一轉,似乎所有人都懂AI。這次谷歌又放出了stadia,國內鵝廠再次跑步進場,貴州某xx雲提前布局。

閑來無事,嘗試體驗了一下貴州某xx雲的雲遊戲(不打廣告),暫且不評論如何如何,剛好對流媒體技術略有研究,僅在這裏簡單聊一下這方面涉及的架構和技術。

架構設計:

總體架構自上而下大致分為四端:

1、雲遊戲主機端(雲遊戲運行端,或者叫雲遊戲畫面渲染端,需要接收控制指令並錄屏推流到流媒體服務)

主機端需要運行遊戲並讓通過錄屏推流程序把渲染好的遊戲畫面(其實就是錄屏)推流到流媒體服務進行實時視頻分發。

有人會想這個雲遊戲主機端可能會很複雜,其實也還好,只是包含了錄屏、推流、用戶控制指令接收和一些其他諸如計費此類的相關功能。

2、流媒體服務(用於轉發主機端推上來的遊戲實時視頻並分發出去,所有用戶都可以觀看這個視頻)

這個不需要多講了,只是用來轉發遊戲實時視頻,並不涉及雲遊戲主機的控制權。

3、控制指令轉發服務(用戶需要獲取控制指令服務的所有權才能控制雲遊戲主機)

這個是雲遊戲的控制核心,獲取某台雲遊戲主機的用戶就可以通過鍵盤或者鼠標進行雲遊戲的試玩(操作),理論上講能夠獲取該控制權的不是只有一個用戶,完全可以支持多個用戶同時控制一台雲遊戲主機。

4、客戶端(瀏覽器,pc客戶端,ios,安卓客戶端等)

客戶端需要從流媒體服務拉取實時遊戲視頻,用戶需要先獲取雲遊戲主機的控制權,才能夠發送控制指令來試玩(操作)雲遊戲(鼠標,鍵盤,手柄等)

靈魂畫師繪製結構圖:

架構示意圖-來自靈魂畫師的傾情手繪

難點或者叫待解決的點:

1、流媒體協議的選擇?高延遲才是最大殺手

從流媒體技術出身開始,實時視頻延遲一直是個比較棘手的問題,比如rtmp/http-flv等基於tcp的協議本身優化到極點也要幾百毫秒的延遲,hls這種超高延遲到幾秒的不提也罷。就目前看只有sip、rtsp以及基於udp的一些協議能夠滿足這種超低延遲的需求,但是這種協議就很難在瀏覽器上就很難實現了,除了webrtc,而webrtc協議是谷歌力推的下一代流媒體協議,不排除這次是谷歌webrtc技術的奠基之作,拭目以待。

2、雲遊戲主機控制指令的所有權?依然是延遲

這個所有權其實不算是難點,只是用戶獲取某台雲遊戲主機的控制權而已。難點在於控制指令的延遲,沒錯,就是網絡延遲。尤其是在拉取實時視頻時,在視頻已經佔用大量帶寬的情況下,在這種網絡負載或者網絡波動較大的情況下控制指令延遲或許值得重視。

跟很多朋友討論過雲遊戲這個話題,不約而同第一個想到的都是網絡延遲,當然這個延遲不僅包含控制指令的延遲也指實時遊戲視頻的延遲。

 

後言(啰嗦幾句):

其實這塊依然屬於共享經濟的後續,類似共享單車。

給大家舉個栗子:我有一百台性能強勁的遊戲主機,每台主機價值一萬,當二手貨賣掉可能還會虧點,好可惜。那麼我把他共享出來,假設現在有十萬個用戶想租我這一百台機器,然後每人只收10塊錢月租,不考慮電費等其他成本,請問我什麼時候能回本?

作者:eguid

說明:原CSDN相關博客文章已經全部轉移到博客園

【精選推薦文章】

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

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

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