分類: 3C資訊

  • Golang簡單入門教程——函數進階篇

    Golang簡單入門教程——函數進階篇

    本文始發於個人公眾號:TechFlow,原創不易,求個關注

    今天是golang專題的第八篇,我們來聊聊golang當中的函數。

    我們在之前的時候已經介紹過了函數的基本用法,知道了怎麼樣設計或者是定義一個函數,以及怎麼樣調用一個函數,還了解了defer的用法。今天這篇文章我們來繼續深入這個話題,來看看golang當中關於函數的一些進階的用法。

    返回error

    前文當中我們曾經提到過,在golang當中並沒有try catch捕獲異常的機制。在其他語言當中異常只有一種,可以通過try catch語句進行捕獲,而golang當中做了區分,將異常分為兩種,一種是可以在函數當中返回的error,另外一種是嚴重的會引起程序崩潰的panic

    在golang中,error也是一個數據類型,由於golang支持函數的多值返回,所以我們可以設置一個返回值是error。我們通過對這個error的判斷來獲取運行函數的情況。

    舉個例子,比如說,假設我們實現一個Divide函數實現兩個int相除。那麼顯然我們需要除數不能為0,當除數為0的時候我們需要返回一個異常。這個時候我們可以把代碼寫成這樣:

    // Divide test
    func Divide(a, b int) (ret int, err error) {
     if b == 0 {
      err = errors.New("divisor is zero")
      return
     }
     return a / b, nil
    }
    

    當我們調用函數的時候,我們用兩個變量去接收這個函數返回的結果,第二個變量的類型是error。當這個函數成功執行的時候第二個變量的結果為nil,我們只需要判斷它是否等於nil,就可以知道函數執行是否成功。如果不成功,我們還可以記錄失敗的原因。

    func main() {
     ret, err := Divide(5, 2)
     if err == nil {
      fmt.Println(ret)
     } else {
      fmt.Println(err)
     }
    }
    

    這種用法在golang當中非常常見,我們之前在介紹字符串相關操作的時候也介紹過返回error的用法。我們在設計函數的時候如果需要判斷輸入的合法性可以使用error,這樣就可以保證handle住非法的情況,並且也能讓下游感知到。

    不定參數

    不定參數的用法在很多語言當中都有,比如在Python當中,不定參數是*args。通過*args我們可以接受任何數量的參數,由於Python是弱變量類型的語言,所以args這些參數的類型可以互不相同。但是golang不行,golang嚴格限制類型,不定參數必須要保證類型一樣。除此之外,其他的用法和Python一樣,不定參數會以數組的形式傳入函數內部,我們可以使用數組的api進行訪問。

    我們來看一個例子,我們通過…來定義不定參數。比如我們可以實現一個sum函數,可以將任意個int進行累加。

    func Sum(nums ... int) int{
        ret := 0
        for _, num := range nums {
            ret += num
        }
        return ret
    }
    

    我們來仔細研究一下上面這個例子,在這個例子當中,我們通過…傳入了一個不定參數,我們不定參數的類型只寫一次,寫在…的後面。從底層實現的機制上來說,不定參數本質上是將傳入的參數轉化成數組的切片。但是這就有了一個問題,既然傳入的是一個數組的切片,我們為什麼要專門設置一個關鍵字,而不是規定傳入一個切片呢?

    比如上面的代碼我們完全可以寫成這樣:

    func Sum(nums []int) int{
        ret := 0
        for _, num := range nums {
            ret += num
        }
        return ret
    }
    

    無論從代碼的閱讀還是編寫上來看相差並不大,好像這樣做完全沒有意義,其實不是這樣的。這個關鍵字簡化的並不是函數的設計方,而是函數的使用方。如果我們規定了函數的輸入是一個切片,那麼當我們在傳入數據的時候,必須要使用強制轉化,將我們的數據轉化成切片,比如這樣:

    Sum([]int(3, 4, 6, 8))
    

    而使用…關鍵字我們則可以省略掉強制轉化的過程,上面的代碼我們寫成這樣就可以了:

    Sum(3, 4, 6, 8)
    

    很明顯可以看出差異,使用不定參數的話調用方會輕鬆很多,不需要再進行額外的轉換。如果我們要傳入的也是一個數組,那麼在傳遞的時候也需要用…符號將它展開

    a := make([]int)
    a = append(a, 3)
    a = append(a, 4)
    Sum(a...)
    Sum(a[1:]...)
    

    既然聊到不定參數的傳遞,那麼又涉及到了一個問題,當我們想要像Python那樣傳遞多個類型不同的參數的時候,應該怎麼辦呢?按照道理golang是靜態類型的語言,限制死了參數的類型,是不能隨便轉換的才對。但是偏偏這樣操作是可以的,因為golang當中有一個特殊的類型,叫做interface

    interface的用法很多,一個很重要的用法是用在面向對象當中充當結構體的接口。這裏我們不做過多深入,我們只需要知道,interface的一個用法是可以用來代替所有類型的變量。我們來看一個例子:

    func testInterface(args ...interface{}) {
        for _, arg := range args {
            switch arg.(type) {
                case int:
                 fmt.Println("it's a int")
             case string:
                 fmt.Println("it's a string")    
                case float32:
                 fmt.Println("it's a float")
                default:
                 fmt.Println("it's an unknown type")
            }
        }
    }
    
    
    func main() {
        testInterface(3, 4.5, "abc")
    }
    

    我們可以用.(type)獲取一個interface變量實際的類型,這樣我們就實現了任意類型任意數量參數的傳入。

    匿名函數和閉包

    匿名函數我們在Python當中經常使用到,其實這個概念出現已久,最早可以追溯到1958年Lisp語言。所以這並不是一個新鮮的概念,只是傳統的C、C++等語言沒有支持匿名函數的功能,所以顯得好像是一個新出現的概念一樣。golang當中也支持匿名函數,但是golang當中匿名函數的使用方式和Python等語言稍稍有些不同。

    在Python當中我們是通過lambda關鍵字來定義匿名函數,它可以被傳入另一個函數當中,也可以賦值給一個變量。golang當中匿名函數的定義方式和普通函數基本是一樣的,只是沒有函數名而已,不過它也可以被傳入函數或者是賦值給另一個變量。

    比如:

    s := func(a, b int) int {
        return a + b
    }
    
    c := s(3, 4)
    

    除了匿名函數之外,golang還支持閉包。閉包的概念我們在之前Python閉包的介紹當中曾經提到過,我們之前也用過好幾次,閉包的本質不是一個包,而是一個函數,是一個持有外部環境變量的函數。比如在Python當中,我們經常可以看到這樣的寫法:

    def outside(x):
        def inside(y):
            print(x, y)
        return inside
    
    
    ins = outside(3)
    ins(5) #3, 5
    

    我們可以看到outside這個函數返回了inside這個函數,對於inside這個函數而言,它持有了x這個變量。x這個變量並不是屬於它的,而是定義在它的外部域的。並且我們在調用inside的時候是無法干涉這個變量的,這就是一個閉包的典型例子。根據輪子哥的說法,閉包的閉的意思並不是封閉內部,而是封閉外部。當外部scope失效的時候,函數仍然持有一份外部的環境的值。

    golang當中閉包的使用方法大同小異,我們來看一個類似的例子:

    func main() {
        a := func(x int) (func(int)) {
            return func(y int){
                fmt.Println(x, y)
            }
        }
        b := a(4)
        b(5)
    }
    

    這個閉包的例子和剛才上面Python那個例子是一樣的,唯一不同的是由於golang是強類型的語言,所以我們需要在定義閉包的時候將輸入和輸出的類型定義清楚。

    總結

    關於golang當中函數的高級用法就差不多介紹完了,這些都是實際編程當中經常使用的方法,如果想要學好golang這門語言的話,這些是基本功。如果你之前有其他語言的基礎,來寫go的話,整體上手的難度還是不大的,很多設計都可以在其他的語言當中找到影子,有了參照來學會簡單得多。

    我很難描述實際工作當中寫golang的體驗,和我寫任何一門其他的語言都不一樣,有一種一開始期望很低,慢慢慢慢總能發現驚喜的感覺。我強烈建議大家去實際感受一下。

    如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。

    本文使用 mdnice 排版

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

    【其他文章推薦】

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

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

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

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

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

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

  • 自己動手實現深度學習框架-8 RNN文本分類和文本生成模型

    自己動手實現深度學習框架-8 RNN文本分類和文本生成模型

    代碼倉庫: https://github.com/brandonlyg/cute-dl

    目標

            上階段cute-dl已經可以構建基礎的RNN模型。但對文本相模型的支持不夠友好, 這個階段的目標是, 讓框架能夠友好地支持文本分類和本文生成任務。具體包括:

    1. 添加嵌入層, 為文本尋找高效的向量表示。
    2. 添加類別抽樣函數, 根據模型輸出的類別分佈抽樣得到生成的文本。
    3. 使用imdb-review數據集驗證文本分類模型。
    4. 使用一個古詩數據集驗證文本生成模型。

            這階段涉及到的代碼比較簡單因此接下來會重點描述RNN語言相關模型中涉及到的數學原理和工程方法。

    數學原理

    文本分類模型

            可以把文本看成是一個詞的序列\(W=[w_1, w_2, …, w_T]\), 在訓練數據集中每個文本屬於一個類別\(a_i\), \(a_i∈A\), 集合 \(A = \{ a_1, a_2, …, a_k \}\) 是一個類別別集合. 分類模型要做的是給定一個文本W, 計算所有類別的后驗概率:

    \[P(a_i|W) = P(a_i|w_1,w_2,…,w_T), \quad i=1,2,…k \]

            那麼文本序列W的類別為:

    \[a = arg \max_{a_i} P(a_i|w_1,w_2,…,w_T) \]

            即在給定文本的條件下, 具有最大后驗概率的類別就是文本序列W所屬的類別.

    文本預測模型

            設任意一個文本序列為\(W=[w_1,w_2,…,W_T]\), 任意一個詞\(w_i ∈ V\), V是所有詞彙的集合,也叫詞彙表, 這裏需要強調的是\(w_i\)在V中是無序的, 但在W中是有序的, 文本預測的任務是, 計算任意一個詞\(w_i ∈ V\)在給定一個序列中的任意一個位置出現的概率:

    \[P(w_1,…,W_T) = ∏_{t=1}^T P(w_t|w_1,…,w_{t-1}) \]

            文本預測輸出一個\(w_i ∈ V\)的分佈列, 根據這個分佈列從V中抽取一個詞即為預測結果。不同於分類任務,這裏不是取概率最大的詞, 這裏的預測結果是某個詞出現的在一個序列特定位置的個概率,只要概率不是0都有可能出現,所以要用抽樣的方法確定某次預測的結果。

    詞的数字化表示

            任意一條數據在送入模型之前都要表示為一個数字化的向量, 文本數據也不例外。一個文本可以看成詞的序列,因此只要把詞数字化了,文本自然也就数字化了。對於詞來說,最簡單的方式是用詞在詞彙表中的唯一ID來表示, ID需要遵守兩個最基本的規則:

    1. 每個詞的ID在詞彙表中必須是唯一的.
    2. 每個詞的ID一旦確定不能變化.

            這種表示很難表達詞之間的關係, 例如: 在詞彙表中把”好”的ID指定為100, 如果希望ID能夠反映詞意的關係, 需要把”好”的近意詞: “善”, “美”, “良”, “可以”編碼為98, 99, 101, 102. 目前為止這看起還行. 如果還希望ID能夠反映詞之間的語法關係, “好”前後經常出現的詞: “友”, “人”, “的”, 這幾個詞的ID就很難選擇, 不論怎樣, 都會發現兩個詞它們在語義和語法上的關係都很遠,但ID卻很接近。這也說明了標量的表達能力很有限,無法表達多個維度的關係。為了能夠表達詞之間多個維度的的關係,多維向量是一個很好的選擇. 向量之間的夾大小衡量它們之間的關係:

    \[cos(θ) = \frac{<A, B>}{|A||B|} \]

            對於兩個向量A, B使用它們的點積, 模的乘積就能得到夾角θ餘弦值。當cos(θ)->1表示兩個向量的相似度高, cos(θ)->0 表示兩個向量是不相關的, cos(θ)->-1 表示兩個向量是相反的。

            把詞的ID轉換成向量,最簡單的辦法是使用one-hot編碼, 這樣得到的向量有兩個問題:

    1. 任意兩個向量A,B, <A,B>=0, 夾角的餘弦值cos(θ)=0, 不能表達詞之間的關係.
    2. 向量的維度等於詞彙表的大小, 而且是稀疏向量,這和導致模型有大量的參數,模型訓練過程的運算量也很大.

            詞嵌入技術就是為解決詞表示的問題而提出的。詞嵌入把詞ID映射到一個合適維度的向量空間中, 在這個向量空間中為每個ID分配一個唯一的向量, 把這些向量當成參數看待, 在特定任務的模型中學習這些參數。當模型訓練完成后, 這些向量就是詞在這個特定任務中的一個合適的表示。詞嵌入向量的訓練步驟有:

    1. 收集訓練數據集中的詞彙, 構建詞彙表。
    2. 為詞彙表中的每個詞分配一個唯一的ID。假設詞彙表中的詞彙量是N, 詞ID的取值為:0,1,2,…,N-1, 對人任意一個0<ID<N-1, 必然存在ID-1, ID+1.
    3. 隨機初始化N個D維嵌入向量, 向量的索引為0,1,2,…,N-1. 這樣詞ID就成了向量的索引.
    4. 定義一個模型, 把嵌入向量作為模型的輸入層參与訓練.
    5. 訓練模型.

    嵌入層實現

            代碼: cutedl/rnn_layers.py, Embedding類.

            初始化嵌入向量, 嵌入向量使用(-1, 1)區間均勻分佈的隨機變量初始化:

    '''
    dims 嵌入向量維數
    vocabulary_size 詞彙表大小
    need_train 是否需要訓練嵌入向量
    '''
    def __init__(self, dims, vocabulary_size, need_train=True):
        #初始化嵌入向量
        initializer = self.weight_initializers['uniform']
        self.__vecs = initializer((vocabulary_size, dims))
    
        super().__init__()
    
        self.__params = None
        if need_train:
            self.__params = []
            self.__cur_params = None
            self.__in_batch = None
    

            初始化層參數時把所有的嵌入向量變成參与訓練的參數:

    def init_params(self):
        if self.__params is None:
            return
    
        voc_size, _ = self.__vecs.shape
        for i in range(voc_size):
            pname = 'weight_%d'%i
            p = LayerParam(self.name, pname, self.__vecs[i])
            self.__params.append(p)
    

            向前傳播時, 把形狀為(m, t)的數據轉換成(m, t, n)形狀的數據, 其中t是序列長度, n是嵌入向量的維數.

    '''
    in_batch shape=(m, T)
    return shape (m, T, dims)
    '''
    def forward(self, in_batch, training):
        m,T = in_batch.shape
        outshape = (m, T, self.outshape[-1])
        out = np.zeros(outshape)
    
        #得到每個序列的嵌入向量表示
        for i in range(m):
            out[i] = self.__vecs[in_batch[i]]
    
        if training and self.__params is not None:
            self.__in_batch = in_batch
    
        return out
    

            反向傳播時只關注當前批次使用到的向量, 注意同一個向量可能被多次使用, 需要累加同一個嵌入向量的梯度.

    def backward(self, gradient):
        if self.__params is None:
            return
    
        #pdb.set_trace()
        in_batch = self.__in_batch
        params = {}
        m, T, _ = gradient.shape
        for i in range(m):
            for t in range(T):
                grad = gradient[i, t]
                idx = self.__in_batch[i, t]
    
                #更新當前訓練批次的梯度
                if idx not in params:
                    #當前批次第一次發現該嵌入向量
                    params[idx] = self.__params[idx]
                    params[idx].gradient = grad
                else:
                    #累加當前批次梯度
                    params[idx].gradient += grad
    
        self.__cur_params = list(params.values())
    

    驗證

    imdb-review數據集上的分類模型

            代碼: examples/rnn/text_classify.py.

            數據集下載地址: https://pan.baidu.com/s/13spS_Eac_j0uRvCVi7jaMw 密碼: ou26

    數據集處理

            數據集處理時有幾個需要注意的地方:

    1. imdb-review數據集由長度不同的文本構成, 送入模型的數據形狀為(m, t, n), 至少要求一個批次中的數據具有相同的序列長度, 因此在對數據進行分批時, 對數據按批次填充.
    2. 一般使用0為填充編碼. 在構建詞彙表時, 假設有v個詞彙, 詞彙的編碼為1,2,…,v.
    3. 由於對文本進行分詞, 編碼比較耗時。可以把編碼后的數據保存起來,作為數據集的預處理數據, 下次直接加載使用。

    模型

    def fit_gru():
        print("fit gru")
        model = Model([
                    rnn.Embedding(64, vocab_size+1),
                    wrapper.Bidirectional(rnn.GRU(64), rnn.GRU(64)),
                    nn.Filter(),
                    nn.Dense(64),
                    nn.Dropout(0.5),
                    nn.Dense(1, activation='linear')
                ])
        model.assemble()
        fit('gru', model)
    

            訓練報告:

    這個模型和tensorflow給出的模型略有差別, 少了一個RNN層wrapper.Bidirectional(rnn.GRU(32), rnn.GRU(32)), 這個模型經過16輪的訓練達到了tensorflow模型的水平.

    文本生成模型

            我自己收集了一個古由詩詞構成的小型數據集, 用來驗證文本生成模型. 代碼: examples/rnn/text_gen.py.

            數據集下載地址: https://pan.baidu.com/s/14oY_wol0d9hE_9QK45IkzQ 密碼: 5f3c

            模型定義:

    def fit_gru():
        vocab_size = vocab.size()
        print("vocab size: ", vocab_size)
        model = Model([
                    rnn.Embedding(256, vocab_size),
                    rnn.GRU(1024, stateful=True),
                    nn.Dense(1024),
                    nn.Dropout(0.5),
                    nn.Dense(vocab_size, activation='linear')
                ])
    
        model.assemble()
        fit("gru", model)
    

            訓練報告:

            生成七言詩:

    def gen_text():
        mpath = model_path+"gru"
    
        model = Model.load(mpath)
        print("loadding model finished")
        outshape = (4, 7)
    
        print("vocab size: ", vocab.size())
    
        def do_gen(txt):
            #編碼
            #pdb.set_trace()
            res = vocab.encode(sentence=txt)
    
            m, n = outshape
    
            for i in range(m*n - 1):
                in_batch = np.array(res).reshape((1, -1))
                preds = model.predict(in_batch)
                #取最後一維的預測結果
                preds = preds[:, -1]
                outs = dlmath.categories_sample(preds, 1)
                res.append(outs[0,0])
    
            #pdb.set_trace()
            txt = ""
            for i in range(m):
                txt = txt + ''.join(vocab.decode(res[i*n:(i+1)*n])) + "\n"
    
            return txt
    
    
        starts = ['雲', '故', '畫', '花']
        for txt in starts:
            model.reset()
            res = do_gen(txt)
            print(res)
    

            生成的文本:

    雲填纜首月悠覺
    纜濯醉二隱隱白
    湖杖雨遮雙雨鄉
    焉秣都滄楓寓功
    
    故民民時都人把
    陳雨積存手菜破
    好纜簾二龍藕卻
    趣晚城矣中村桐
    
    畫和春覺上蓋騎
    滿楚事勝便京兵
    肯霆唇恨朔上楊
    志月隨肯八焜著
    
    花夜維他客陳月
    客到夜狗和悲布
    關欲摻似瓦闊靈
    山商過牆灘幽惘
    

            是不是很像李商隱的風格?

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

    【其他文章推薦】

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

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

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

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

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

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

  • RocketMQ系列(六)批量發送與過濾

    RocketMQ系列(六)批量發送與過濾

    今天我們再來看看RocketMQ的另外兩個小功能,消息的批量發送和過濾。這兩個小功能提升了我們使用RocketMQ的效率。

    批量發送

    以前我們發送消息的時候,都是一個一個的發送,這樣效率比較低下。能不能一次發送多個消息呢?當然是可以的,RocketMQ為我們提供了這樣的功能。但是它也有一些使用的條件:

    • 同一批發送的消息的Topic必須相同;
    • 同一批消息的waitStoreMsgOK 必須相同;
    • 批量發送的消息不支持延遲,就是上一節說的延遲消息;
    • 同一批次的消息,大小不能超過1MiB;

    好了,只要我們滿足上面的這些限制,就可以使用批量發送了,我們來看看發送端的代碼吧,

    @Test
    public void producerBatch() throws Exception {
    
        List<Message> messages = new ArrayList<>();
        for (int i = 0;i<3;i++) {
            MessageExt message = new MessageExt();
            message.setTopic("cluster-topic");
            message.setKeys("key-"+i);
            message.setBody(("this is batchMQ,my NO is "+i+"---"+new Date()).getBytes());
            messages.add(message);
        }
        SendResult sendResult = defaultMQProducer.send(messages);
        System.out.println("sendResult:" + sendResult.getSendStatus().toString());
    }
    
    • 其實批量發送很簡單,我們只是把消息放到一個List當中,然後統一的調用send方法發送就可以了。

    再來看看消費端的代碼,

    @Bean(initMethod = "start",destroyMethod = "shutdown")
    public DefaultMQPushConsumer pushConsumer()  {
        try {
            DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("DefaultMQPushConsumer");
            consumer.setNamesrvAddr("192.168.73.130:9876;192.168.73.131:9876;192.168.73.132:9876;");
            consumer.subscribe("cluster-topic", "*");
            consumer.registerMessageListener(new MessageListenerConcurrently() {
                @Override
                public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                    System.out.println("msgs.size():"+msgs.size());
                    if (msgs != null && msgs.size() > 0) {
                        for (MessageExt msg : msgs) {
                            System.out.println(new String(msg.getBody()));
                        }
                    }
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
            });
            return consumer;
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    • 消費端的代碼沒有任何的變化,正常的接收消息就可以了,我們只是打印出了msgs.size(),看看一次接收一個消息,還是一次可以批量的接收多個消息。

    我們啟動項目,批量發送一下,看看效果吧,

    發送端的日誌如下:

    sendResult:SEND_OK
    

    發送成功,看來我們批量發送的3個消息都進入到了隊列中,再看看消費端,是一次消費一個,還是一次消費3個,如下:

    msgs.size():1
    this is batchMQ,my NO is 0---Mon Jun 15 09:31:04 CST 2020
    msgs.size():1
    this is batchMQ,my NO is 1---Mon Jun 15 09:31:04 CST 2020
    msgs.size():1
    this is batchMQ,my NO is 2---Mon Jun 15 09:31:04 CST 2020
    

    看樣子是一次只消費了一個消息,那麼能不能一次消費3個消息呢?當然是可以的,不過要進行特殊的設置,

    consumer.setConsumeMessageBatchMaxSize(5);
    

    在消費端,我們設置批量消費消息的數量是5,這個值默認是1。我們再看看消費端的日誌,

    msgs.size():3
    this is batchMQ,my NO is 0---Mon Jun 15 09:35:47 CST 2020
    this is batchMQ,my NO is 1---Mon Jun 15 09:35:47 CST 2020
    this is batchMQ,my NO is 2---Mon Jun 15 09:35:47 CST 2020
    

    這次一次消費了3個消息,如果消息比較多的話,最大一次能消費5個。這就是RocketMQ的批量發送和批量消費。

    消息過濾

    其實我們在大多數情況下,使用tag標籤就能夠很好的實現消息過濾。雖然tag標籤咱們並沒有過多的介紹,其實也很好理解,就是一個子Topic的概念,咱們在構建消息message的時候,message.setTags("xxx")。然後在消費的時候,訂閱Topic的時候,也可以指定訂閱的tag,

    consumer.subscribe("cluster-topic", "*");
    

    看到那個”*”了嗎?它就是訂閱的tag,”*”代表全部的tag,如果您想訂閱其中的一個或幾個,可以使用這種方式”tagA || tagB || tagC”,這是訂閱了cluster-topic下的3個tag,其他的tag是不會被消費的。

    這裏我們所說的消息過濾比tag要高級很多,是可以支持sql的,怎麼樣?高級吧。比如:我們訂閱”a > 5 and b = ‘abc’”的消息,如下圖:

    但是,RocketMQ畢竟不是數據庫,它只能支持一些基礎的SQL語句,並不是所有的SQL都支持,

    • 数字型的支持,>, >=, <, <=, BETWEEN, =

    • 字符串支持,=, <>, IN

    • IS NULL或者IS NOT NULL

    • 邏輯判斷,ANDORNOT

    字段的類型也只是簡單的幾種,

    • 数字型,支持123,543.123,整型、浮點都可以;
    • 字符串,必須使用單引號”括起來;
    • 空值,NULL;
    • 布爾型,TRUE或者FALSE;

    並且對消費者的類型也有一定的限制,只能使用push consumer才可以進行消息過濾。好了,說了這麼多了,我們看看怎麼使用吧,消費端和生產端都要進行相應的改造,先看看生產端吧,

    @Test
    public void producerBatch() throws Exception {
    
        List<Message> messages = new ArrayList<>();
        for (int i = 0;i<3;i++) {
            MessageExt message = new MessageExt();
            message.setTopic("cluster-topic");
            message.setKeys("key-"+i);
            message.setBody(("this is batchMQ,my NO is "+i+"---"+new Date()).getBytes());
    
            int a = i+4;
            message.putUserProperty("a",String.valueOf(a));
    
            messages.add(message);
        }
        SendResult sendResult = defaultMQProducer.send(messages);
        System.out.println("sendResult:" + sendResult.getSendStatus().toString());
    }
    

    我們在之前批量發送的基礎上進行了修改,定義了a的值,等於i+4,這樣循環3次,a的值就是4,5,6。然後調用message.putUserProperty("a",String.valueOf(a))注意,在使用消息過濾的時候,這些附加的條件屬性都是通過putUserProperty方法進行設置。這裏,我們設置了a的值。再看看消費端,

    consumer.subscribe("cluster-topic", MessageSelector.bySql("a > 5"));
    

    消費端,整體上沒有變化,只是在訂閱的方法中,使用MessageSelector.bySql("a > 5"),進行了條件的過濾。有的小夥伴可能會有疑問,我既想用sql過濾又想用tag過濾怎麼辦?當然也是可以,我們可以使用MessageSelector.bySql("a > 5").byTag("xx),byTag和bySql不分前後,怎麼樣,很強大吧。我們運行一下程序,看看效果吧。

    我們啟動一下服務,報錯了,怎麼回事?錯誤信息如下:

    The broker does not support consumer to filter message by SQL92
    

    隊列不支持過濾消息,我們查詢了RocketMQ源碼中的BrokerConfig類,這個類就是對broker的一些設置,其中發現了這兩個屬性,

    // whether do filter when retry.
    private boolean filterSupportRetry = false;
    private boolean enablePropertyFilter = false;
    
    • filterSupportRetry是在重試的時候,是否支持filter;
    • enablePropertyFilter,這個就是是否支持過濾消息的屬性;

    我們把這兩個屬性在broker的配置文件改為true吧,如下:

    filterSupportRetry=true
    enablePropertyFilter=true
    

    然後,再重新部署一下我們兩主兩從的集群環境。環境部署完以後,我們再重啟應用,沒有報錯。在生產端發送一下消息看看吧,

    sendResult:SEND_OK
    

    生產端發送消息沒有問題,說明3個消息都發送成功了。再看看消費端的日誌,

    msgs.size():1
    this is batchMQ,my NO is 2---Mon Jun 15 10:59:37 CST 2020
    

    只消費了一個消息,並且這個消息中i的值是2,那麼a的值就是2+4=6,它是>5的,滿足SQL的條件,所以被消費掉了。這完全符合我們的預期。

    總結

    今天的兩個小功能還是比較有意思的,但裡邊也有需要注意的地方,

    • 消息的批量發送,只要我們滿足它的條件,然後使用List發送就可以了;批量消費,默認的消費個數是1,我們可以調整它的值,這樣就可以一次消費多個消息了;
    • 過濾消息中,最大的坑就是隊列的配置里,需要設置enablePropertyFilter=true,否則消費端在啟動的時候報不支持SQL的錯誤;

    我們在使用的時候,多加留意就可以了,有問題,評論區留言吧~

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

    【其他文章推薦】

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

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

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

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

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

  • 分析ThreadLocal的弱引用與內存泄漏問題-Java8,利用線性探測法解決hash衝突

    分析ThreadLocal的弱引用與內存泄漏問題-Java8,利用線性探測法解決hash衝突

    目錄

    一.介紹

    二.問題提出

      2.1內存原理圖

      2.2幾個問題

    三.回答問題

      3.1為什麼會出現內存泄漏

      3.2若Entry使用弱引用

      3.3弱引用配合自動回收

    四.總結  

     

     

     

    一.介紹

      之前使用ThreadLocal的時候,就聽過ThreadLocal怎麼怎麼的可能會出現內存泄漏,具體原因也沒去深究,就是一種不清不楚的狀態。最近在看JDK的源碼,其中就包含ThreadLocal,在對ThreadLocal的使用場景介紹以及源碼的分析后,對於ThreadLocal中可能存在的內存泄漏問題也搞清楚了,所以這裏專門寫一篇博客分析一下。

      在分析內存泄漏之前,先了解2個概念,就是內存泄漏和內存溢出:

      內存溢出(memory overflow):是指不能申請到足夠的內存進行使用,就會發生內存溢出,比如出現的OOM(Out Of Memory)

      內存泄漏(memory lack):內存泄露是指在程序中已經動態分配的堆內存由於某種原因未釋放或者無法釋放(已經沒有用處了,但是沒有釋放),造成系統內存的浪費,這種現象叫“內存泄露”。

      當內存泄露到達一定規模后,造成系統能申請的內存較少,甚至無法申請內存,最終導致內存溢出,所以內存泄露是導致內存溢出的一個原因。

     

    二.問題提出

    2.1內存原理圖

      下圖是程序運行中的內存分布圖,簡要介紹一下這種圖:當前線程有一個threadLocals屬性(ThreadLocalMap屬性),該map的底層是數組,每個數組元素時Entry類型,Entry類型的key是ThreadLocal類型(也就是創建的ThreadLocal對象),而value是則是ThreadLocal.set()方法設置的value。

      

      需要注意的是ThreadLocalMap的Entry,繼承自弱引用,定義如下,關於Java的引用介紹,可以參考:Java-強引用、軟引用、弱引用、虛引用

    /**
     * ThreadLocalMap中存放的元素類型,繼承了弱引用類
     */
    static class Entry extends WeakReference<ThreadLocal<?>> {
        // key對應的value,注意key是ThreadLocal類型
        Object value;
    
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }
    

     

    2.2問題提出

      在看了上面ThreadLocal和ThreadLocalMap相關的內存分佈以及關聯后,提出這樣幾個問題:

      1.ThreadLocal為什麼會出現內存溢出?

      2.Entry的key為什麼要用弱引用?

      3.使用弱引用是否就能解決內存溢出?

      為了回答上面這3個問題,我寫了一段代碼,後面根據這段代碼進行分析:

    public void step1() {
        // some action
        
        step2();
        step3();
        
        // other action
    }
    
    // 在stepX中都會創建threadLocal對象
    public void step2() {
        ThreadLocal<String> tl = new ThreadLocal<>();
        tl.set("this is value");
    }
    public void step3() {
        ThreadLocal<Integer> tl = new ThreadLocal<>();
        tl.set(99);
    }
    

      在step1中會調用step2和step3,step2和step3都會創建ThreadLocal對象,當step2和step3執行完畢后,其中的棧內存中ThreadLocal引用就會被清除。

     

    三.回答問題

     

      

      現在針對這個圖,一步一步的分析問題,中途會得出一些臨時的結論,但是最終的結論才是正確的

     

    3.1為什麼會出現內存泄露

      現在有2點假設,本小節的分析都是基於這兩個假設之上的:

      1.Entry的key使用強引用,key對ThreadLocal對象使用強引用,也就是上面圖中連線5是強引用(key強引用ThreadLocal對象);

      2.ThreadLocalMap中不會對過期的Entry進行清理。

      上面代碼中,如果ThreadLocalMap的key使用強引用,那麼即使棧內存的ThreadLocal引用被清除,但是堆中的ThreadLocal對象卻並不會被清除,這是因為ThreadLocalMap中Entry的key對ThreadLocal對象是強引用。

      如果當前線程不結束,那麼堆中的ThreadLocal對象將會一直存在,對應的內存就不會被回收,與之關聯的Entry也不會被回收(Entry對應的value也不會被回收),當這種情況出現數量比較多的時候,未釋放的內存就會上升,就可能出現內存泄漏的問題。

      上面的結論是暫時的,有前提假設!!!最終結論還需要看後面分析。

     

    3.2若Entry使用弱引用

      

      仍舊有1個假設,就是ThreadLocalMap中不會對過期的Entry進行清理,陳舊的Entry是指Entry的key為null。

      按照源碼,Entry繼承弱引用,其Key對ThreadLocal是弱引用,也就是上圖中連線5是弱引用,連線6仍為強引用。

      同樣以上面代碼為例,step2和step3創建了ThreadLocal對象,step2和step3執行完后,棧中的ThreadLocal引用被清除了;由於堆內存中ThreadLocalMap的Entry key弱引用ThreadLocal對象,根據垃圾收集器對弱引用對象的處理:

    當垃圾收集器工作時,無論當前內存是否足夠,都會回收掉只被弱引用關聯的對象。

      此時堆中ThreadLocal對象會被gc回收(因為現在沒有對ThreadLocal的強引用,只有一個弱引用ThreadLocal對象),Entry的key為null,但是value不為null,且value也是強引用(連線6),所以Entry仍舊不能回收,只能釋放ThreadLocal的內存,仍舊可能導致內存泄漏

      在沒有自動清理陳舊Entry的前提下,即使Entry使用弱引用,仍可能出現內存泄漏。

     

    3.3弱引用配合自動回收

      通過3.2的分析,其實只要陳舊的Entry能自動被回收,就能解決內存泄漏的問題,其實JDK就是這麼做的。

      如果看過源碼,就知道,ThreadLocalMap底層使用數組來保存元素,使用“線性探測法”來解決hash衝突,關於線性探測法的介紹可以查看:利用線性探測法解決hash衝突

      在每次調用ThreadLocal類的get、set、remove這些方法的時候,內部其實都是對ThreadLocalMap進行操作,對應ThreadLocalMap的get、set、remove操作。

      重點來了!重點來了!重點來了!

      ThreadLocalMap的每次get、set、remove,都會清理過期的Entry,下面以get操作解釋,其他操作也是一個意思,大致如下:

      1.ThreadLocalMap底層用數組保存元素,當get一個Entry時,根據key的hash值(非hashCode)計算出該Entry應該出在什麼位置;

      2.計算出的位置可能會有衝突,比如預期位置是position=5,但是position=5的位置已經有其他Entry了;

      3.出現衝突后,會使用線性探測法,找position=6位置上的Entry是否匹配(匹配是指hash相同),如果匹配,則返回position=6的Entry。

      4.在這個過程中,如果position=5位置上的Entry已經是陳舊的Entry(Entry的key為null),此時position=5的key就應該被清理;

      5.光清理position=5的Entry還不夠,為了保證線性探測法的規則,需要判斷數組中的其他元素是否需要調整位置(如果需要,則調整位置),在這個過程中,也會進行清理陳舊Entry的操作。

      上面這5個步驟就保證了每次get都會清理數組中(map)的陳舊Entry,清理一個陳舊的Entry,就是下面這三行代碼:

    Entry.value = null; // 將Entry的value設為null
    table[index] = null;// 將數組中該Entry的位置設置null
    size--;	// map的size減一
    

      對於ThreadLocal的set、remove也類似這個原理。

      有了自動回收陳舊Entry的操作,需要注意的是,在這個時候,key使用弱引用就是至關重要的一點!!!

      因為key使用弱引用后,當弱引用的ThreadLocal對象被會回收后,該key的引用為null,則該Entry在下一次get、set、remove的時候就才會被清理,從未避免內存泄漏的問題。

      

    四.總結

      在上面的分析中,看到ThreadLocal基本不會出現內存泄漏的問題了,因為ThreadLocalMap中會在get、set、remove的時候清理陳舊的Entry,與Entry的key使用弱引用密不可分。

      當然我們也可以在代碼中手動調用ThreadLocal的remove方法進行清除map中key為該threadLocal對象的Entry,同時清理過期的Entry。

      

     

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

    【其他文章推薦】

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

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

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

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

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

    ※超省錢租車方案

  • 養生吧,程序員!

    由於寫作的原因,我認識了蠻多天南海北的朋友。空下來的時候,我就會主動找他們聊一聊,一呢,從他們那吸取成功的經驗,開拓一下眼界;二呢,讓自己的社交圈擴大一些,要知道,多一個朋友就多一條路;三呢,看看朋友們有沒有自己可以幫得上的忙;四呢,保持年輕的心態,不至於落伍。

    老讀者都知道了,我在三線城市洛陽,雖然幸福感很足,但整體社交的圈子是有限的,只通過互聯網,很難得到一些不便於公開的信息,和朋友們聊一聊,不僅能夠加深感情,還能夠讓自己和一線城市保持同步。

    昨天,我和一個非常優秀的年輕人聊天,他給我說,身體上出了一些狀況。他比我小七八歲,按理說身體素質倍棒才對,但大城市的生活壓力,讓他只能快馬加鞭。這就導致身體一直處於高負荷的運轉狀態,很容易出問題。

    提起程序員,總免不了和一些段子關聯上,比如說“要變強,必變禿”,再比如說:

    零基礎學編程→某編程語言入門→某編程語言進階→技術專家→頸椎病

    以前,我對這些段子總是一笑而過,但回想起朋友說的那些話,總免不了一陣心酸。就讓我來寫一篇“程序員養生指南”吧,希望能給讀者朋友們一些警醒或者說參考吧。

    心學鼻祖王陽明曾提出過一個觀點,叫做“知行合一”,我的理解就是,當你要做一件事情的話,你必須得對它有一定的認知,否則的話,你根本就不會去做這件事。

    舉個例子來說,如果你不知道學習很重要,哪怕你天資聰慧,你也不可能去學習,你會把心思花在其他地方。

    再比如說,如果你認知不到英語對於程序員的重要性,你永遠也擺脫不了對翻譯軟件的依賴症。

    對吧?如果在你的認知里,意識不到健康的重要性,那你對待身體的態度可就會大有不同。

    大二結束后,我要去蘇州參加培訓,臨走之前,同學們給我送行,結果我一下子喝大了。畢竟一起玩了兩年,又要去人生地不熟的地方,傷感在所難免,於是我把自己喝到了醫院。

    喝完酒感覺沒啥事,結果睡覺前嘔吐的厲害,感覺整個人就要死翹翹了。我的一個好兄弟看我情況不妙,背着我就跑,大晚上也沒啥車,幸好醫院就在我們學校旁邊,算是保住了一條小命。

    從那以後,我就特別討厭喝酒,儘管有的時候不得不喝一些,但都會盡量控制到不上頭的狀態。

    我身邊有不少人,總是把鍛煉掛在嘴上,聊起來感覺特別注重身體。但過一段時間再問他,“夥計,你健身卡辦了沒?”“最近忙,過两天就去辦,感覺身體有點撐不住了。”

    生存的壓力確實大,但如果身體跨了,生存的意義又是什麼呢?

    改變一個人的認知,最壞的方式就是徹底摧毀他之前的認知。極端的例子就是大病初愈,那時候,人會迫切地想要鍛煉身體。

    最好的方式,當然是聽得進去勸,把別人糟糕的經歷當做是自己前進的動力。認識到健康的重要性,然後一點一滴地去改善生活的習慣,最終達到知行合一的境界。

    我曾看過一本書,裏面提到一個觀點,養成習慣的最好方式就是,連續不間斷地做一件事,周期為 21 天。這件事最好是一件小事,比如說,起床后疊被子這件事,它一點也不難,很容易就能做到。

    但能不能堅持 21 天不間斷就需要一點點耐力了,21 天不算長,但絕對算得上是富有意義的考驗了,它對你培養飲食、作息、運動方面的良好行為習慣是一道開胃菜。

    接下來說說飲食吧,我覺得一定不要暴飲暴食,或者餓着肚子。每天的三餐一定要及時,哪怕你早上起晚了,一定也要記得吃點東西,可以準備一些麵包或者牛奶,不要餓着肚子挺到中午,那樣的話,對身體不好,另外,餓的時候,工作狀態也會大打折扣。

    現在天氣熱了,很多讀者的食慾都不會特彆強烈,尤其是到了中午的時候,可以選擇一些清淡的,比如說,我作為北方人,最喜歡的就是甜面片,伴着一點鹹菜吃,再喝點麵湯,感覺特別舒服。

    到了晚上,不要因為餓就要找場子,覺得必須得吃回來,然後睡覺的時候就感覺特別撐,很難入睡,反而影響了睡眠質量。

    我一般是十點半入睡,然後一覺睡到早上五六點。這個作息還是非常規律的,中午如果困的話,就再補個覺。最好不要超過半個小時,否則越睡越困,如果實在睡不着,就閉目養神會,就算是休息休息眼睛吧,畢竟做程序員的,每天對着電腦屏幕和手機屏幕,對眼睛的傷害還是蠻大的。

    有不少讀者都睡得特別晚,一方面是公司上下班時間上的問題,一方面就是好不容易有點自己的自由時間,舍不得睡覺,於是熬一會,打一把遊戲,就到了凌晨一兩點。

    我是怎麼知道的?通過留言的時間就知道了。讓我很心疼的一個事實是,有些留言的時間竟然是凌晨三四點。真的,看到這個時間點的留言,我都會勸讀者能早點睡就早點睡,不要熬夜。

    二十五六歲之前,熬個夜,很快就恢復了,但再往後,真的是非常難,我以前熬夜看英超,結果第二天整個人都處於懵逼的狀態,效率特別差,要兩三天才能恢復正常,索性後來就戒了。

    最後再說說鍛煉吧,年前我辦了一張健身卡,一周能堅持去兩到三次,但後來就中斷了。最近兩個月,我開始了騎自行車,感覺效果還不錯,瘦了七八斤的樣子,有一種返老還童的感覺,真的。

    五六點起來,騎一個小時左右,回到家不耽誤上班。我在朋友圈曬過兩張圖,老讀者應該看到了。清晨,空氣特別好,路上人也不多,車也不多,氣溫也剛剛好,耳邊再聽着周杰倫或者王力宏,感覺真的非常愜意。

    作為程序員,絕大部分時間都要坐在椅子上,再加上有些公司加班特別厲害,就導致久坐的時間特別長,於是頸椎病、肩周炎等等職業病隨着而來。

    除了及時地走動,還是要盡量騰出一些時間去鍛煉一下,哪怕走走路,跑幾步,對身體的調整都卓有成效,業績是公司的,身體是自己的。

    最後,就是堅持了。生活需要用心去對待,如果我們用心去愛她,她就會加倍地愛我們——養生吧,程序員!

    如果覺得文章對你有點幫助,請微信搜索「 沉默王二 」第一時間閱讀。

    本文已收錄 GitHub,傳送門~ ,裏面更有大廠面試完整考點,歡迎 Star。

    我是沉默王二,一枚有顏值卻靠才華苟且的程序員。關注即可提升學習效率,別忘了三連啊,點贊、收藏、留言,我不挑,嘻嘻

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

    【其他文章推薦】

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

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

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

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

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

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

  • 【SEED Labs】Public-Key Infrastructure (PKI) Lab

    【SEED Labs】Public-Key Infrastructure (PKI) Lab

    Lab Overview

    公鑰加密是當今安全通信的基礎,但當通信的一方向另一方發送其公鑰時,它會受到中間人的攻擊。根本的問題是,沒有簡單的方法來驗證公鑰的所有權,即,給定公鑰及其聲明的所有者信息,如何確保該公鑰確實屬於聲明的所有者?公鑰基礎設施(PKI)是解決這一問題的一種切實可行的方法。

    通過這個實驗,我們應該能夠更好地了解PKI是如何工作的,PKI是如何用來保護網絡,以及PKI如何打敗中間人攻擊。此外,我們將能夠了解在公鑰基礎設施中信任的根源,以及如果這種根源信任被破壞會出現什麼問題。本實驗所涵蓋的主題如下:

    • Public-key encryption

    • Public-Key Infrastructure (PKI)

    • Certificate Authority (CA) and root CA

    • X.509 certificate and self-signed certificate

    • Apache, HTTP, and HTTPS

    • Man-in-the-middle attacks

    Lab Environment

    這個實驗在我kali VM和Ubuntu 16.04 VM上進行了測試.在這個實驗中,我們將使用openssl命令和庫。

    Lab Tasks

    Task1: Becoming a Certificate Authority(CA) 

    證書頒發機構(CA)是發布数字證書的受信任實體。数字證書通過證書的命名主體來驗證公鑰的所有權。一些商業性的CAs被視為根類CAs;在撰寫本文時,VeriSign是最大的CA。想要獲得商業核證機關發出的数字證書的用戶需要向這些核證機關支付費用。

    在這個實驗室,我們需要創建数字證書,但是我們不會支付任何商業CA,我們自己會成為一個根CA,然後用這個CA為其他人(比如服務器)頒發證書。在這個任務中,我們將使自己成為一個根CA,併為這個CA生成一個證書。RootCA的認證通常預裝在大多數操作系統、web瀏覽器和其他依賴於PKI的軟件中。根CA的證書是無條件信任的。

    The Configuration File openssl.conf  

    為了使用OpenSSL創建證書,必須有一個配置文件。配置文件通常有一個extension.cnf。它由三個OpenSSL命令使用:ca、req和x509。可以使用谷歌搜索找到openssl.conf的手冊頁。還可以從/usr/lib/ssl/openssl.cnf獲得配置文件的副本。將此文件複製到當前目錄后,需要按照配置文件中指定的方式創建子目錄(查看[CA default]部分): 

     

     

     對於index.txt文件,只需創建一個空文件。對於serial文件,在文件中放入一個字符串格式的数字(例如1000)。設置好配置文件openssl.cnf之後,就可以創建和頒發證書了。

    CertificateAuthority(CA).

    如前所述,我們需要為我們的CA生成一個自簽名證書,這意味着這個CA是完全可信的,它的證書將作為根證書。運行以下命令為CA生成自簽名證書:

    系統將提示您輸入信息和密碼。不要丟失此密碼,因為每次要使用此CA為其他人簽名證書時,都必須鍵入口令。您還將被要求填寫一些信息,如國家名稱、常用名稱等。該命令的輸出存儲在兩個文件中:ca.key和ca.crt。文件CA .key包含CA的私鑰,而CA .crt包含公鑰證書。

     

     

     Task2: Creating a Certificate for SEEDPKILab2018.com 

    現在,我們成為一個根CA,我們準備為我們的客戶簽署数字證書。我們的第一個客戶是一家名為SEEDPKILab2018.com的公司。該公司要從CA獲得数字證書,需要經過三個步驟。

    Step 1: Generate public/private key pair  。公司需要首先創建自己的公鑰/私鑰對。可以運行以下命令來生成RSA密鑰對(私有和公共密鑰)。您還需要提供一個密碼來加密私鑰(使用AES-128加密算法,在命令選項中指定)。密鑰將存儲在文件服務器中。

     

    server.key是一個編碼的文本文件(也是加密的),因此無法看到實際內容,例如模數、私有指數等。要查看這些,可以運行以下命令:

     

     

     

     

     Step 2: Generate a Certificate Signing Request (CSR). 一旦公司擁有了密鑰文件,它應該生成一個證書籤名請求(CSR),它基本上包括公司的公鑰。CSR將被發送到CA, CA將為密鑰生成證書(通常在確保CSR中的身份信息與服務器的真實身份匹配之後)。使用SEEDPKILab2018.com作為證書請求的通用名稱。

    需要注意的是,上面的命令與我們為CA創建自簽名證書時使用的命令非常相似,唯一的區別是使用了-x509選項。沒有它,命令生成一個請求;使用它,該命令生成一個自簽名證書。

    Step 3: Generating Certificates . CSR文件需要有CA的簽名才能形成證書。在現實世界中,CSR文件通常被發送到受信任的CA進行簽名。在這個實驗中,我們將使用我們自己的可信CA來生成證書。以下命令使用CA的CA .crt和CA .key將證書籤名請求(server.csr)轉換為X509證書(server.crt):

    如果OpenSSL拒絕生成證書,您請求中的名稱很可能與ca的名稱不匹配。匹配規則在配置文件中指定(查看[policy match]部分)。您可以更改請求的名稱以符合策略,也可以更改策略。配置文件還包括另一個限制較少的策略(稱為任何策略)。您可以通過更改以下行來選擇該策略:

    “policy = policy_match” change to “policy = policy_anything”.

    Task3: Deploying Certificate in an HTTPS Web Server

    在這個實驗中,我們將探索網站如何使用公鑰證書來保護web瀏覽。我們將使用openssl的內置web服務器建立一個HTTPS網站。

    Step1: Configuring DNS .我們選擇SEEDPKILab2018.com作為我們的網站名稱。為了讓我們的計算機識別這個名稱,讓我們將下面的條目添加到/etc/hosts;這個條目基本上將主機名SEEDPKILab2018.com映射到本地主機(即127.0.0.1):

     

    Step 2: Configuring the web server.  讓我們使用在上一個任務中生成的證書啟動一個簡單的web服務器。OpenSSL允許我們使用s_server命令啟動一個簡單的web服務器:

     

    默認情況下,服務器將監聽端口4433。您可以使用-accept選項進行更改。現在,您可以使用以下URL訪問服務器:https://SEEDPKILab2018.com:4433/。最有可能的是,您將從瀏覽器中得到一條錯誤消息。在Firefox中,您將看到如下消息:“seedpkilab2018.com:4433使用了無效的安全證書。該證書不受信任,因為發布者證書未知”.

     

    Step3: Getting the browser to accept our CA certificate. 如果我們的證書是由VeriSign分配的,就不會出現這樣的錯誤消息,因為VeriSign的證書很可能已經預加載到Firefox的證書存儲庫中了。很遺憾,SEEDPKILab2018.com的證書是由我們自己的CA,並且Firefox無法識別此CA。有兩種方法可以讓Firefox接受CA的自簽名證書。

    • 我們可以請求Mozilla將我們的CA證書包含在Firefox軟件中,這樣每個使用Firefox的人都可以識別我們的CA。不幸的是,我們自己的CA沒有足夠大的市場讓Mozilla包含我們的證書,所以我們不會追求這個方向。
    • 加載CA .crt到Firefox中:我們可以手動添加我們的CA證書到Firefox瀏覽器通過點擊下面的菜單序列:

                 Edit -> Preference -> Privacy & Security -> View Certificates

    您將看到一個已經被Firefox接受的證書列表。從這裏,我們可以“導入”我們自己的證書。請導入CA .crt,並選擇以下選項:“信任此CA識別網站”。您將看到我們的CA證書現在位於Firefox接受的證書列表中。

     Step4. Testing our HTTPS website . 現在,將瀏覽器指向https://SEEDPKILab2018.com: 4433,可以正常訪問

    Task4: Deploying Certificate in an Apache-Based HTTPS Website

    使用openssl的s_server命令設置HTTPS服務器主要用於調試和演示目的。在這個實驗中,我們基於Apache建立了一個真正的HTTPS web服務器。Apache服務器(已經安裝在我們的VM中)支持HTTPS協議。要創建一個HTTPS網站,我們只需要配置Apache服務器,這樣它就知道從哪裡獲得私鑰和證書。

    一個Apache服務器可以同時託管多個網站。它需要知道網站文件存儲的目錄。這是通過它的VirtualHost文件完成的,該文件位於/etc/apache2/sites-available目錄中。要添加一個HTTP網站,我們需要在文件000-default.conf中添加一個虛擬主機條目。而要添加一個HTTPS網站,我們則需要在同一個文件夾的default-ssl.conf文件中添加一個VirtualHost條目。

     

     

    ServerName條目指定網站的名稱,而DocumentRoot條目指定網站文件存儲的位置。在設置中,我們需要告訴Apache服務器證書和私鑰存儲在哪裡。

    修改了default-ssl.conf文件之後,我們需要運行一系列命令來啟用SSL。Apache將要求我們輸入用於加密私鑰的密碼。一旦一切都設置好了,我們就可以瀏覽網站了,瀏覽器和服務器之間的所有流量都被加密了。

     

     Task5: Launching a Man-In-The-Middle Attack 

     

     在這個任務中,我們將展示PKI如何擊敗中間人(MITM)攻擊。下圖描述了MITM攻擊的工作原理。假設Alice想通過HTTPS協議訪問example.com。她需要從example.com服務器獲取公鑰;Alice將生成一個密鑰,並使用服務器的公鑰對該密鑰進行加密,然後將其發送到服務器。如果攻擊者可以攔截Alice和服務器之間的通信,則攻擊者可以用自己的公鑰替換服務器的公鑰。因此,Alice的秘密實際上是用攻擊者的公鑰加密的,因此攻擊者將能夠讀取秘密。攻擊者可以使用服務器的公鑰將密鑰轉發給服務器。秘密用於加密Alice和服務器之間的通信,因此攻擊者可以解密加密的通信。

     

     

    Step 1: Setting up the malicious website. 在Task 4中,我們已經為SEEDPKILab2018.com建立了一個HTTPS網站。我們將使用相同的Apache服務器模擬example.com 。為此,我們將按照任務4中的指令向Apache的SSL配置文件添加一個VirtualHost條目:ServerName應該是example.com,但配置的其餘部分可以與任務4中使用的相同。我們的目標如下:當用戶試圖訪問example.com時,我們將讓用戶登陸我們的服務器,其中為example.com託管一個假網站。如果這是一個社交網站,虛假網站可以显示一個登錄頁面類似於目標網站。如果用戶不能分辨出兩者的區別,他們可能會在假網頁中輸入他們的帳戶憑據,本質上就是向攻擊者披露憑據。

    Step2: Becoming the man in the middle 。有幾種方法可以讓用戶的HTTPS請求到達我們的web服務器。一種方法是攻擊路由,將用戶的HTTPS請求路由到我們的web服務器。另一種方法是攻擊DNS,當受害者的機器試圖找到目標網絡服務器的IP地址時,它會得到我們的網絡服務器的IP地址。在此任務中,我們使用“攻擊”DNS。我們只需修改受害者機器的/etc/hosts文件,以模擬DNS緩存設置攻擊的結果,而不是啟動實際的DNS緩存中毒攻擊。

    Step3: Browse the target website  。一切都設置好了,現在訪問目標真實的網站。

    可以看到,我們訪問到的是kali攻擊機的默認目錄。

    訪問https服務的時候,由於kali攻擊機的證書不被信任,所以會有安全警告

     

     

     

    Task6: Launching a Man-In-The-Middle Attack with a Compromised CA 

    設計一個實驗來證明攻擊者可以在任何HTTPS網站上成功發起MITM攻擊。可以使用在Task 5中創建的相同設置,但是這一次,需要演示MITM攻擊是成功的。即,當受害者試圖訪問一個網站而進入MITM攻擊者的假網站時,瀏覽器不會引起任何懷疑。

     

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

    【其他文章推薦】

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

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

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

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

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

  • CPU性能分析工具原理

    轉載請保留以下聲明

      作者: 趙宗晟

      出處: https://www.cnblogs.com/zhao-zongsheng/p/13067733.html

    很多軟件都要做性能分析和性能優化。很多語言都會有他的性能分析工具,例如如果優化C++的性能,我們可以用Visual Studio自帶的性能探測器,或者使用Intel VTune Profiler。了解性能分析工具的原理有助於了解工具給出的數據與結果,也能幫助我們在遇到異常結果時排查哪裡出了問題。這篇博客簡單總結一下常見的性能分析工具原理。

    性能分析器原理分類

    性能分析工具大部分都可以分為下面幾類

    1. 基於採樣(Sampling)
    2. 基於插裝(Instrumentation)
    3. 基於事件(Event-based)

    1. 基於採樣

    基於採樣的分析器會每隔一個固定時間間隔暫停所有線程的執行,然後分析有哪些線程正在執行,那些線程處於就緒狀態。對於這類線程,我們記錄每個線程的調用堆棧,以及其他需要的信息。我們稱這個行為為一次採樣,記錄下來的每個堆棧為一個樣本。然後在結束性能分析的時候我們統計記錄下載的堆棧,看每個堆棧被記錄了多少次,或者每個函數被記錄了多少次。統計學告訴我們,那些執行時間比較長的函數、堆棧,被記錄的次數會更多。如果堆棧A被記錄了200次,堆棧B被記錄了100次,那麼堆棧B的執行時間是堆棧A的2倍。我們可以計算某個堆棧樣本的數量佔總樣本數的比例,這個比例就是堆棧執行時間的佔比。用Visual Studio的性能探測器我們看到的百分比和数字就是值樣本的佔比(也就是時間佔比)和樣本次數。

    很多性能分析工具都是基於採樣的方式。運行性能分析器是會影響被測程序的性能的,而基於採樣的有點是對性能影響比較小,不需要重新編譯程序,非常方便。

    2.基於插裝

    插裝是指通過修改程序,往裡面加入性能分析相關代碼,來收集、監控相關性能指標。例如我們可以在一個函數的開頭寫下計數代碼,我們就可以知道在運行中這個函數被執行了多少次。一般來說基於插裝的性能分析更為準確,但是對性能影響比較大。因為需要修改代碼,所以也不是很方便。另外,基於插裝的分析也可能會引起海森堡bug(heisenbug)。海森堡bug是指當你再運行程序的時候能遇到這個bug,但是試圖定位這個bug時卻遇不到這個bug。這個bug往往是因為在定位bug時修改了軟件的運行環境/流程,導致軟件執行和生產時不一樣,於是就遇不到這個bug了。這個命名的來源很有意思,海森堡是量子力學的著名科學家,他提出了不確定性原理,以及觀察者理論。這個理論認為,觀察會影響例子的狀態,導致觀察粒子和不觀察粒子會導致不同的結果,這個和海森堡bug的情形非常相似。關於觀察者理論,有興趣的人可以再了解一下。

    回到正題,基於插裝也可以再進行劃分:

    • 人手修改源碼:這個是我們非常常用的性能分析方法。我們做性能分析有時候就會直接修改源碼,計算某一段代碼的執行時長,或者計算函數調用次數,分析哪段代碼耗時。
    • 工具自動修改源碼
    • 工具自動修改彙編/中間碼
    • 運行時注入
    • ……

    3.基於事件

    在軟件執行過程中,可能會拋出某些事件。我們通過統計事件出現的次數,事件出現的時機,可以得到軟件的某些性能指標。事件又可以分為軟件事件和硬件事件。軟件事件比如Java可以在class-load的時候拋出事件。硬件事件則是使用專門的性能分析硬件。現在很多CPU裏面都有用於分析性能的性能監控單元(PMU),PMU本身是一個寄存器,在某個事件發生時寄存器裏面的值會+1。例如我們可以設置為當運行中發生memory cache miss的時候PMU寄存器+1,這樣我們就知道一段時間內發生了多少次memory cache miss。性能分析器使用PMU時,會給PMU設置需要統計的事件類型,以及Sample After Value (SAV)。SAV是指寄存器達到什麼值之後出發硬件中斷。例如,我們可以給PMU設置SAV為2000,統計事件為memory cache miss。那麼當cache miss發生2000次時,發生硬件中斷。這個時候性能分析器就可以收集CPU的IP,調用堆棧,進程ID等等信息,分析器結束時進行統計分析。

    基於硬件事件的優點是,對被測程序的影響非常小,比基於採樣還小,可以使用更短的時間間隔收集信息,而且可以收集CPU的非常重要的性能指標,例如cache miss,分支預測錯誤,等等。

    但是基於硬件事件的分析器也有它的一些問題,導致數據上的誤差:

    • SAV一般會設置成很大的數值:
      像是Intel VTune Profiler一般會把SAV設置成10,000到2,000,000,發生中斷時我們能知道最後一次觸發該事件是哪段代碼引起的,但是在這之前的9,999到1,999,999次事件我們是不知道的。他會認為所有10,000到2,000,000次事件都是由同一處代碼引起的。如果發生了很多次中斷,收集了很多次信息,而某一行代碼出現了很多次,那麼根據統計學,我們能知道這行代碼觸發了多少次事件。但是如果某一行代碼只出現了一兩次,那麼我們很難知道這行代碼到底出發了多少次時間。
    • CPU一個核只有幾個PMU,但是可以統計的事件有幾十種:
      一個PMU可以統計一個事件,但是我們分析一個軟件可能需要統計幾十種事件。一般的處理方法是多路復用(Multiplexing)。比如說前10ms記錄事件A,后10ms記錄事件B,再后10ms由記錄事件A,……,這樣輪流記錄事件A和事件B,那麼一個PMU就可以同時統計兩個事件。多路復用可以解決少量PMU統計大量事件的問題,但是也會導致每種事件記錄的樣本數減少,倒是最後統計計算的結果誤差更大。
    • Intel® Hyper-Threading Technology導致記錄不準:
      Hyper-Threading技術可以讓一個CPU物理核變成兩個邏輯核,但是這兩個邏輯核會共享很多硬件,包括PMU。這會出現什麼問題呢?例如我們有兩個線程再兩個CPU核同時運行。我們覺得實在兩個核上執行,但是實際上是在同一個物理核上。所以PMU會同時統計兩個程序觸發的事件,我們很難區分到底是哪個邏輯核出發了多少事件,所以PMU記錄的數據就會不準確。另外,性能分析器計算性能指標時會使用一些硬件參數,Hyper-Threading技術會讓這些參數不準確。例如一般個CPU核能再一個clock執行4個uop,所以CPI(Cycle Per Instruction,每個clock執行的指令數)是0.25。但是如果使用了Hyper-Threading技術,實際的CPI會是0.5
    • Event Skid(事件打滑)會導致記錄的IP不準確:
      PMU記錄有些事件會出現一定延時,所以在執行分析器的中斷處理代碼時,可能被測程序已經又執行了好多指令,IP已經向後滑動了很遠了。一般如果我們只是統計函數的話不會太大問題,但是我們想統計指令時就會有很大問題了。比如我們可能會看到某個add指令導致了大量的分支預測錯誤,顯然這個是不可能的。往往這種時候我們可以看看前面一點的指令。
    • Interrupt Masking(中斷屏蔽),導致統計出來的空閑狀態比正常的高
      不同的中斷有不同的優先級,為了高優先級的中斷處理程序不被打斷,我們可以選擇屏蔽一部分中斷事件。但是PMU的事件也是一个中斷,如果系統中有大量的中斷屏蔽,那麼會有PMU的中斷被屏蔽掉一部分,導致統計出來的數據不準確。表現出來的效果就是,統計出來的處於空閑狀態的時間比實際的要高。

    總結

    這幾個就是比較常見的性能分析方法。我們知道了性能分析的原理,可以更好地理解性能分析器給出的結果,也可以在出現明顯異常的結果時,分析判斷可能的原因,針對性的解決。

    參考

    https://en.wikipedia.org/wiki/Profiling_(computer_programming)
    https://software.intel.com/content/www/us/en/develop/articles/understanding-how-general-exploration-works-in-intel-vtune-amplifier-xe.html
    https://software.intel.com/content/www/us/en/develop/documentation/vtune-help/top/analyze-performance/user-mode-sampling-and-tracing-collection.html
    https://software.intel.com/content/www/us/en/develop/documentation/vtune-help/top/analyze-performance/hardware-event-based-sampling-collection.html

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

    【其他文章推薦】

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

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

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

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

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

  • 循序漸進VUE+Element 前端應用開發(10)— 基於vue-echarts處理各種圖表展示,循序漸進VUE+Element 前端應用開發(5)— 表格列表頁面的查詢,列表展示和字段轉義處理,循序漸進VUE+Element 前端應用開發(9)— 界面語言國際化的處理

    循序漸進VUE+Element 前端應用開發(10)— 基於vue-echarts處理各種圖表展示,循序漸進VUE+Element 前端應用開發(5)— 表格列表頁面的查詢,列表展示和字段轉義處理,循序漸進VUE+Element 前端應用開發(9)— 界面語言國際化的處理

    在我們做應用系統的時候,往往都會涉及圖表的展示,綜合的圖表展示能夠給客戶帶來視覺的享受和數據直觀體驗,同時也是增強客戶認同感的舉措之一。基於圖表的處理,我們一般往往都是利用對應第三方的圖表組件,然後在這個基礎上為它的數據模型提供符合要求的圖表數據即可,VUE+Element 前端應用也不例外,我們這裏使用了基於vue-echarts組件模塊來處理各種圖表vue-echarts是對echarts圖表組件的封裝。

    1、圖表組件的安裝使用

    首先使用npm 安裝vue-echarts組件。

    git地址:https://github.com/ecomfe/vue-echarts

    NPM安裝命令

    npm install echarts vue-echarts

    然後在對應模塊頁面裏面引入對應的組件對象,如下代碼所示。

    <script>
    import ECharts from 'vue-echarts' // 主圖表對象
    import 'echarts/lib/chart/line' // 曲線圖表
    import 'echarts/lib/chart/bar' // 柱狀圖
    import 'echarts/lib/chart/pie' // 餅狀圖
    import 'echarts/lib/component/tooltip' // 提示信息

    接着在Vue組件裏面對象中加入對象即可。

    export default {
      components: {
        'v-chart': ECharts
      },

    如果是全局註冊使用,那麼可以在main.js裏面進行加載

    // 註冊組件后即可使用
    Vue.component('v-chart', VueECharts)

    我們來看看圖表展示的效果圖

    柱狀圖效果

     

    餅狀圖

      

     曲線圖

      

     其他類型,極坐標和散點圖形

      

     或者曲線和柱狀圖組合的圖形

     更多的案例可以參考官網的展示介紹:https://echarts.apache.org/examples/zh/index.html

      

    2、各種圖表的展示處理

    對於我們需要的各種常規的柱狀圖、餅狀圖、折線圖(曲線圖)等,我下來介紹幾個案例代碼,其他的一般我們根據官方案例提供的data數據模型,構造對應的數據即可生成,就不再一一贅述。

    另外,我們也可以參考Vue-echarts封裝的處理demo:https://github.com/ecomfe/vue-echarts/tree/master/src/demo 

    對於柱狀圖,效果如下

    在Vue模塊頁面的Template 裏面,我們定義界面代碼如下即可。

    <v-chart
      ref="simplebar"
      :options="simplebar"
      autoresize
    />

    然後在data裏面為它準備好數據即可,如下代碼所示。

     data() {
        return {
          simplebar: {
            title: { text: '柱形圖Demo' },
            tooltip: {},
            xAxis: {
              data: ['襯衫', '羊毛衫', '雪紡衫', '褲子', '高跟鞋', '襪子']
            },
            yAxis: {},
            series: [{
              name: '銷量',
              type: 'bar',
              data: [5, 20, 36, 10, 10, 20]
            }]
          }
        }
      }

    當然我們也可以把這些構造對應數據的邏輯放在單獨的JS文件裏面,然後導入即可。

    例如對於餅圖,它的界面效果如下所示。

    它的vue視圖下,Template裏面的代碼如下所示。

    <v-chart
      ref="pie"
      :options="pie"
      autoresize />

    一般對於圖表的數據,由於處理代碼可能不少,建議是獨立放在一個JS文件裏面,然後我們通過import導入即可使用。

      然後在data裏面引入對應的對象即可,如下所示。

    <script>
    import ECharts from 'vue-echarts' // 主圖表對象
    import 'echarts/lib/chart/line' // 曲線圖表
    import 'echarts/lib/chart/bar' // 柱狀圖
    import 'echarts/lib/chart/pie' // 餅狀圖
    import 'echarts/lib/component/tooltip' // 提示信息
    
    // 導入報表數據
    import getBar from './chartdata/bar' import pie from './chartdata/pie'
    import scatter from './chartdata/scatter'
    import lineChart from './chartdata/lineChart'
    import incomePay from './chartdata/incomePay'
    
    export default {
      components: {
        'v-chart': ECharts
      },
       return {
          pie,
          scatter,,
          lineChart,
          incomePay,
          simplebar: {
            title: { text: '柱形圖Demo' },
            tooltip: {},
            xAxis: {
              data: ['襯衫', '羊毛衫', '雪紡衫', '褲子', '高跟鞋', '襪子']
            },
            yAxis: {},
            series: [{
              name: '銷量',
              type: 'bar',
              data: [5, 20, 36, 10, 10, 20]
            }]
          }
        }
      },

    其中pie.js裏面放置的是處理餅圖數據的邏輯,如下代碼所示。

    export default {
      title: {
        text: '餅圖程序調用高亮示例',
        x: 'center'
      },
      tooltip: {
        trigger: 'item',
        formatter: '{a} <br/>{b} : {c} ({d}%)'
      },
      legend: {
        orient: 'vertical',
        left: 'left',
        data: ['直接訪問', '郵件營銷', '聯盟廣告', '視頻廣告', '搜索引擎']
      },
      series: [
        {
          name: '訪問來源',
          type: 'pie',
          radius: '55%',
          center: ['50%', '60%'],
          data: [
            { value: 335, name: '直接訪問' },
            { value: 310, name: '郵件營銷' },
            { value: 234, name: '聯盟廣告' },
            { value: 135, name: '視頻廣告' },
            { value: 1548, name: '搜索引擎' }
          ],
          itemStyle: {
            emphasis: {
              shadowBlur: 10,
              shadowOffsetX: 0,
              shadowColor: 'rgba(0, 0, 0, 0.5)'
            }
          }
        }
      ]
    }

    在界面處理的時候,值得注意的時候,有時候Vue頁面處理正常,但是圖表就是沒有出來,可能是因為高度或者寬度為0的原因,需要對對應的樣式進行處理設置,以便能夠正常显示出來。

    如下是我 對圖表的設置的樣式處理,使得圖表在一個卡片的位置能夠显示正常。

    <style scoped>
      .echarts { width: 100%; height: 400px;}
    
      .el-row {
        margin-bottom: 20px;
      }
      .el-col {
        border-radius: 4px;
        margin-bottom: 20px;
      }
    </style>

    最後幾個界面組合一起的效果如下所示。

     以上就是基於vue-echarts處理各種圖表展示,其中常規的引入組件很容易的,主要就是需要根據對應的圖表案例,參考數據組成的規則,從而根據我們實際情況構建對應的數據,賦值給對應的模型變量即可。

    列出以下前面幾篇隨筆的連接,供參考:

    循序漸進VUE+Element 前端應用開發(1)— 開發環境的準備工作

    循序漸進VUE+Element 前端應用開發(2)— Vuex中的API、Store和View的使用

    循序漸進VUE+Element 前端應用開發(3)— 動態菜單和路由的關聯處理

    循序漸進VUE+Element 前端應用開發(4)— 獲取後端數據及產品信息頁面的處理

    循序漸進VUE+Element 前端應用開發(5)— 表格列表頁面的查詢,列表展示和字段轉義處理

    循序漸進VUE+Element 前端應用開發(6)— 常規Element 界面組件的使用

    循序漸進VUE+Element 前端應用開發(7)— 介紹一些常規的JS處理函數

    循序漸進VUE+Element 前端應用開發(8)— 樹列表組件的使用

    循序漸進VUE+Element 前端應用開發(9)— 界面語言國際化的處理

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

    【其他文章推薦】

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

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

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

    ※超省錢租車方案

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

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

  • 因為知道了30+款在線工具,我的工作效率提升500%!

    因為知道了30+款在線工具,我的工作效率提升500%!

    GitHub 15.2k Star 的Java工程師成神之路,不來了解一下嗎!

    GitHub 15.2k Star 的Java工程師成神之路,不來了解一下嗎!

    Perl 之父 Larry Wall 曾經在自己的《Programming Perl》一書中提到過:”程序員有3種美德: 懶惰、急躁和傲慢” 。懶惰,作為程序員美德的第一個要素。

    Larry Wall 所說程序員應該具備的懶惰,並不是安於現狀、不思進取。而是一種為了達到同樣甚至更好的目標,而付出最少的時間或者精力的行為。一個懶惰的程序員會盡量使自己的代碼即實用又有很好的可讀性,這樣可以節省很多後面的維護的成本。一個懶惰的程序員會儘力完善代碼中的註釋及文檔,以免別人問自己太過問題。一個懶惰的程序員會擅長使用各種工具,從方方面面提升自己的效率。

    懶惰是科技發展、人類進步的最大動力。從原始社會、農業時代、工業時代一直到如今的信息時代。因為懶惰,人們才會有動力去發明各種高效、便捷的工具,這些當初的工具,漸漸的就形成了如今的科技。所謂工欲善其事、必先利其器,說的就是這個道理。

    在一篇文章中,作者將介紹多種實用的工具,全方位的武裝你,使我們的讀者都可以當一個“懶惰”的程序員。

    搜索類在線工具

    1、SearchCode(https://searchcode.com/ )是一個源碼搜索引擎,目前支持從 Github、Bitbucket、Google Code、CodePlex、SourceForge 和 Fedora Project 平台搜索公開的源碼。

    2、mvnrepository(http://mvnrepository.com )這個不用詳細解釋了,就是查詢maven的gav等信息。

    3、Iconfont(https://www.iconfont.cn )國內功能很強大且圖標內容很豐富的矢量圖標庫,提供矢量圖標下載、在線存儲、格式轉換等功能。阿里巴巴體驗團隊傾力打造,設計和前端開發的便捷工具。

    4、BinaryDoc for OpenJDK(https://openjdk.binarydoc.org/net.java/openjdk/)直接從OpenJDK二進制文件生成文檔,二進制代碼是最好的文檔。

    5、Unsplash(https://unsplash.com )是一個免費的圖片分享網站,可以在上面搜索無版權圖片

    6、鳩摩搜書(https://www.jiumodiary.com/ )國內一款強大的电子書搜索引擎,整合了大部分电子書平台的資源,最重要的是他無需註冊登錄,可以直接下載。並且網站頁面清新、且資源免費。

    7、MySlide(https://myslide.cn/ )是一個提供PPT分享服務的平台,在這裏你可以找到你想要的PPT。專註技術領域的PPT共享,各種技術大會的演講PPT這裏都有。

    8、IT大咖說(https://www.itdks.com/ )是IT垂直領域的大咖知識分享平台,分享行業TOP大咖乾貨,技術大會在線直播錄播,在線直播知識分享平台。

    生成類在線工具

    1、BeJSON(http://www.bejson.com/json2javapojo )是一個比較好用將Json轉成Java對象的工具。json是目前JavaWeb中數據傳輸的主要格式,很多時候會有把json轉成Java對象的需求。有時候合作方會提供一個json的樣例,需要我們自己定義Java類,這時候這個工具就派上用場了。

    2、在線corn生成工具(https://cron.qqe2.com/ ),Cron 一般用於配置定時任務的執行。但是要想一次性的把一個corn表達式配置好確實很難的,需要程序員記住他的語法。有一些在線工具可以提供圖形化的界面,只要輸入想要定時執行的周期等,就可以自動生成corn表達式。

    3、正則表達式的生成工具(http://tool.chinaz.com/tools/regexgenerate )正則表達式,又稱規則表達式。(英語:Regular Expression,在代碼中常簡寫為regex、regexp或RE),計算機科學的一個概念。正則表達式通常被用來檢索、替換那些符合某個模式(規則)的文本。在使用正則表達式進行字符轉過濾的時候,需要用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規則字符串”,這個“規則字符串”用來表達對字符串的一種過濾邏輯。通常,這個規則字符串的定義是比較麻煩和複雜的。也需要經過大量的測試和驗證才能被採用。

    4、 ASCII藝術生成工具(http://patorjk.com/software/taag/ )可以將輸入的字符快速轉換成ASCII藝術文字的形式。

    5、ProcessOn(https://www.processon.com/ )是一個在線協作繪圖平台,為用戶提供最強大、易用的作圖工具!支持在線創作流程圖、BPMN、UML圖、UI界面原型設計、iOS界面原型設計。

    6、MarkDown編輯器,Markdown 是一種輕量級標記語言,它允許人們使用易讀易寫的純文本格式編寫文檔,深受廣大程序員們的喜愛,推薦幾款在線md編輯器:MaHua(https://mahua.jser.me/ ) 馬克飛象(https://maxiang.io/ ) Cmd(https://www.zybuluo.com/mdeditor )

    轉換類在線工具

    1、站長工具的編碼轉換(http://tool.chinaz.com/tools/unicode.aspx )比較全面,提供了Unicode編碼、UFT8編碼、URL編碼/解碼等功能。編碼問題一直困擾着開發人員,尤其在Java 中更加明顯,因為Java 是跨平台語言,不同平台之間編碼之間的切換較多。計算中提拱了多種編碼方式,常見的有 ASCII、ISO-8859-1、GB2312、GBK、UTF-8、UTF-16 等。有些時候開發人員需要通過編碼轉換的方式來查看不同編碼下面的文件內容。

    2、時間戳轉換工具(http://tool.chinaz.com/Tools/unixtime.aspx),時間戳(英語:Timestamp)是指在一連串的資料中加入辨識文字,如時間或日期,用以保障本地端(local)資料更新順序與遠端(remote)一致。

    3、Timebie(http://www.timebie.com/cn/easternbeijing.php )提供了世界時間相互轉換的功能。世界各地時間轉換在做國際業務的時候會經常用到,比如北京時間轉紐約時間,北京時間轉洛杉磯時間。

    4、加密解密也是JavaWeb可能會經常遇到的,有的時候我們需要驗證加密算法是否正確,或者要解密等場景,就需要一個在線工具(http://tool.chinaz.com/tools/textencrypt.aspx )來快速驗證。

    5、convertworld(https://www.convertworld.com/zh-hans/ )是一個比較全的單位換算的網站。我經常用它進行時間單位和貨幣單位的換算。

    6、Convertio(https://convertio.co/zh/flv-mp4/ )是一個在線視頻格式轉換工具,支持多種常見視頻格式,如 FLV、MOV 和 AVI 等。上傳的視頻文件不能超過 100 MB。

    7、Docsmall(https://docsmall.com/image-compress )是一個在線圖片壓縮工具,可以批量壓縮圖片、Gif 圖,一次最多上傳 30 張圖片,每張圖片最大為 25 MB。

    檢查類在線工具

    1、JSON格式化工具(https://www.json.cn/ )是我嘗試過很多同類工具之後最經常使用的一個,不僅支持json格式的驗證及格式化,還可以將json格式壓縮成普通文本等好用功能。有時候我們不確定這個文本是否完全符合JSON格式,有時候我們也想可以更清晰的查看這個JSON文本的格式關係。就可以使用這個工具來進行JSON格式的驗證和格式化。

    2、正則驗證(http://tool.chinaz.com/regex ),Java開發對正則表達式肯定不陌生。站長工具提供的這個正則驗真工具還不錯。

    3、Diffchecker(https://www.diffchecker.com/ )是一個使用很不錯代碼差異對比工具。使過svn或者git的人對diffcheck肯定不陌生,但有時候我們修改的文本內容並沒有被版本控制,那麼就可以使用在線的網站查看文件的修改情況。

    對照類工具

    1、ASCII對照表 : http://tool.oschina.net/commons?type=4 2、HTTP狀態碼 : http://tool.oschina.net/commons?type=5 3、HTTP Content-type : http://tool.oschina.net/commons 4、TCP/UDP常見端口參考 : http://tool.oschina.net/commons?type=7 5、HTML轉義字符 : http://tool.oschina.net/commons?type=2 6、RGB顏色參考 : http://tool.oschina.net/commons?type=3 7、網頁字體參考 : http://tool.oschina.net/commons?type=8

    在線代碼運行

    1、CodeRunner(https://tool.lu/coderunner/ )可以在線運行php、c、c++、go、python、java、groovy等代碼。當我們在外面,沒有IDE又想執行個小程序的時候是個不錯的選擇。

    一個實用小插件

    最後,再給大家推薦一個chrome插件,這個插件中囊括了很多上面介紹的在線工具的功能,如JSON格式化、時間戳轉換、Markdown工具、編碼解碼、加密解密、正則驗證等。

    FeHelper ,可以關注我的公眾號,後台回復”在線工具”,我已經把安裝包給大家準備好了。

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

    【其他文章推薦】

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

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

    ※超省錢租車方案

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

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

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

  • 一起玩轉微服務(1)——概念

    一起玩轉微服務(1)——概念

    一、什麼是微服務

    隨着各行各業公司的快速發展,業務規模的不斷擴大,不可避免的造成原有架構不能夠適應快速的增長和變化。這時,微服務就進入大家的視野,其實在微服務之前,很多的公司已經做過服務化的改造,並且取得了一定的成果,但是對於整體流程的標準化還有一定有差距。那麼,什麼是微服務呢?
    準確的說,微服務是一種軟件架構模式,將大型系統或者複雜的應用分割成多個服務的架構,服務之間互相協調、互相配合,為用戶提供最終價值。每個服務都有獨立的生命周期,可以單獨的維護和部署,各個業務模塊之間是松耦合的,比傳統的應用程序更有效地利用計算資源,應用的擴展更加靈活,能夠通過擴展組件來處理功能瓶頸問題。這樣一來,開發人員只需要為額外的組件部署計算資源,而不需要部署一個完整的應用程序的全新迭代。
    一個微服務的架構如圖所示,單體應用被拆分成多個微小的服務:

    也有人將微服務的開發比喻成搭積木,每個服務都是一個零件,使用這些不同的服務可以搭建出不同的形狀。簡單的說,微服務架構就是把一個大系統按業務功能分解成多個職責單一的小系統,並利用簡單的方法使多個小系統相互協作,組合成一個大系統。
    其實這裏蘊含着自古以來的真理,就是分而治之,當一件事情大到不能處理的時候,就使用一定的切分方法,將其變成很多微小的類,然後分門別類的進行處理,以達到最好的效果,最終實現1+1>2的功效。
    微服務的優點和缺點(或者說挑戰)一樣明顯。
    優點

    • 開發簡單,每個服務完成獨立的功能

    • 技術棧靈活,可以選擇不同的語言完成不同的服務,發揮各種語言的最大優勢

    • 服務獨立無依賴,每個服務都可以單獨部署,一個服務出現問題不會導致整個系統癱瘓

    • 獨立按需擴展,以應對高併發以及大流量

    • 可用性高,當其中一個點出現問題時,能夠及時切換,不影響業務正常運行

    • 複雜應用解耦為小而眾的服務,拆分可以基於一定的原則,將耗時的應用解耦

    • 各服務精而專,也就是我們常說的專人干專事,映射到微服務中就是專服務干專事

    • 服務間通信通過API完成,選擇輕量的API通信

      缺點(挑戰)

    • 多服務運維難度,服務的增加意味着運維的困難,如何有效的管理是一個挑戰

    • 系統部署依賴,當業務複雜是,系統之間的耦合關係高度耦合,如何高效部署是一個挑戰

    • 服務間通信成本,包括網絡延遲,接口不可用性等,保證服務的高可用性是一個挑戰

    • 數據一致性,再各個服務間如何有效的共享數據,確保相應服務的數據需求一致性是一個挑戰

    • 系統集成測試,拆分后,原本需要測試的內容成倍的增加,如何高效的降低測試成本是一個挑戰

    • 重複工作,服務拆分之後,由於信息的不對稱導致的重複性工作,如何有效抽象是一個挑戰

    • 性能監控,原本只需要一個監控的部分,現在需要分開監控,如何快速定位問題是一個挑戰

    • 溝通成本的成倍增加,服務拆分后,各個服務由單獨的人來維護,如何高效的溝通是一個挑戰

    二、為什麼微服務

    從一般的平台遇到的問題說起,平台的問題包括:

    • 服務配置複雜。基礎服務多,服務的資源配置複雜。傳統方式管理服務複雜。
    • 服務之間調用複雜。檢索服務、用戶中心服務等,服務之間的調用複雜,依賴多。
    • 服務監控難度大。服務比較多,機器部署複雜,服務存活監控、業務是否正常監控尤為重要。
    • 服務化測試問題。服務依賴性比較大,測試一個小的功能,周邊服務也需要啟動。

    那麼微服務的架構有什麼優勢,大家為什麼都懷着極高的熱情來應對微服務呢。

    1. 區別

    首先看一下兩者的區別,單體應用和分佈式應用都有哪些優點和缺點呢,通過下面的表格來做一下分析和對比?

     

     

    從上面的表格我們可以看到,分佈式系統雖然有一些優勢,但也存在一些問題。

    • 架構設計變得複雜(尤其是其中的分佈式事務)。
    • 部署單個服務會比較快,但是如果一次部署需要多個服務,部署會變得複雜。
    • 系統的吞吐量會變大,但是響應時間會變長。
    • 運維複雜度會因為服務變多而變得很複雜。
    • 架構複雜導致學習曲線變大。
    • 測試和查錯的複雜度增大。
    • 技術可以很多樣,這會帶來維護和運維的複雜度。
    • 管理分佈式系統中的服務和調度變得困難和複雜。

    也就是說,分佈式系統架構的難點在於系統設計,以及管理和運維。

    接下來我們就一起來看一下架構的演變過程。

    2. 從單體應用說起

    下圖是我們非常熟悉的單體應用,或者說是非常傳統的應用架構。
    從圖中可以看到,應用通過瀏覽器進行訪問,當訪問到訂單服務的時候,分單服務提供相應的功能,然後去訪問應用的數據層,數據層負責對數據的解析,這是一個極其典型的單體應用結構,這種結構所帶來的問題顯而易見,數據庫存在單點,所有服務都耦合在一個應用中,當其中一個服務出現問題的時候,整個工程都需要重新發布,從而導致整體業務不能提供響應。這種結構在小項目中是沒有什麼問題的,而且操作起來非常靈活,但當業務量爆增的時候,就無法靈活應對了。

     

     

    3. 第一步切分

    為了應對單體應對無法滿足業務增漲,需要對數據庫進行進一步的切分,以提高擴展性,下圖就是一個切分后的架構圖。

    業務之間通過進程間的服務進行相互調用,數據庫之間沒有耦合性,不會存在單點故障。前端只需要調用相應的服務,返回自身需要的數據,然後與用戶進行交互。可以看到,這種方式比傳統的單體應用已經前進了一步,但是數據庫層面仍然存在着問題,根據數據量需要評估是否使用讀寫分離的設計,服務層面也增加了相應的複雜性。前端調用隨着調用接口數量的增加也急需治理。

    4. 服務化所帶來的問題

    隨着服務的拆分,新的問題應運而生。客戶端如何訪問這些服務?這些服務的調用情況,切分是否合理,安全問題,如果受到攻擊應該如何應對,是否可以使用限流或者降級的方式來及時解決。
    應對這些問題,API網關是一個不錯的解決方案。當有新的設備需要調用這些接口時,可以復用原有接口,不需要進行二次開發。接口的維護也會更有條理性,對於訪問次數,安全等問題,都可以在這一層進行解決。

    解決了應用前端訪問的問題后,服務之間的相互調用也是一個問題,如果整個系統內部調用關係混亂,就會帶來非常多的不必要的問題。所以約定好服務之間的通信方式是非常有必要的。不管是開源還是公司內部研發,都有非常多的解決方案。最簡單的方式,是通過rpc的調用,傳輸json或者XML,雙方定義好協議格式,通過報文的方式進行數據傳輸。
    當多種服務需要互相調用的時候,服務的數量會急劇的增加。服務的治理就成為新的問題。不同的服務的版本問題。如果不能通過一個單獨的註冊地址,像書的目錄一樣來管理整個服務結構,服務的調用就侍显示非常混亂。
    一般的分佈式服務,都有一個註冊中心,例如dubbo是基於zookeeper進行的二次開發,自身提供管理控制台,可以對服務進行註冊和查找,Spring Cloud有Eureka,還有etcd,consul等可供選擇。
    經過上面的處理,整體上來看應用已經達到了一個非常好的狀態,但是每個應用服務仍然存在着單點問題,當一個服務出現問題的時候,有可能導致連鎖的反應,使用整個系統癱瘓。這時候需要除了監控告警之外的一種容錯機制保障整體服務的可運行性。
    通過網關層的反向代理來實現高可用是一個不錯的解決方案,訪問層無需要了解整個體系有多少應用提供,只需要關心服務是否能夠提供服務,並且對必要的接口進行監測,當發現接口無法正常提供服務時,提供相應的告警機制,以微信、短信或者郵件的方式通知相關人及時進行處理。
    隨着服務的切分,業務的擴展,數據量的激增也是一個非常大的問題,如果採用傳統的方案來應對,各種關係型數據庫都有瓶頸,把運算量比較大,比較耗資源的運算,跨庫統計查詢的需求。
    再下一步隨着數據量的不斷增漲,需要業務和統計分離。
    統計一般都是比較耗時的應用,比如計算用戶的留存情況,需要分析一周甚至是更長周期內的用戶數據,如果使用在線的方式分析顯然不太現實,所以,對於大數據量的分析和數據挖掘,需要從業務中抽取數據進行離線分析,然後將分析的結果進行展現。

    5. 微服務的可擴展性

    針對以上的分析,可以看到,微服務需要具備極強的可擴展性,這些擴展性包含以下幾個方面:
    • 性能可擴展:性能無法完全實現線性擴展,但要盡量使用具有併發性和異步性的組件。具備完成通知功能的工作隊列要優於同步連接到數據庫。
    • 可用性可擴展:CAP理論表明,分佈式系統無法同時提供一致性、可用性和分區容錯性保證。許多大規模Web應用程序都為了可用性和分區容錯性而犧牲了強一致性,而後者則有賴於最終一致性來保證。
    • 維護可擴展:軟件和服務器都需要維護。在使用平台的工具監控和更新應用程序時,要盡可能地自動化。
    • 成本可擴展:總成本包括開發、維護和運營支出。在設計一個系統時,要在重用現有組件和完全新開發組件之間進行權衡。現有組件很少能完全滿足需求,但修改現有組件的成本還是可能低於開發一個完全不同的方案。另外,使用符合行業標準的技術使組織更容易聘到專家,而發布獨有的開源方案則可能幫助組織從社區中挖掘人才。

    6. 微服務與SOA的區別

    面向服務的架構(SOA)是一個組件模型,它將應用程序的不同功能單元(稱為服務)通過這些服務之間定義良好的接口和契約聯繫起來。接口是採用中立的方式進行定義的,它應該獨立於實現服務的硬件平台、操作系統和編程語言。這使得構建在各種各樣的系統中的服務可以以一種統一和通用的方式進行交互。
    都是做服務化,那麼微服務與SOA的異同有哪些呢?
    相同點:

    • 需要Registry,實現動態的服務註冊發現機制;
    • 需要考慮分佈式下面的事務一致性,CAP原則下,兩段式提交不能保證性能,事務補償機制需要考慮;
    • 同步調用還是異步消息傳遞,如何保證消息可靠性?SOA由ESB來集成所有的消息;
    • 都需要統一的Gateway來匯聚、編排接口,實現統一認證機制,對外提供APP使用的RESTful接口;
    • 同樣的要關注如何再分佈式下定位系統問題,如何做日誌跟蹤,就像我們電信領域做了十幾年的信令跟蹤的功能;

    差異點:

    • 是持續集成、持續部署?對於CI、CD(持續集成、持續部署),這本身和敏捷、DevOps是交織在一起的,所以這更傾向於軟件工程的領域而不是微服務技術本身;
    • 使用不同的通訊協議是不是區別?微服務的標杆通訊協議是RESTful,而傳統的SOA一般是SOAP,不過目前來說採用輕量級的RPC框架Dubbo、Thrift、gRPC非常多,在Spring Cloud中也有Feign框架將標準RESTful轉為代碼的API這種仿RPC的行為,這些通訊協議不應該是區分微服務架構和SOA的核心差別;
    • 是流行的基於容器框架還是虛擬機為主?Docker和虛擬機還是物理機都是架構實現的一種方式,不是核心區別;

    SOA和微服務的一個主要不同點就是自動化程度上的不同。大部分的SOA實現只達到服務級別的抽象,而微服務走的更遠,它達到了對實現和運行環境的抽象級別。
    而在一個規範的微服務中,每個微服務應該被構建成胖jar(fat Jar)其中內置了所有的依賴,然後作為一個單獨的java進程存在。

    三、常見的微服務組件

    既然談到了微服務架構,就說一下通用的微服務都包括哪些組件:

    • 服務註冊

    服務註冊是一個記錄當前可用的微服務實例的網絡信息數據庫,是服務發現機制的主要核心,服務註冊表查詢api、管理api,使用查詢api獲得可用服務的實例,使用管理api實現註冊、註銷。

    • 服務發現

    服務調用方從服務註冊中心找到自己需要調用的服務的地址。可以選擇客戶端服務發現,也可以選擇服務端服務發現。

    • 負載均衡

    服務提供方一般以多實例的形式提供服務,負載均衡功能能夠讓服務調用方連接到合適的服務節點。並且,節點選擇的工作對服務調用方來說是透明的。可以選擇服務端的負載均衡也可以選擇客戶端的負載均衡。

    • 服務網關

    服務網關是服務調用的唯一入口,可以在這個組件是實現用戶鑒權、動態路由、灰度發布、A/B測試、負載限流等功能。根據公司流量規模的大小網關可以是一個,也可以是多個。

    • 配置中心

    將本地化的配置信息(properties, XML, yaml等)註冊到配置中心,實現程序包在開發、測試、生產環境的無差別性,方便程序包的遷移。配置部分可以單獨使用高可用的分佈式配置中心,確保一個配置服務出現問題是,其它服務也能夠提供配置服務。

    • API管理

    以方便的形式編寫及更新API文檔,並以方便的形式供調用者查看和測試。通常需要加入版本控制的概念,以確保服務的不同版本在升級過程中都能夠提供服務。

    • 集成框架

    微服務組件都以職責單一的程序包對外提供服務,集成框架以配置的形式將所有微服務組件集成到統一的界面框架下,讓用戶能夠在統一的界面中使用系統。

    • 分佈式事務

    對於重要的業務,需要通過分佈式事務技術(TCC、高可用消息服務、最大努力通知)保證數據的一致性。根據業務的不同適當的需要犧牲一些數據的一致性要求,確保數據的最終一致性。

    • 調用鏈

    記錄完成一個業務邏輯時調用到的微服務,並將這種串行或并行的調用關係展示出來。在系統出錯時,可以方便地找到出錯點。同時統計各個服務的調用次數,確保比較熱的服務能夠分配更多的資源。

    • 支撐平台

    系統微服務化后,系統變得更加碎片化,系統的部署、運維、監控等都比單體架構更加複雜,那麼,就需要將大部分的工作自動化。現在,可以通過Docker等工具來中和這些微服務架構帶來的弊端。 例如持續集成、藍綠髮布、健康檢查、性能健康等等。可以這麼說,如果沒有合適的支撐平台或工具,就不要使用微服務架構。

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

    【其他文章推薦】

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

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

    ※回頭車貨運收費標準

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

    ※超省錢租車方案

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