JSON類庫Jackson優雅序列化Java枚舉類

1. 前言

在Java開發中我們為了避免過多的魔法值,使用枚舉類來封裝一些靜態的狀態代碼。但是在將這些枚舉的意思正確而全面的返回給前端卻並不是那麼順利,我們通常會使用Jackson類庫序列化對象為JSON,今天就來講一個關於使用Jackson序列化枚舉的通用性技巧。

2. 通用枚舉範式

為了便於統一處理和規範統一的風格,建議指定一個統一的抽象接口,例如:

/**
 * The interface Enumerator.
 */
public interface Enumerator {
    /**
     * Code integer.
     *
     * @return the integer
     */
    Integer code();

    /**
     * Description string.
     *
     * @return the string
     */
    String description();
}

我們來寫一個實現來標識性別:

public enum GenderEnum implements Enumerator {
   
    UNKNOWN(0, "未知"),

    MALE(1, "男"),

    FEMALE(2, "女");


    private final Integer code;
    private final String description;

    GenderEnum(Integer code, String description) {
        this.code = code;
        this.description = description;
    }


    @Override
    public Integer code() {
        return code;
    }

    @Override
    public String description() {
        return description;
    }
}

3. 序列化枚舉

如果我們直接使用Jackson對枚舉進行序列化,將只能簡單的輸出枚舉的String名稱:

    @Resource
    private ObjectMapper objectMapper;

    @Test
    void enumTest() {
        try {
            String s = objectMapper.writeValueAsString(GenderEnum.MALE);
            // 輸出字符串 MALE
            System.out.println(s);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

我們期望將GenderEnum.MALE 序列化為 {"code":1,"description":"男"} 。我們可以向ObjectMapper定製化一個Module來實現這種個性化需求:

         // 聲明一個簡單Module 對象
         SimpleModule module = new SimpleModule();
           // 給Module 添加一個序列化器
            module.addSerializer(Enumerator.class, new JsonSerializer<Enumerator>() {
                @Override
                public void serialize(Enumerator value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                   // 開始寫入對象
                    gen.writeStartObject();
                    // 分別指定 k v   code   description 
                    gen.writeNumberField("code",value.code());
                    gen.writeStringField("description",value.description());
                    // 顯式結束操作
                    gen.writeEndObject();
                }
            });

        // 註冊 Module
        objectMapper.registerModule(module);

然後再次執行就會獲取我們期望的結果。然而這並不算合理。

4. Spring Boot 中自動全局配置

在Spring Boot應用中我們希望能全局配置。Spring Boot的自動配置為我們提供了一個個性化定製ObjectMapper的可能性,你只需要聲明一個Jackson2ObjectMapperBuilderCustomizer並注入Spring IoC:

@Bean
public Jackson2ObjectMapperBuilderCustomizer enumCustomizer(){
    return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.serializerByType(Enumerator.class, new JsonSerializer<Enumerator>() {
        @Override
        public void serialize(Enumerator value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                    gen.writeStartObject();
                    gen.writeNumberField("code",value.code());
                    gen.writeStringField("description",value.description());
                    gen.writeEndObject();


        }
    });
}

這樣就實現了全局配置。

5. 總結

這裏我們介紹了如何定製Jackson庫以達到對枚舉進行更加友好的序列化的目的。其實不單單枚舉,你也可以實現其它序列化,反序列化,時間輸出格式的定製。這些特性留給你自己挖掘。多多關注:碼農小胖哥 獲取更多開發技巧。

關注公眾號:Felordcn 獲取更多資訊

個人博客:https://felord.cn

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

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

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

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

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

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

※回頭車貨運收費標準

Linux上TCP的幾個內核參數調優

Linux作為一個強大的操作系統,提供了一系列內核參數供我們進行調優。光TCP的調優參數就有50多個。在和線上問題鬥智斗勇的過程中,筆者積累了一些在內網環境應該進行調優的參數。在此分享出來,希望對大家有所幫助。

調優清單

好了,在這裏先列出調優清單。請記住,這裏只是筆者在內網進行TCP內核參數調優的經驗,僅供參考。同時,筆者還會在餘下的博客裏面詳細解釋了為什麼要進行這些調優!

序號 內核參數 值 備註
1.1 /proc/sys/net/ipv4/tcp_max_syn_backlog 2048
1.2 /proc/sys/net/core/somaxconn 2048
1.3 /proc/sys/net/ipv4/tcp_abort_on_overflow 1
2.1 /proc/sys/net/ipv4/tcp_tw_recycle 0 NAT環境必須為0
2.2 /proc/sys/net/ipv4/tcp_tw_reuse 1
3.1 /proc/sys/net/ipv4/tcp_syn_retries 3
3.2 /proc/sys/net/ipv4/tcp_retries2 5
3.3 /proc/sys/net/ipv4/tcp_slow_start_after_idle 0

tcp_max_syn_backlog,somaxconn,tcp_abort_on_overflow

tcp_max_syn_backlog,somaxconn,tcp_abort_on_overflow這三個參數是關於
內核TCP連接緩衝隊列的設置。如果應用層來不及將已經三次握手建立成功的TCP連接從隊列中取出,溢出了這個緩衝隊列(全連接隊列)之後就會丟棄這個連接。如下圖所示:

從而產生一些詭異的現象,這個現象詭異之處就在於,是在TCP第三次握手的時候丟棄連接

就如圖中所示,第二次握手的SYNACK發送給client端了。所以就會出現client端認為連接成功,而Server端確已經丟棄了這個連接的現象!由於無法感知到Server已經丟棄了連接。
所以如果沒有心跳的話,只有在發出第一個請求后,Server才會發送一個reset端通知這個連接已經被丟棄了,建立連接后第二天再用,也會報錯!所以我們要調大Backlog隊列!

echo 2048 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 2048 > /proc/sys/net/core/somaxconn

當然了,為了盡量避免第一筆調用失敗問題,我們也同時要設置

echo 1 > /proc/sys/net/ipv4/tcp_abort_on_overflow

設置這個值以後,Server端內核就會在這個連接被溢出之後發送一個reset包給client端。

如果我們的client端是NIO的話,就可以收到一個socket close的事件以感知到連接被關閉!

注意Java默認的Backlog是50

這個TCP Backlog的隊列大小值是min(tcp_max_syn_backlog,somaxconn,應用層設置的backlog),而Java如果不做額外設置,Backlog默認值僅僅只有50。C語言在使用listen調用的時候需要傳進Backlog參數。

tcp_tw_recycle

tcp_tw_recycle這個參數一般是用來抑制TIME_WAIT數量的,但是它有一個副作用。即在tcp_timestamps開啟(Linux默認開啟),tcp_tw_recycle會經常導致下面這種現象。

也即,如果你的Server開啟了tcp_tw_recycle,那麼別人如果通過NAT之類的調用你的Server的話,NAT後面的機器只有一台機器能正常工作,其它情況大概率失敗。具體原因呢由下圖所示:

在tcp_tw_recycle=1同時tcp_timestamps(默認開啟的情況下),對同一個IP的連接會做這樣的限制,也即之前後建立的連接的時間戳必須要大於之前建立連接的最後時間戳,但是經過NAT的一個IP後面是不同的機器,時間戳相差極大,就會導致內核直接丟棄時間戳較低的連接的現象。由於這個參數導致的問題,高版本內核已經去掉了這個參數。如果考慮TIME_WAIT問題,可以考慮設置一下

echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse

tcp_syn_retries

這個參數值得是client發送SYN如果server端不回復的話,重傳SYN的次數。對我們的直接影響呢就是connet建立連接時的超時時間。當然Java通過一些C原生系統調用的組合使得我們可以進行超時時間的設置。在Linux裏面默認設置是5,下面給出建議值3和默認值5之間的超時時間。

tcp_syn_retries timeout
1 min(so_sndtimeo,3s)
2 min(so_sndtimeo,7s)
3 min(so_sndtimeo,15s)
4 min(so_sndtimeo,31s)
5 min(so_sndtimeo,63s)

下圖給出了,重傳和超時情況的對應圖:

當然了,不同內核版本的超時時間可能不一樣,因為初始RTO在內核小版本間都會有細微的變化。所以,有時候在抓包時候可能會出現(3,6,12……)這樣的序列。當然Java的API有超時時間:

java:
 // 函數調用中攜帶有超時時間
 public void connect(SocketAddress endpoint, int timeout) ;

所以,對於Java而言,這個內核參數的設置沒有那麼重要。但是,有些代碼可能會有忘了設置timeout的情況,例如某個版本的Kafka就是,所以它在我們一些混沌測試的情況下,容災恢復的時間會達到一分多鍾,主要時間就是卡在connect上面-_-!,而這時我們的tcp_syn_retries設置的是5,也即超時時間63s。減少這個恢復時間的手段就是:

echo 3 > /proc/sys/net/ipv4/tcp_syn_retries

tcp_retries2

tcp_retries2這個參數表面意思是在傳輸過程中tcp的重傳次數。但在某個版本之後Linux內核僅僅用這個tcp_retries2來計算超時時間,在這段時間的重傳次數純粹由RTO等環境因素決定,重傳超時時間在5/15下的表現為:

tcp_retries2 對端無響應
5 25.6s-51.2s根據動態rto定
15 924.6s-1044.6s根據動態rto定

如果我們在應用層設置的Socket所有ReadTimeout都很小的話(例如3s),這個內核參數調整是沒有必要的。但是,筆者經常發現有的系統,因為一兩個慢的接口或者SQL,所以將ReadTimeout設的很大的情況。

平常這種情況是沒有問題的,因為慢請求頻率很低,不會對系統造成什麼風險。但是,物理機突然宕機時候的情況就不一樣了,由於ReadTimeOut設置的過大,導致所有落到這台宕機的機器都會在min(ReadTimeOut,(924.6s-1044.6s)(Linux默認tcp_retries2是15))后才能從read系統調用返回。假設ReadTimeout設置了個5min,系統總線程數是200,那麼只要5min內有200個請求落到宕機的server就會使A系統失去響應!

但如果將tcp_retries2設置為5,那麼超時返回時間即為min(ReadTimeOut 5min,25.6-51.2s),也就是30s左右,極大的緩解了這一情況。

echo 5 > /proc/sys/net/ipv4/tcp_retries2

但是針對這種現象,最好要做資源上的隔離,例如線程上的隔離或者機器級的隔離。

golang的goroutine調度模型就可以很好的解決線程資源不夠的問題,但缺點是goroutine裏面不能有阻塞的系統調用,不然也會和上面一樣,但僅僅對於系統之間互相調用而言,都是非阻塞IO,所以golang做微服務還是非常Nice的。當然了我大Java用純IO事件觸發編寫代碼也不會有問題,就是對心智負擔太高-_-!

物理機突然宕機和進程宕不一樣

值得注意的是,物理機宕機和進程宕但內核還存在表現完全不一樣。

僅僅進程宕而內核存活,那麼內核會立馬發送reset給對端,從而不會卡住A系統的線程資源。

tcp_slow_start_after_idle

還有一個可能需要調整的參數是tcp_slow_start_after_idle,Linux默認是1,即開啟狀態。開啟這個參數后,我們的TCP擁塞窗口會在一個RTO時間空閑之後重置為初始擁塞窗口(CWND)大小,這無疑大幅的減少了長連接的優勢。對應Linux源碼為:

static void tcp_event_data_sent(struct tcp_sock *tp,
				struct sk_buff *skb, struct sock *sk){
	// 如果開啟了start_after_idle,而且這次發送的時間-上次發送的時間>一個rto,就重置tcp擁塞窗口
	if (sysctl_tcp_slow_start_after_idle &&
	    (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto))
		tcp_cwnd_restart(sk, __sk_dst_get(sk));
}

關閉這個參數后,無疑會提高某些請求的傳輸速度(在帶寬夠的情況下)。

echo 0 > /proc/sys/net/ipv4/tcp_slow_start_after_idle

當然了,Linux啟用這個參數也是有理由的,如果我們的網絡情況是時刻在變化的,例如拿個手機到處移動,那麼將擁塞窗口重置確實是個不錯的選項。但是就我們內網系統間調用而言,是不太必要的了。

初始CWND大小

毫無疑問,新建連接之後的初始TCP擁塞窗口大小也直接影響到我們的請求速率。在Linux2.6.32源碼中,其初始擁塞窗口是(2-4個)mss大小,對應於內網估計也就是(2.8-5.6K)(MTU 1500),這個大小對於某些大請求可能有點捉襟見肘。
在Linux 2.6.39以上或者某些RedHat維護的小版本中已經把CWND
增大到RFC 6928所規定的的10段,也就是在內網裡面估計14K左右(MTU 1500)。

Linux 新版本
/* TCP initial congestion window */
#define TCP_INIT_CWND		10

公眾號

關注筆者公眾號,獲取更多乾貨文章

總結

Linux提供了一大堆內參參數供我們進行調優,其默認設置的參數在很多情況下並不是最佳實踐,所以我們需要潛心研究,找到最適合當前環境的組合。

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

最通俗易懂的RSA加密解密指導

前言

RSA加密算法是一種非對稱加密算法,簡單來說,就是加密時使用一個鑰匙,解密時使用另一個鑰匙。

因為加密的鑰匙是公開的,所又稱公鑰,解密的鑰匙是不公開的,所以稱為私鑰。

密鑰

關於RSA加密有很多文章,但幾乎都只介紹了RSACryptoServiceProvider類的使用方法,如果只是走走看看,是沒問題的,但真的想使用時,就會發現,你沒有密鑰字符串。。。

下面我們從獲取密鑰字符串開始逐步學習加密。

密鑰字符串

每個安裝過VisualStudio的電腦都可以找到一個文件—makecert.exe。

我電腦的makecert.exe地址:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\makecert.exe

makecert.exe是用來生成證書的程序,我們可以借用該程序來獲取密鑰字符串。

 

編寫生成證書的CreateCertWithPrivateKey函數,代碼如下:

 public static bool CreateCertWithPrivateKey(string subjectName, string makecertPath)
 {
     subjectName = "CN=" + subjectName;
     string param = " -pe -ss my -n \"" + subjectName + "\" ";
     try
     {
         Process p = Process.Start(makecertPath, param);
         p.WaitForExit();
         p.Close();
     }
     catch (Exception e)
     { 
         return false;
     }
     return true;
 }

調用證書生成函數,代碼如下:

string keyName = "Kiba518.Licence";//證書的KEY 
var ret = DataCertificate.CreateCertWithPrivateKey(keyName, @"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\makecert.exe");

剛剛生成的證書還存儲在WINDOWS的證書存儲區,現在我們通過證書的Key在證書存儲區查找到證書,並將其到出(導出時需要指定密碼),導出函數代碼如下:

public static bool ExportToPfxFile(string subjectName, string pfxFileName,
    string password, bool isDelFromStore)
{
    subjectName = "CN=" + subjectName;
    X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    store.Open(OpenFlags.ReadWrite);
    X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;
    foreach (X509Certificate2 x509 in storecollection)
    {
        if (x509.Subject == subjectName)
        { 
            byte[] pfxByte = x509.Export(X509ContentType.Pfx, password);
            using (FileStream fileStream = new FileStream(pfxFileName, FileMode.Create))
            {
                // Write the data to the file, byte by byte. 
                for (int i = 0; i < pfxByte.Length; i++)
                    fileStream.WriteByte(pfxByte[i]);
                // Set the stream position to the beginning of the file. 
                fileStream.Seek(0, SeekOrigin.Begin);
                // Read and verify the data. 
                for (int i = 0; i < fileStream.Length; i++)
                {
                    if (pfxByte[i] != fileStream.ReadByte())
                    { 
                        fileStream.Close();
                        return false;
                    }
                }
                fileStream.Close();
            }
            if (isDelFromStore == true)
                store.Remove(x509);
        }
    }
    store.Close();
    store = null;
    storecollection = null;
    return true;
}

調用導出函數,代碼如下:

DataCertificate.ExportToPfxFile(keyName, "Kiba518.pfx", "123456", true);

運行完導出函數后,我們打開Debug文件夾,可以看到證書已經被成功導出了,如下圖:

證書導出后,我們就可以通過讀取證書的信息,來獲取到公鑰和私鑰了。

X509Certificate2 x509 = X509Certificate2("Kiba518.pfx", "123456", X509KeyStorageFlags.Exportable);
string publickey = x509.PublicKey.Key.ToXmlString(false);//公鑰獲取
string privatekey = x509.PrivateKey.ToXmlString(true);//私鑰獲取

公鑰私鑰如下圖所示:

加密解密

得到密鑰字符串后,我們創建RSA的加密解密函數,代碼如下:

//加密
public static string RSADecrypt(string xmlPrivateKey, string enptStr)
{
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
    provider.FromXmlString(xmlPrivateKey);
    byte[] rgb = Convert.FromBase64String(enptStr);
    byte[] bytes = provider.Decrypt(rgb, RSAEncryptionPadding.OaepSHA1);
    return new UnicodeEncoding().GetString(bytes);
}
//解密
public static string RSAEncrypt(string xmlPublicKey, string enptStr)
{
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
    provider.FromXmlString(xmlPublicKey);
    byte[] bytes = new UnicodeEncoding().GetBytes(enptStr);
    return Convert.ToBase64String(provider.Encrypt(bytes, RSAEncryptionPadding.OaepSHA1));
}

然後我們測試一下加密解密,測試函數如下。

public static void RsaTest()
{
    string myname = "my name is Kiba518!";
    Console.WriteLine($"內容:{myname}");
    string enStr = RSAEncrypt(publicKey, myname);
    Console.WriteLine($"加密字符串:{enStr}");
    string deStr = RSADecrypt(privateKey, enStr);
    Console.WriteLine($"解密字符串:{enStr}");
}

運行結果,加密解密成功,如下圖所示:

長字符分段加密

Rsa加密有字節數限制,即待加密的字符串太長,系統就會拋出異常:【System.Security.Cryptography.CryptographicException:“不正確的長度】

Rsa加密具體限制內容如下:

待加密的字節數不能超過密鑰的長度值除以 8 再減去 11(即:RSACryptoServiceProvider.KeySize / 8 – 11),而加密后得到密文的字節數,正好是密鑰的長度值除以 8(即:RSACryptoServiceProvider.KeySize / 8)。

分段加密

為解決長字符加密的異常,我們採取分段加密的方法進行字符串加密,代碼如下:

//加密
public static String SubRSAEncrypt(string xmlPublicKey, string enptStr)
{ 
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
    provider.FromXmlString(xmlPublicKey);
    Byte[] bytes = Encoder.GetBytes(enptStr);
    int MaxBlockSize = provider.KeySize / 8 - 11;    //加密塊最大長度限制
​
    if (bytes.Length <= MaxBlockSize)
        return Convert.ToBase64String(provider.Encrypt(bytes, false));
​
    using (MemoryStream PlaiStream = new MemoryStream(bytes))
    using (MemoryStream CrypStream = new MemoryStream())
    {
        Byte[] Buffer = new Byte[MaxBlockSize];
        int BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
​
        while (BlockSize > 0)
        {
            Byte[] ToEncrypt = new Byte[BlockSize];
            Array.Copy(Buffer, 0, ToEncrypt, 0, BlockSize);
​
            Byte[] Cryptograph = provider.Encrypt(ToEncrypt, false);
            CrypStream.Write(Cryptograph, 0, Cryptograph.Length);
​
            BlockSize = PlaiStream.Read(Buffer, 0, MaxBlockSize);
        }
​
        return Convert.ToBase64String(CrypStream.ToArray(), Base64FormattingOptions.None);
    } 
}
//解密
public static String SubRSADecrypt(string xmlPublicKey, string enptStr)
{ 
    RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
    provider.FromXmlString(xmlPublicKey);
    Byte[] bytes = Convert.FromBase64String(enptStr);
    int MaxBlockSize = provider.KeySize / 8;    //解密塊最大長度限制
​
    if (bytes.Length <= MaxBlockSize)
        return Encoder.GetString(provider.Decrypt(bytes, false));
​
    using (MemoryStream CrypStream = new MemoryStream(bytes))
    using (MemoryStream PlaiStream = new MemoryStream())
    {
        Byte[] Buffer = new Byte[MaxBlockSize];
        int BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
​
        while (BlockSize > 0)
        {
            Byte[] ToDecrypt = new Byte[BlockSize];
            Array.Copy(Buffer, 0, ToDecrypt, 0, BlockSize); 
            Byte[] Plaintext = provider.Decrypt(ToDecrypt, false);
            PlaiStream.Write(Plaintext, 0, Plaintext.Length); 
            BlockSize = CrypStream.Read(Buffer, 0, MaxBlockSize);
        } 
        return Encoder.GetString(PlaiStream.ToArray());
    }
}  

編寫分段加密測試函數如下:

public static void SubRsaTest()
{
    string myname = "my name is Kiba518!my name is Kiba518!my name is Kiba518!my name is Kiba518!my name is Kiba518!my name is Kiba518!my name is Kiba518!";
    Console.WriteLine($"內容:{myname}");
    string enStr = SubRSAEncrypt(publicKey, myname);
    Console.WriteLine($"加密字符串:{enStr}");
    string deStr = SubRSADecrypt(privateKey, enStr);
    Console.WriteLine($"解密字符串:{deStr}");
}

運行結果,加密解密成功,如下圖:

關於證書

文中創建的證書—Kiba518.pfx,就是https所使用的證書,換言之,https的證書就是個Rsa加密解密文件。

當然正式的可以在互聯網中被各大網站認可的證書,是需要權威機構認證的,這個機構叫做CA,這個機構頒發的證書是.crt後綴名;而我們的pfx後綴名的證書,學名叫做個人信息交換證書。

其實它們沒有什麼區別,就是套的殼子不一樣,crt證書的殼子里多一些屬性,比如認證機構,有效期等等。但兩個證書的核心內容是一樣的,都是Rsa加密解密文件。

下面我們簡單了解下證書的導入。

導入證書

在運行窗口(window+r)輸入mmc打開microsoft管理控制台。

然後操作文件 -> 添加/刪除管理單元,選擇可用的管理單元中的證書點擊添加。

添加完管理單元,在右側控制台根節點會增加一個證書的根節點,如下圖:

然後,我們展開節點,找到【個人—證書】節點,然後【右鍵—所有任務—導入】。

然後按嚮導提示導入證書。

需要注意的是瀏覽導入證書的對話框,默認導入的是crt類型,我們需要點擊下拉菜單,選擇人信息交換選項,如下圖。

—————————————————————————————————-

到此Rsa加密解密的基本使用已經介紹完了。

代碼已經傳到Github上了,歡迎大家下載。

Github地址:https://github.com/kiba518/RsaDemo

—————————————————————————————————-

注:此文章為原創,任何形式的轉載都請聯繫作者獲得授權並註明出處!
若您覺得這篇文章還不錯,請點擊下方的【推薦】,非常感謝!

https://www.cnblogs.com/kiba/p/13141981.html

 

 

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

【其他文章推薦】

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

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

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

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

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

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

從零開始學習Prometheus監控報警系統

Prometheus簡介

Prometheus是一個開源的監控報警系統,它最初由SoundCloud開發。

2016年,Prometheus被納入了由谷歌發起的Linux基金會旗下的雲原生基金會( Cloud Native Computing Foundation),並成為僅次於Kubernetes的第二大開源項目。自此,它成為了一個獨立的開源項目,獨立於任何公司進行維護。

Prometheus擁有非常活躍的開發人員和用戶社區,目前在GitHub上已擁有三萬多的Star。

Prometheus特點

  • 提供多維度數據模型,使用指標名稱和鍵值對標識的時間序列數據
  • 提供靈活的PromQL查詢方式,還提供了HTTP查詢接口,可以很方便地結合Grafana等組件展示數據。
  • 不依賴外部存儲,支持單節點的本地存儲。通過Prometheus自帶的時序數據庫,可以完成每秒百萬及的數據存儲,如果需要存儲大量歷史數據,還可以對接第三方的時序數據庫。
  • 時間序列收集通過HTTP的拉取方式進行,並提供了開放的指標數據標準。
  • 支持向中間網關推送時序數據,可以更加靈活地適用於多種監控場景。
  • 支持通過動態服務發現和靜態文件配置獲取監控對象,目前已支持Kubernetes、Etcd、Consul等多種服務發現機制。
  • 支持多種模式的圖形展示和儀錶盤。
  • 大多數Prometheus的組件都是使用Go語言編寫的,這使得它們很容易以二進制文件的形式構建和部署。

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

Prometheus架構

Prometheus生態圈由多個組件構成,其中許多組件是可選的:

  • Prometheus Server:用於收集、存儲和查詢時間序列數據。通過靜態配置文件管理監控目標,也可以配合使用動態服務發現的方式動態管理監控目標,並從這些監控目標中獲取數據。它將採集到的數據按照時間序列的方式存儲在本地磁盤當中或者外部的時序數據庫中,可通過PromQL語言對數據的查詢以及分析。
  • Client Library:為被監控的應用生成相應的指標(Metric)數據並暴露給Prometheus Server。當Prometheus Server 來拉取時,直接返回實時狀態的指標數據。
  • Push Gateway:主要用於短期存在的Jobs。由於這類Jobs存在時間較短,可能在Prometheus Server來拉取數據之前就消失了。所以,Jobs可以直接向Push Gateway推送它們的指標數據,然後Prometheus Server再從Push Gateway拉取。
  • Exporters:用於暴露已有的第三方服務的指標數據通過HTTP服務的形式暴露給Prometheus Server,比如HAProxy、StatsD、Graphite等等。Prometheus Server通過訪問該Exporter提供的Endpoint,即可獲取到需要採集的監控數據。
  • Alertmanager:從Prometheus Server接收到告警后,會進行去除重複數據,分組,並路由到對收的接受方式,發出報警。Alertmanager的告警方式非常靈活,支持通過郵件、slack或釘釘等多種途徑發出告警。
  • 一些其他的組件。

下面這張圖展示了Prometheus的架構和各個組件是如何交互和協作的:

其大概的工作流程是:

  1. Prometheus Server直接從HTTP接口或者Push Gateway拉取指標(Metric)數據。
  2. Prometheus Server在本地存儲所有採集的指標(Metric)數據,並在這些數據上運行規則,從現有數據中聚合和記錄新的時間序列,或者生成告警。
  3. Alertmanager根據配置文件,對接收到的告警進行處理,發出報警。
  4. 在Grafana或其他API客戶端中,可視化收集的數據。

Prometheus數據模型

Prometheus會將所有採集到的監控數據以時間序列的方式保存在內存數據庫中,並且定時保存到硬盤上。每一條數據由以下三部分組成:

  • 指標(Metric):由指標名稱和描述當前數據特徵的標籤組成。
  • 時間戳(Timestamp):一個精確到毫秒的時間戳。
  • 數據值(Value):一個float64的浮點型數據表示當前數據的值。

其中,指標(Metric)通過如下格式標識:

<指標名稱>{<標籤名稱>=<標籤值>, ...}

指標名稱(Metric Name)可以反映被監控數據的含義。指標名稱只能由ASCII字符、数字、下劃線以及冒號組成並必須符合正則表達式[a-zA-Z_:][a-zA-Z0-9_:]*。
標籤(Label)反映了當前數據的特徵維度,通過這些維度Prometheus可以對數據進行過濾,聚合等操作。標籤的名稱只能由ASCII字符、数字以及下劃線組成並滿足正則表達式[a-zA-Z_][a-zA-Z0-9_]*。

比如:

prometheus_http_requests_total{code="200",handler="/metrics"}

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

指標類型

Prometheus定義了4種不同的指標類型(Metric Type):

  • Counter(計數器)
  • Gauge(儀錶盤)
  • Histogram(直方圖)
  • Summary(摘要)

Counter(計數器)

Counter類型和計數器一樣,只增不減(除非系統發生重置),一般在定義Counter類型指標的名稱時推薦使用_total作為後綴。

比如,Prometheus Server中prometheus_http_requests_total, 表示Prometheus處理的HTTP請求總數:

# HELP prometheus_http_requests_total Counter of HTTP requests.
# TYPE prometheus_http_requests_total counter
prometheus_http_requests_total{code="200",handler="/api/v1/label/:name/values"} 3
prometheus_http_requests_total{code="200",handler="/api/v1/query"} 5
prometheus_http_requests_total{code="200",handler="/api/v1/query_range"} 15
prometheus_http_requests_total{code="200",handler="/graph"} 3
prometheus_http_requests_total{code="200",handler="/metrics"} 23
prometheus_http_requests_total{code="200",handler="/static/*filepath"} 18
prometheus_http_requests_total{code="302",handler="/"} 1

Gauge(儀錶盤)

Gauge類型側重於反應系統的某一個瞬時的值,這類指標的數據可增可減。

比如,Prometheus Server中go_threads, 表示Prometheus當前go線程的數量:

# HELP go_threads Number of OS threads created.
# TYPE go_threads gauge
go_threads 13

Histogram(直方圖)

Histogram類型由 _bucket{le=” “}, _bucket{le=”+Inf”}, _sum, _count 組成,主要用於表示一段時間範圍內對數據進行採樣,並能夠對其指定區間以及總數進行統計,通常它採集的數據展示為直方圖。

比如,Prometheus Server中prometheus_http_response_size_bytes:

# HELP prometheus_http_response_size_bytes Histogram of response size for HTTP requests.
# TYPE prometheus_http_response_size_bytes histogram
prometheus_http_response_size_bytes_bucket{handler="/",le="100"} 1
prometheus_http_response_size_bytes_bucket{handler="/",le="1000"} 1
prometheus_http_response_size_bytes_bucket{handler="/",le="10000"} 1
prometheus_http_response_size_bytes_bucket{handler="/",le="100000"} 1
prometheus_http_response_size_bytes_bucket{handler="/",le="1e+06"} 1
prometheus_http_response_size_bytes_bucket{handler="/",le="1e+07"} 1
prometheus_http_response_size_bytes_bucket{handler="/",le="1e+08"} 1
prometheus_http_response_size_bytes_bucket{handler="/",le="1e+09"} 1
prometheus_http_response_size_bytes_bucket{handler="/",le="+Inf"} 1
prometheus_http_response_size_bytes_sum{handler="/"} 29
prometheus_http_response_size_bytes_count{handler="/"} 1

Summary(摘要)

Summary類型由 {quantile=”<φ>”}, _sum, _count 組成,主要用於表示一段時間內數據採樣結果,它直接存儲了分位數據,而不是根據統計區間計算出來的。

比如,Prometheus Server中prometheus_target_interval_length_seconds:

# HELP prometheus_target_interval_length_seconds Actual intervals between scrapes.
# TYPE prometheus_target_interval_length_seconds summary
prometheus_target_interval_length_seconds{interval="15s",quantile="0.01"} 14.9986249
prometheus_target_interval_length_seconds{interval="15s",quantile="0.05"} 14.998999
prometheus_target_interval_length_seconds{interval="15s",quantile="0.5"} 15.0000428
prometheus_target_interval_length_seconds{interval="15s",quantile="0.9"} 15.0012009
prometheus_target_interval_length_seconds{interval="15s",quantile="0.99"} 15.0016468
prometheus_target_interval_length_seconds_sum{interval="15s"} 315.0013755
prometheus_target_interval_length_seconds_count{interval="15s"} 21

歡迎關注微信公眾號:萬貓學社,每周一分享Java技術乾貨。

安裝Prometheus Server

從官方網站(https://prometheus.io/download/)上找到最新版本的Prometheus Sevrer軟件包,如下圖:
根據自己的系統下載對應的壓縮包,這裏以Windows為例,下載prometheus-2.19.0.windows-amd64.tar.gz。

解壓后當前目錄會包含默認的Prometheus配置文件promethes.yml:

# my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets:
      # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
    - targets: ['localhost:9090']

暫且不做修改,雙擊prometheus.exe即可啟動,如下圖:

訪問http://localhost:9090/graph,就可以看到Prometheus自身的監控數據:

尾聲

Prometheus的大致介紹已經告一段落了,但是只是萬里長征的第一步,Prometheus的更多強大功能和使用方法還等待我們去挖掘。

微信公眾號:萬貓學社

微信掃描二維碼

獲得更多Java技術乾貨

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

【其他文章推薦】

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

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

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

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

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

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

一起玩轉微服務(9)——前後端分離

前後端分離

在傳統的web應用開發中,大多數的程序員會將瀏覽器作為前後端的分界線。將瀏覽器中為用戶進行頁面展示的部分稱之為前端,而將運行在服務器,為前端提供業務邏輯和數據準備的所有代碼統稱為後端。 由於前後端分離這個概念相對來說剛出現不久,很多人都是只聞其聲,不見其形,所以可能會對它產生一些誤解,誤以為前後端分離只是一種web應用開發模式,只要在web應用的開發期進行了前後端開發工作的分工就是前後端分離。 其實前後端分離並不只是開發模式,而是web應用的一種架構模式。在開發階段,前後端工程師約定好數據交互接口,實現并行開發和測試;在運行階段前後端分離模式需要對web應用進行分離部署,前後端之前使用HTTP或者其他協議進行交互請求。 前後端分離原則,簡單來講就是前端和後端的代碼分離也就是技術上做分離。推薦的模式是最好直接採用物理分離的方式部署,進一步促使進行更徹底的分離。不要繼續以前的服務端模板技術,比如JSP ,把Java JS HTML CSS 都堆到一個頁面里,稍複雜的頁面就無法維護。

好處

這種分離模式的方式有幾個好處:

•前後端技術分離,可以由各自的專家來對各自的領域進行優化,這樣前端的用戶體驗優化效果會更好。•分離模式下,前後端交互界面更加清晰,就剩下了接口和模型,後端的接口簡潔明了,更容易維護。•前端多渠道集成場景更容易實現,後端服務無需變更,採用統一的數據和模型,可以支撐前端的web UI\ 移動App等訪問。

前後端分離意味着,前後端之間使用 JSON 來交流,兩個開發團隊之間使用 API 作為契約進行交互。從此,後台選用的技術棧不影響前台。 前後端分離並非僅僅只是前後端開發的分工,而是在開發期進行代碼存放分離、前後端開發職責分離,前後端能夠獨立進行開發測試;在運行期進行應用部署分離,前後端之間通過HTTP請求進行通訊。前後端分離的開發模式與傳統模式相比,能為我們提升開發效率、增強代碼可維護性,讓我們有規劃地打造一個前後端並重的精益開發團隊,更好地應對越來越複雜多變的Web應用開發需求。 前後端分離的核心:後台提供數據,前端負責显示。

常見的前端

AngularJS

Angular JS (Angular.JS) 是一組用來開發 Web 頁面的框架、模板以及數據綁定和豐富 UI 組件。它支持整個開發進程,提供 Web 應用的架構,無需進行手工 DOM 操作。 AngularJS 很小,只有 60K,兼容主流瀏覽器,與 jQuery 配合良好。

數據綁定可能是 AngularJS 最酷最實用的特性。它能夠幫助你避免書寫大量的初始代碼從而節約開發時間。一個典型的 Web 應用可能包含了 80% 的代碼用來處理,查詢和監聽 DOM。數據綁定使得代碼更少,你可以專註於你的應用。

傳統來說,當 Model 變化了。 開發人員需要手動處理 DOM 元素並且將屬性反映到這些變化中。這個一個雙向的過程。一方面,Model 變化驅動了 DOM 中元素變化,另一方面,DOM 元素的變化也會影響到 Model。這個在用戶互動中更加複雜,因為開發人員需要處理和解析這些互動,然後融合到一個 Model 中,並且更新 View。這是一個手動的複雜過程,當一個應用非常龐大的時候,將會是一件非常費勁的事情。

特性二:模板

在 AngularJS 中,一個模板就是一個 HTML 文件。但是 HTML 的內容擴展了,包含了很多幫助你映射 Model 到 View 的內容。

HTML 模板將會被瀏覽器解析到 DOM 中。DOM 然後成為 AngularJS 編譯器的輸入。AngularJS 將會遍歷 DOM 模板來生成一些指導,即,directive(指令)。所有的指令都負責針對 View 來設置數據綁定。

我們要理解 AuguarJS 並不把模板當做 String 來操作。輸入 AngularJS 的是 DOM 而非 string。數據綁定是 DOM 變化,不是字符串的連接或者 innerHTML 變化。使用 DOM 作為輸入,而不是字符串,是 AngularJS 區別於其它的框架的最大原因。使用 DOM 允許你擴展指令詞彙並且可以創建你自己的指令,甚至開發可重用的組件。

特性三:MVC

針對客戶端應用開發 AngularJS 吸收了傳統的 MVC 基本原則。MVC 或者 Model-View-Controll 設計模式針對不同的人可能意味不同的東西。AngularJS 並不執行傳統意義上的 MVC,更接近於 MVVM(Model-View-ViewModel)。

特性四:依賴注入(Dependency Injection,即 DI)

AngularJS 擁有內建的依賴注入子系統,可以幫助開發人員更容易的開發,理解和測試應用。

DI 允許你請求你的依賴,而不是自己找尋它們。比如,我們需要一個東西,DI 負責找創建並且提供給我們。

特性五:Directives(指令)

指令是我個人最喜歡的特性。你是不是也希望瀏覽器可以做點兒有意思的事情?那麼 AngularJS 可以做到。
指令可以用來創建自定義的標籤。它們可以用來裝飾元素或者操作 DOM 屬性。

2. React

React 是一個用於構建用戶界面的 JAVASCRIPT 庫。
React 主要用於構建UI,很多人認為 React 是 MVC 中的 V(視圖)。
React 起源於 Facebook 的內部項目,用來架設 Instagram 的網站,並於 2013 年 5 月開源。
React 擁有較高的性能,代碼邏輯非常簡單,越來越多的人已開始關注和使用它。
使用 React 可以將一些簡短、獨立的代碼片段組合成複雜的 UI 界面,這些代碼片段被稱作“組件”。

React特點

  1. 聲明式設計 −React採用聲明範式,可以輕鬆描述應用。

  2. 高效 −React通過對DOM的模擬,最大限度地減少與DOM的交互。

  3. 靈活 −React可以與已知的庫或框架很好地配合。

  4. JSX − JSX 是 JavaScript 語法的擴展。React 開發不一定使用 JSX ,但我們建議使用它。

  5. 組件 − 通過 React 構建組件,使得代碼更加容易得到復用,能夠很好的應用在大項目的開發中。

  6. 單向響應的數據流 − React 實現了單向響應的數據流,從而減少了重複代碼,這也是它為什麼比傳統數據綁定更簡單。

Vue.js

Vue.js(讀音 /vjuː/, 類似於 view) 是一套構建用戶界面的漸進式框架。

Vue 只關注視圖層, 採用自底向上增量開發的設計。

Vue 的目標是通過盡可能簡單的 API 實現響應的數據綁定和組合的視圖組件。

 

 

Kotlin

Kotlin 是一種在 Java 虛擬機上運行的靜態類型編程語言,被稱之為 Android 世界的Swift,由 JetBrains 設計開發並開源。

Kotlin 可以編譯成Java字節碼,也可以編譯成 JavaScript,方便在沒有 JVM 的設備上運行。

在Google I/O 2017中,Google 宣布 Kotlin 成為 Android 官方開發語言。

 

5. Flutter

 

Flutter 由 Google 的工程師團隊打造,用於創建高性能、跨平台的移動應用。Flutter 針對當下以及未來的移動設備進行優化,專註於 Android and iOS 低延遲的輸入和高幀率。

Flutter 可以給開發者提供簡單、高效的方式來構建和部署跨平台、高性能移動應用;給用戶提供漂亮、快速、jitter-free 的 app 體驗。

Flutter 的主要組件:

  • 一個高度優化, mobile-first 2D 渲染引擎 (保護對 text 優秀的支持 )

  • 一個 functional-reactive 框架 (可選的,你也可以引入你自己的框架)

  • 一組 Material Design 部件 (可選的,你也可以引入你自己的部件)庫 ,工具,和一個用於 Atom 的插件。

6. .Net

.NET是 Microsoft XML Web services 平台。XML Web services 允許應用程序通過 Internet 進行通訊和共享數據,而不管所採用的是哪種操作系統、設備或編程語言。Microsoft .NET 平台提供創建 XML Web services 並將這些服務集成在一起之所需。對個人用戶的好處是無縫的、吸引人的體驗。

這個不用說了,很大一部分人一直在用,而且作為master語言。但是對於微服務程序,感覺更適合於前端應用或者一些輕量級企業級的開發。

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

【其他文章推薦】

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

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

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

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

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

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

Spring Boot入門系列(十五)Spring Boot 開發環境熱部署

在實際的項目開發過中,當我們修改了某個java類文件時,需要手動重新編譯、然後重新啟動程序的,整個過程比較麻煩,特別是項目啟動慢的時候,更是影響開發效率。其實Spring Boot的項目碰到這種情況,同樣也同樣需要經歷重新編譯、重新啟動程序的過程。 只不過 Spring Boot 提供了一個spring-boot-devtools的模塊,使得 Spring Boot應用支持熱部署,無需手動重啟Spring Boot應用,,提高開發者的開發效率。接下來,聊一聊Spring Boot 開發環境熱部署。

 

一、原理

devtools 使用了兩個類加載器(ClassLoader),一個是 Base類加載器(base classloader ):加載那些不會改變的類,如:第三方Jar包等,而另一個是 Restart類加載器(restart classloader):負責加載那些正在開發的會改變的類。這樣在有代碼更改的時候,因為重啟的時候只是加載了在開發的Class類,沒有重新加載第三方的jar包,所以實現了較快的重啟時間。

devtools 監聽classpath下的文件變動(發生在保存時機),並且會立即重啟應用。從而實現類文件和屬性文件的熱部署。

 

二、快速配置

1、pom配置

引入devtools的依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <!-- optional=true, 依賴不會傳遞, 該項目依賴devtools;之後依賴boot項目的項目如果想要使用devtools, 需要重新引入 -->
    <optional>true</optional>
</dependency>

注意:optional=true, 依賴不會傳遞, 該項目依賴devtools;之後依賴boot項目的項目如果想要使用devtools, 需要重新引入。

 

2、application.properties配置

在application.properties中配置devtools。

# 關閉緩存即時刷新
#spring.thymeleaf.cache=false

#熱部署生效
spring.devtools.restart.enabled=true
#設置重啟的目錄
spring.devtools.restart.additional-paths=src/main/java
#classpath目錄下的WEB-INF文件夾內容修改不重啟
spring.devtools.restart.exclude=WEB-INF/**

說明:

devtools可以實現頁面熱部署,即頁面修改後會立即生效,需要將application.properties文件中配置spring.thymeleaf.cache=false。

devtools會監聽classpath下的文件變動,並且會立即重啟應用。

 

3、IDEA配置

如果idea是新安裝的或者之前就沒有配置過,發現改變代碼項目熱部署不成功。當我們修改了Java類后,IDEA默認是不自動編譯的,而spring-boot-devtools又是監測classpath下的文件發生變化才會重啟應用。

所以需要設置IDEA的自動編譯:

(1)File-Settings-Compiler-Build Project automatically

(2)ctrl + shift + alt + /,選擇Registry,勾上 Compiler autoMake allow when app running 

這樣,就可以使用devtools實現熱部署了。

 

最後

以上,就把如何配置Spring Boot 開發環境熱部署介紹完了。還是比較簡單的,大家自己去研究吧。

 

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

【其他文章推薦】

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

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

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

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

※超省錢租車方案

※FB行銷專家,教你從零開始的技巧

大廠需求研發流程,進去前了解一波?

點贊再看,養成習慣,微信搜索【三太子敖丙】關注這個互聯網苟且偷生的程序員。

本文 GitHub https://github.com/JavaFamily 已收錄,有一線大廠面試完整考點和系列文章。

前言

我的讀者好像學生居多,然後大家最近問的比較多的一個話題就是大廠的研發流程,都比較好奇,整個流程是怎麼操作的。

我也不多BB了,那下面就跟隨暖男的腳步,走進大廠研發流程吧。

正文

我們先看看一個產品有哪些研發流程,帥丙就用自己接觸的阿里系的研發流程舉例了,這也基本上是互聯網大廠的研發流程了,可能細節有出入,但是絕對大同小異。

我問了下字節,多多,騰訊的朋友出入不大,所以還是具有代表性。

看完流程我們就一個個點的去看看每個環節幹了些啥,我們開發同學在這個環節需要做啥,以及在每個環節的職能。

需求提出:

這個環節主要是產品爸爸給我們提需求,每個需求都是他們從用戶,或者自己絞盡腦汁想出來的,但是產品爸爸還拿不準,不能直接敲定,所以就需要我們大家(產品,UI,前端,後端,客戶端和測試)一起討論一下,看看這個需求是否合理,或者這個需求是否有意義,能否達到預期,技術實現的成本,周期等等。

一旦聊成了,他們就會進入下一個階段,聊不成他會想方設法讓你答應,然後進入下個階段,知道我為啥叫產品爸爸了吧?

需求PRD提出:

這個階段,產品爸爸會根據第一版聊下來的結果,大致出一個Demo版本的PRD,會畫出初版的原型圖,並且配上文字說明,所有涉及到的業務,還有交互細節都會羅列出來。

大致就是下圖這樣:

這個時候大家又會圍繞這一版本去開會討論,敲定細節,這個環節會久點,因為細節比較認真,邏輯也不能出錯,還有UI稿子也得敲定,這裏如果不敲定邏輯,UI提前去畫原型圖,後面假如邏輯推翻,一切重來就會浪費大量時間。

這一環節大家都會把細節問清楚,不了解的點也會去了解,測試,開發,UI我們都會在會議上提出自己的觀點,自己的意見,然後等產品反饋,最後意見一致之後,產品當天就回改出敲定版本。

UI就會按照產品爸爸的意思去作圖,接下來就是交互設計評審了。

交互設計評審:

UI會畫出客戶端,前端,H5開發所需要的UI圖,基本上就是我們看到的產品的樣子了,不過還是要敲定細節,比如按鈕合理不,或者上面數據是否在這展示,或者這裏展示的數據是否合理。

這個環節會比較快,只要UI按照之前敲定的邏輯開發,出入不會很大,一般都是小改。

但是也不乏很多,之前敲定了情況,等UI按照敲定版本出了圖,但是卻發現出圖之後有些不合理的點,比如是否應該在這裏展示GMV(銷售總額),或者是否這樣展示活動規則啥的,會有這種情況,不過是小概率事件,改動也不會特別大。

UI界面:

大家看到的這種操作界面,按鈕,圖標的各種位置和圖案,都是UI在這個階段設計好的。(我什麼都沒暗示,不用關注我的B站)

大家敲定后就進入我們開發人員的回合了。

概要設計:

概要設計,這個是大廠程序員需求下來之後基本上都會做的一步,不過看需求大小,可能很多小需求直接就詳細設計了,也有啥設計都不用做的小改動,具體需求具體分析嘛。

很多不了解的同學可能會問,需要設計什麼呢?為什麼要設計呢?

問得好,經常看我文章的都知道,技術是把雙刃劍,你用了技術之後你是不是需要列出他的優點缺點,出問題之後的解決方案,還有可能出現的問題,注意點等等。

這麼是為了讓你能有把控力,比如你這個需求接入了新技術Es**(**Elasticsearch)你什麼都不管你就是要接入它,你把他開發好了上線了,但是有啥坑你知道么?上線崩了怎麼辦?

不主動,不拒絕,不負責,這是渣男的行徑,我們需要負起責任。

這個環節你需要考慮這個需求涉及到哪些服務了,需要新增哪些接口,修改哪些接口,表有現場的還是要新建表,字段要新建么?

其實遠遠不止這些問題,這就是我們做設計的主要原因,也是大家工作裏面能成長的途徑之一,你以為大佬們的經驗是怎麼來的?

推薦工具:Xmind/ProcessOn

  • Xmind官網地址: https://www.xmind.cn
  • ProcessOn
    在線作圖地址: https://www.processon.com

ProcessOn是我使用最頻繁的工具了,我身邊也有很多小夥伴在用,也推薦大家都使用:

大家在學習,看書等等的時候做個腦圖,後面學習和複習的時候思路會很清晰,而且效率瞬間高很多,形成知識體系。

概要設計一般就是做個大概,給大家看一下我自己在設計ES相關的需求的時候的概設,比較粗糙看個大概就好了:

這個設計好了,就需要給Leader看,看理解程度,一兩次返工是有可能的,如果你像或者像敖丙一樣笨的話,是有可能會被打回N次的,這裏我得提一下,好好做設計好處大大的有,自己體會。

然後會進行一輪測試用例評審,比如你涉及哪些服務,新增了哪些接口,改了哪些接口,都是要同步出來的,至於為啥?

是因為測試會依據這個數據,評估影響範圍,方便他寫測試用例,後面會提到。

詳細設計

小夥伴又要問了啥是詳細設計呀帥丙?

傻瓜,簡單呀,見名知意嘛,概要設計是大概的設計,詳細設計是詳細的設計。

我們研發的時候整個流程往往很複雜,如果你理解不對直接就寫代碼,最後容易造成返工,延期,加班,被罵,心情差,回家吵架,離家出走,露宿街頭,饑寒交迫,被迫吃野味,然後全國。。。。

看到不做詳細設計的後果了吧,其實大家花點時間做詳細設計很有必要,你思路完全清晰了,寫代碼那就是分分鐘的事情,不是嘛?

那再看看帥丙的一個小設計吧,之前文章中大量的流程圖,時序圖都來自它,主要是這玩意還是在線的,都不用下載很方便啊。

詳細設計的工具我用的就是之前提到的在線**作圖神器:**ProcessOn https://www.processon.com

還是我自己之前設計的一些流程圖,大家可以看看:

這個環節一樣重要,這個地方如果你能想好很多細節,開發的時候效率會高很多,像我上面的一些點,基本上就是看着圖開發了。

這個環節一般上不需要Leader參与,但是如果你有疑問或者不了解的點還是要提出來的。

測試用例評審:

上面我們說過,測試會根據你的概要設計,評估你的影響範圍,你的影響點,新增和改動的接口啥的,去編寫自己的測試用例。

測試用例,主要是為了把改動點影響點都考慮到,測全一點,免得上線了影響別的現有業務,也是為了把你開發的功能可能出現的bug給排除了。

我拿個小破站的小用例大家看看,這個比較粗糙但是也有點那味了。

這個環節也會開會討論,也是細節的確定,比如他寫的是否合理,或者有什麼點沒考慮到,大家有沒有補充的。

接口定義&開發&前後端聯調

這個環節其實比較好理解,啥都敲定了,那就開發唄,開發差不多了,就得前後端聯調了。

這裡有個小細節還是想說一下,一般開發前我們都會提前定義數據類型,接口名稱,然後在公司的接口工具上給出鏈接和參數,方便前端爸爸mock數據。

他總不能等我們後端開發完了,才去開發嘛,這樣效率打折扣,所以都是後端先定義好,然後前後端并行開發的。

後端開發好,一般都是會發布到聯調環境,我們有哪些環境,聯調環境在我們所有的環境中處於哪個地位呢?

大家可以看到我列出了我們開發的所有環境。

Tip:日常環境不能由開發人員發布,是因為測試流程比較久,所以不能中斷,如果你一直發布會影響測試的效率,在發布期間他們是沒辦法幹活的,而且很多部門涉及相同的服務,你發布還會影響別人。

測試發布之前,在測試群里問問可以發某個服務么,大家覺得不影響,那麼就可以發了,懂了吧。

預發環境,也叫灰度環境,這是跟線上數據一樣的一個環境,只是只能內網訪問,一般這一步是防止很多是因為日常的數據量不夠真實,數據級別達不到線上的量級無法測出的bug。

扯遠了,聯調完了就是代碼Review了。

代碼Review:

codeReview環節,畫一下重點,這可能是整個研發流程中,讓你成長最快的一個環節,讓組員和Leader Review你的代碼,往往他們能給你很多業務上和技術上的建議和意見。

過來人的經驗你就說香不香吧,以前老大經常沒時間,但是我就是煩着他要Review,後來他說不用review了,但是我還是要組員大佬review,因為我很享受別人對我提建議的時候,這不就是成長,掃盲的好時機嘛。

提測&灰度發布&產品第一次驗收

這一階段就是把代碼都發到日常環境,然後等測試爸爸測試,這個環節開發同學如果沒BUG是比較輕鬆的,等着就好了,可以看看丙丙的文章啊,看看丙丙的B站視頻什麼的。

但是如果你BUG多,那我覺得你可能會生不如死,因為有的bug真的找很久很久的,調用鏈路又長,特別是跨服務又涉及消息隊列,或者第三方的接口什麼的。

img

總之你也不知道會出現什麼bug,我看身邊的大神也只能用經驗避免常見的吭,孰能生巧吧。

發布計劃

敲黑板,這個確實是比較重要的環節,這個環節主要是開發同學和前端同學說好一個發布時間,然後制定一個發布計劃,為啥要發布計劃呢?

我們開發一個需求,可能涉及到N個服務,這些服務是有依賴關係的,那就需要打包,比如訂單系統,依賴人員系統。優惠券系統,也依賴人員系統,然後訂單系統還依賴優惠券系統,是不是有點亂了?

我們看圖:

打包和發布順序原則上是一樣的,從沒完全依賴的服務按照順序發布到最後一個服務。

生成環境上線:

這就是神聖而莊嚴的上線環節,一般在這個環節丙丙都是要洗手洗澡,然後才點下那個神聖的發布按鈕。

一般現在都是自動化發布,界面上點點就好了,記得丙丙大學發布都是進服務器一個個kill進程,替換jar包然後重啟。

現在都是分佈式的集群,這樣發無疑會累死,我之前負責的系統有50多台機器,一般都是4台4台發布。

日誌觀察&產品第二次驗收

一般發布第一批之後不會馬上發布第二批,而是觀察錯誤日誌,看看是否正常,有時候會發現還是會出現異常情況的,那就保留錯誤日誌,然後回滾。

知道解決了再發布,順利的話就沒啥錯誤,一口氣發完了,看了下時間凌晨了,那發完差不多也得回家了。

一次發布可能涉及服務多的話,真的有可能發布這麼久,但是沒辦法,線上出問題就是掉腦袋的事情。

日誌觀察一般公司都有錯誤日誌搜集系統,或者自己登錄跳板機查看就好了。

沒問題,發完之後告訴產品大大就好了。

需求結束

至此基本上一個需求可能就結束了,其實還是很不容易的,短的需求幾天,長的需求幾個月,中間塗塗改改,BUG,技術難點都是你要面對的,不過沒啥大問題,我們技術人嘛皮實能頂。

總結

產品研發流程大家是不是覺得有點複雜,或者覺得很多點有點小題大做了,不瞞你說,剛開始我也這麼認為的,但是隨着時間的推移,你會發現有時候越是這樣規範,越是提升了效率,也提升了產品質量。

對自己設計的嚴苛也會讓你的業務能力提升,開發考慮的點也越來越廣泛,我想大佬應該都是這樣走過去的,那沒啥好說的,我們也走。

最後給大家看看我自己搞的一個項目管理模板吧,基本上能適用大部分項目了,要xmind格式的公眾號回復【項目】即可。

相關資料

準備了很多學習資料給大家https://pan.baidu.com/s/1gM4Ea11ygHuMomT2VQ2aNQ

我是敖丙,一個在互聯網苟且偷生的程序員。

你知道的越多,你不知道的越多,人才們的 【三連】 就是丙丙創作的最大動力,我們下期見!

注:如果本篇博客有任何錯誤和建議,歡迎人才們留言!

文章持續更新,可以微信搜索「 三太子敖丙 」第一時間閱讀,回復【資料】有我準備的一線大廠面試資料和簡歷模板,本文 GitHub https://github.com/JavaFamily 已經收錄,有大廠面試完整考點,歡迎Star。

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

【其他文章推薦】

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

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

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

※超省錢租車方案

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

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

Project Loom:Reactive模型和協程進行時(翻譯)

Java 15將發布Project Loom的第一個版本。我相信這將改變JVM。在這篇文章中,我想深入探討一下導致我相信這一點的原因。

首先,我們需要了解核心問題。然後,我將嘗試描述以前的技術如何解決它。之後,我們將看到Project Loom採取的方法。最後,我將推斷後者可能對生態系統產生什麼影響。

Project Loom

我們首先必須記住,很長一段時間以來,計算機只有一個內核。即使這樣,還是需要同時運行多個程序:這至少要運行兩個操作系統和適當的程序。

為了實現并行性的幻覺,它依賴於一個技巧。它運行一個程序,如果該程序沒有在特定的時間範圍內完成,它將存儲其狀態以供以後使用。然後,它運行下一個要運行的程序。有幾種算法可用來調度下一個程序:循環調度,加權循環調度等。好處是,所有這些都可以通過操作系統線程的概念很好地從開發人員中抽象出來。該操作系統通吃繁重的護理,包括存儲執行的狀態。但是,線程有兩個缺點:

  • 線程很重,因為它帶有很多狀態
  • 線程需要大量的機器資源來創建
    在所有情況下,現代OS都允許M個線程,其中M是數千個線程。現代機器是多核的,提供N個核,比M少兩個數量級。擁有多個內核(無論是物理內核還是虛擬內核)並不會從根本上改變底層機制:M遠高於N,並且OS負責從線程到內核的映射。

阻塞線程

面的模型在傳統方案中效果很好,但在網絡方案中效果不佳。假設有一個Web服務器需要響應HTTP請求。在過去不太好的時候,CGI是處理請求的一種方法。它將每個請求映射到一個流程,以便處理創建整個新流程所需的請求,並在發送響應后將其清除。

Java EE應用程序服務器極大地改善了這種情況,因為實現將線程保留在池中以供以後重用。但是,想象一下響應的生成需要時間,例如因為它需要訪問數據庫以讀取數據。在數據庫返回數據之前,線程需要等待。

這意味着線程實際上正在等待其生命周期的大部分時間。一方面,此類線程自己不使用任何CPU。另一方面,它使用其他種類的資源,尤其是內存。

同樣,太多線程是操作系統的負擔:操作系統必須在數量有限的CPU內核上平衡大量線程。這花費了寶貴的CPU周期,因此,操作系統正在與應用程序競爭CPU。

現在,併發請求的數量可以遠遠超過服務器可用的線程數量。因此,阻塞的線程浪費資源,並使服務器無響應。為了解決這個問題,可以添加更多的Web服務器來處理負載:這是水平縮放。

在大多數情況下,水平縮放就足夠了。等待阻塞線程所花費的時間是浪費的,但是沒有任何相關的費用…除非一個人的基礎架構位於’雲’中。在那種情況下,人們要為未使用的資源付費:這絕不是一個明智的主意。

單線程,反應式和Kotlin協程模型

對於開發人員來說,管理多個線程很複雜。例如,如果您一直在使用(或開發)Swing應用程序,則可能知道“灰色矩形效果”。當用戶與窗口的交互(例如單擊)啟動長時間運行的任務時,就會發生這種情況。如果將另一個窗口移到Swing窗口上,然後再移出,Swing不會重畫另一個窗口與Swing窗口相交的區域,而不會留下難看的灰色矩形。原因是長時間運行的任務是在“ 事件調度線程”上啟動的,而不是在專用線程上啟動的。而且這很容易避免,甚至不涉及在共享的可變狀態上進行同步!

為了避免這種情況,某些堆棧完全禁止開發人員使用多個線程。例如,Node.js的API僅提供一個非阻塞事件循環線程:提交的函數採用回調的形式。請注意,這不會阻止實現使用多個線程。

該反應的方法是另一種選擇,其實頗為相似。儘管它擺脫了單線程API的限制,並提供了反壓力機制,但它仍然需要非阻塞代碼。由於OS線程很昂貴,因此Reactive將它們池化,並在整個應用程序生命周期中重複使用它們。核心過程是從池中獲取空閑線程,讓其執行代碼,然後將線程釋放回池中。這就是為什麼它需要非阻塞代碼的原因:如果代碼阻塞了,那麼執行線程將不會被釋放,並且池將在某一點或另一點耗盡。

我感興趣地觀察了Reactive模型如何像篝火一樣在Spring生態系統中傳播,儘管我選擇站在一邊。恕我直言,反應式有幾個缺點:

  • 編寫(和閱讀!)反應式代碼的思維方式與編寫傳統代碼的思維方式非常不同。我願意承認改變心態只需要時間,持續時間取決於每個開發人員。
  • 儘管真正的開發人員不會調試,但我知道很多人會調試-包括我自己。由於上述線程切換的魔力,要跟蹤一段代碼及其相關的狀態並不容易。這需要足夠的工具,例如帶有相關插件的 IntelliJ IDEA 。
  • 最後,出於相同的原因,傳統的堆棧跟蹤也無濟於事。一些黑魔法可以繞開它。但是,這不是為了膽小者。有關選項的完整列表,請查看此文檔。

Kotlin語言提供了Reactive方法的替代方法:協程。簡而言之,當使用suspend關鍵字時,Kotlin編譯器會在字節碼中生成一個有限狀態機。好處是在協程塊中調用的函數看起來像是順序執行的,儘管它們是并行執行的-更確切地說,取決於確切的範圍,有可能會執行。

Project Loom和虛擬線程

Reactive模型和Kotlin協程都在客戶端代碼和JVM線程之間添加了一個額外的抽象層。框架/庫的職責是動態地將一個映射到另一個。問題的癥結在於JVM線程是OS線程的薄包裝:請記住,OS線程創建起來很昂貴,並且數量限製為數千個。

Project Loom的目標是實際上將JVM線程與OS線程解耦。
當我第一次意識到該倡議時,其想法是創建一個稱為Fiber(線程,Project Loom,您能抓住麻煩嗎?)的抽象。一個Fiber責任是讓一個操作系統線程,使其運行代碼,釋放回池,就像無棧一樣。

當前的建議有很大的不同:Fiber它沒有使用新的類,而是重新使用了Java開發人員非常熟悉的一個類- java.lang.Thread!

因此,在新的JVM版本中,某些Thread對象可能是重量級的並映射到OS線程,而另一些對象可能是虛擬線程。

Project Loom發布的後續影響

主要問題是,既然JVM API提供了對OS線程的抽象,那麼其他抽象(例如響應式和協程)又會變成什麼樣呢?我對預測不滿意,但以下是Reactive /協程背後的公司可能採取的一些態度:

  • 正面態度,他們意識到自己的框架不再帶來任何附加值,而只是重複。他們停止了開發工作,僅向現有客戶提供維護版本。他們幫助說客戶遷移到新的ThreadAPI,一些幫助可能是以付費諮詢的形式。
  • 反面態度,他們在各自的框架中投入了大量的精力之後,他們決定繼續進行,好像什麼也沒有發生。例如,Spring框架負責實際設計一個共享的Reactive API,稱為Reactive Streams,沒有Spring依賴項。當前有兩種實現,RxJava v2和Pivotal的Project Reactor。另一方面,JetBrains宣傳Kotlin的協程是并行運行代碼的最簡單方法。
  • 中間態度。這兩個框架都將繼續其生命,但是會將它們各自的基礎實現更改為使用虛擬線程。
    由於沉沒成本的謬誤,排在第一位的可能性極小:銷售和市場營銷將努力保持其“競爭優勢”-無論在他們眼中意味着什麼。儘管有些工程師出於相同的原因希望保留現有代碼,但其他一些工程師則將努力使用新的API。因此,我也不相信第二名也會發生。但是,我認為這兩個工程派之間都發揮着力量,然後它們與市場營銷/銷售之間將在#3之間找到平衡。

結論

Project Looms將現有的Thread實現方式從OS線程的映射更改為可以表示此類線程或虛擬線程的抽象。就其本身而言,這是一個有趣的舉動,它在一個平台上歷來比創新更重視向後兼容性。與其他最新的Java版本相比,此功能是真正的遊戲規則改變者。一般而言,開發人員應儘快開始熟悉它。打算學習Reactive和協程的開發人員可能應該退後一步,並評估他們是否應該學習新的ThreadAPI- 是否需要。

翻譯原文

https://blog.frankel.ch/project-loom-reactive-coroutines/

擴展閱讀

Project Loom地址: https://github.com/openjdk/loom
Project Loom現有狀態: http://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html

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

【其他文章推薦】

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

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

※回頭車貨運收費標準

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

※超省錢租車方案

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

英研究稱城市臭氧污染與死亡風險增加相關

摘錄自2020年2月17日北京新浪網報導

倫敦大學衛生和熱帶醫學院最近發佈一項研究說,對全球數百個城市的調查發現,人們日常暴露在城市地面臭氧污染中與死亡風險增加有關。

來自該學院以及多個科研機構的國際團隊在最新一期《英國醫學雜誌》上發表文章報告稱,他們採集了1985年至2015年間來自20個國家和地區406個城市的4500多萬例死亡案例相關數據,並分析了這些城市的污染狀況及死亡風險間的關係後發現,城市地面臭氧水平平均每上升10微克/立方米,總體死亡風險就會增加0.18%。也就是說,如果這些城市執行了更嚴格的空氣排放標準,每年共可減少6000多人死亡。

但團隊也表示,這項研究是基於觀察性分析,因此無法直接確立因果關係,研究結果的準確性也受到一些因素的限制。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

研究:野火危機影響75%澳洲人 當局支持率暴跌

摘錄自2020年2月18日中央社報導

澳洲野火延燒5個月,據今天(18日)公布的最新調查,澳洲75%民眾、將近1800萬人自認受到這波致命野火危機影響。調查也顯示,野火這一燒,同時燒掉了政府和煤炭計畫的支持率。

法新社報導,澳洲國立大學(Australian National University)社會研究主筆畢德爾(Nicholas Biddle)表示:「這場火災幾乎影響到每個澳洲民眾,這將會影響我們許多人好幾年。」

這項訪問3000人的調查指出,14%成人受到直接影響,他們的房屋沒了或受損,或是全家被迫撤離。

除了近300萬人直接受衝擊,更有1500萬名澳洲人受到間接影響,包括受野火煙霧影響或度假計畫泡湯。

上次大選支持政府的受訪者中,支持新建煤礦場的比例從野火危機前的72%跌到1月的57%。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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