詳解Kafka Producer

上一篇文章我們主要介紹了什麼是 Kafka,Kafka 的基本概念是什麼,Kafka 單機和集群版的搭建,以及對基本的配置文件進行了大致的介紹,還對 Kafka 的幾個主要角色進行了描述,我們知道,不管是把 Kafka 用作消息隊列、消息總線還是數據存儲平台來使用,最終是繞不過消息這個詞的,這也是 Kafka 最最核心的內容,Kafka 的消息從哪裡來?到哪裡去?都干什麼了?別著急,一步一步來,先說說 Kafka 的消息從哪來。

生產者概述

在 Kafka 中,我們把產生消息的那一方稱為生產者,比如我們經常回去淘寶購物,你打開淘寶的那一刻,你的登陸信息,登陸次數都會作為消息傳輸到 Kafka 後台,當你瀏覽購物的時候,你的瀏覽信息,你的搜索指數,你的購物愛好都會作為一個個消息傳遞給 Kafka 後台,然後淘寶會根據你的愛好做智能推薦,致使你的錢包從來都禁不住誘惑,那麼這些生產者產生的消息是怎麼傳到 Kafka 應用程序的呢?發送過程是怎麼樣的呢?

儘管消息的產生非常簡單,但是消息的發送過程還是比較複雜的,如圖

我們從創建一個ProducerRecord 對象開始,ProducerRecord 是 Kafka 中的一個核心類,它代表了一組 Kafka 需要發送的 key/value 鍵值對,它由記錄要發送到的主題名稱(Topic Name),可選的分區號(Partition Number)以及可選的鍵值對構成。

在發送 ProducerRecord 時,我們需要將鍵值對對象由序列化器轉換為字節數組,這樣它們才能夠在網絡上傳輸。然後消息到達了分區器。

如果發送過程中指定了有效的分區號,那麼在發送記錄時將使用該分區。如果發送過程中未指定分區,則將使用key 的 hash 函數映射指定一個分區。如果發送的過程中既沒有分區號也沒有,則將以循環的方式分配一個分區。選好分區后,生產者就知道向哪個主題和分區發送數據了。

ProducerRecord 還有關聯的時間戳,如果用戶沒有提供時間戳,那麼生產者將會在記錄中使用當前的時間作為時間戳。Kafka 最終使用的時間戳取決於 topic 主題配置的時間戳類型。

  • 如果將主題配置為使用 CreateTime,則生產者記錄中的時間戳將由 broker 使用。
  • 如果將主題配置為使用LogAppendTime,則生產者記錄中的時間戳在將消息添加到其日誌中時,將由 broker 重寫。

然後,這條消息被存放在一個記錄批次里,這個批次里的所有消息會被發送到相同的主題和分區上。由一個獨立的線程負責把它們發到 Kafka Broker 上。

Kafka Broker 在收到消息時會返回一個響應,如果寫入成功,會返回一個 RecordMetaData 對象,它包含了主題和分區信息,以及記錄在分區里的偏移量,上面兩種的時間戳類型也會返回給用戶。如果寫入失敗,會返回一個錯誤。生產者在收到錯誤之後會嘗試重新發送消息,幾次之後如果還是失敗的話,就返回錯誤消息。

創建 Kafka 生產者

要往 Kafka 寫入消息,首先需要創建一個生產者對象,並設置一些屬性。Kafka 生產者有3個必選的屬性

  • bootstrap.servers

該屬性指定 broker 的地址清單,地址的格式為 host:port。清單里不需要包含所有的 broker 地址,生產者會從給定的 broker 里查找到其他的 broker 信息。不過建議至少要提供兩個 broker 信息,一旦其中一個宕機,生產者仍然能夠連接到集群上。

  • key.serializer

broker 需要接收到序列化之後的 key/value值,所以生產者發送的消息需要經過序列化之後才傳遞給 Kafka Broker。生產者需要知道採用何種方式把 Java 對象轉換為字節數組。key.serializer 必須被設置為一個實現了org.apache.kafka.common.serialization.Serializer 接口的類,生產者會使用這個類把鍵對象序列化為字節數組。這裏拓展一下 Serializer 類

Serializer 是一個接口,它表示類將會採用何種方式序列化,它的作用是把對象轉換為字節,實現了 Serializer 接口的類主要有 ByteArraySerializerStringSerializerIntegerSerializer ,其中 ByteArraySerialize 是 Kafka 默認使用的序列化器,其他的序列化器還有很多,你可以通過 查看其他序列化器。要注意的一點:key.serializer 是必須要設置的,即使你打算只發送值的內容

  • value.serializer

與 key.serializer 一樣,value.serializer 指定的類會將值序列化。

下面代碼演示了如何創建一個 Kafka 生產者,這裏只指定了必要的屬性,其他使用默認的配置

private Properties properties = new Properties();
properties.put("bootstrap.servers","broker1:9092,broker2:9092");
properties.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
properties.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
properties = new KafkaProducer<String,String>(properties);

來解釋一下這段代碼

  • 首先創建了一個 Properties 對象
  • 使用 StringSerializer 序列化器序列化 key / value 鍵值對
  • 在這裏我們創建了一個新的生產者對象,併為鍵值設置了恰當的類型,然後把 Properties 對象傳遞給他。

實例化生產者對象后,接下來就可以開始發送消息了,發送消息主要由下面幾種方式

直接發送,不考慮結果

使用這種發送方式,不會關心消息是否到達,會丟失一些消息,因為 Kafka 是高可用的,生產者會自動嘗試重發,這種發送方式和 UDP 運輸層協議很相似。

同步發送

同步發送仍然使用 send() 方法發送消息,它會返回一個 Future 對象,調用 get() 方法進行等待,就可以知道消息時候否發送成功。

異步發送

異步發送指的是我們調用 send() 方法,並制定一個回調函數,服務器在返迴響應時調用該函數。

下一節我們會重新討論這三種實現。

向 Kafka 發送消息

簡單消息發送

Kafka 最簡單的消息發送如下:

ProducerRecord<String,String> record =
                new ProducerRecord<String, String>("CustomerCountry","West","France");

producer.send(record);

代碼中生產者(producer)的 send() 方法需要把 ProducerRecord 的對象作為參數進行發送,ProducerRecord 有很多構造函數,這個我們下面討論,這裏調用的是

public ProducerRecord(String topic, K key, V value) {}

這個構造函數,需要傳遞的是 topic主題,key 和 value。

把對應的參數傳遞完成后,生產者調用 send() 方法發送消息(ProducerRecord對象)。我們可以從生產者的架構圖中看出,消息是先被寫入分區中的緩衝區中,然後分批次發送給 Kafka Broker。

發送成功后,send() 方法會返回一個 Future(java.util.concurrent) 對象,Future 對象的類型是 RecordMetadata 類型,我們上面這段代碼沒有考慮返回值,所以沒有生成對應的 Future 對象,所以沒有辦法知道消息是否發送成功。如果不是很重要的信息或者對結果不會產生影響的信息,可以使用這種方式進行發送。

我們可以忽略發送消息時可能發生的錯誤或者在服務器端可能發生的錯誤,但在消息發送之前,生產者還可能發生其他的異常。這些異常有可能是 SerializationException(序列化失敗)BufferedExhaustedException 或 TimeoutException(說明緩衝區已滿),又或是 InterruptedException(說明發送線程被中斷)

同步發送消息

第二種消息發送機制如下所示

ProducerRecord<String,String> record =
                new ProducerRecord<String, String>("CustomerCountry","West","France");

try{
  RecordMetadata recordMetadata = producer.send(record).get();
}catch(Exception e){
  e.printStackTrace();
}

這種發送消息的方式較上面的發送方式有了改進,首先調用 send() 方法,然後再調用 get() 方法等待 Kafka 響應。如果服務器返回錯誤,get() 方法會拋出異常,如果沒有發生錯誤,我們會得到 RecordMetadata 對象,可以用它來查看消息記錄。

生產者(KafkaProducer)在發送的過程中會出現兩類錯誤:其中一類是重試錯誤,這類錯誤可以通過重發消息來解決。比如連接的錯誤,可以通過再次建立連接來解決;無錯誤則可以通過重新為分區選舉首領來解決。KafkaProducer 被配置為自動重試,如果多次重試后仍無法解決問題,則會拋出重試異常。另一類錯誤是無法通過重試來解決的,比如消息過大對於這類錯誤,KafkaProducer 不會進行重試,直接拋出異常。

異步發送消息

同步發送消息都有個問題,那就是同一時間只能有一個消息在發送,這會造成許多消息無法直接發送,造成消息滯后,無法發揮效益最大化。

比如消息在應用程序和 Kafka 集群之間一個來回需要 10ms。如果發送完每個消息后都等待響應的話,那麼發送100個消息需要 1 秒,但是如果是異步方式的話,發送 100 條消息所需要的時間就會少很多很多。大多數時候,雖然Kafka 會返回 RecordMetadata 消息,但是我們並不需要等待響應。

為了在異步發送消息的同時能夠對異常情況進行處理,生產者提供了回掉支持。下面是回調的一個例子

ProducerRecord<String, String> producerRecord = new ProducerRecord<String, String>("CustomerCountry", "Huston", "America");
        producer.send(producerRecord,new DemoProducerCallBack());


class DemoProducerCallBack implements Callback {

  public void onCompletion(RecordMetadata metadata, Exception exception) {
    if(exception != null){
      exception.printStackTrace();;
    }
  }
}

首先實現回調需要定義一個實現了org.apache.kafka.clients.producer.Callback的類,這個接口只有一個 onCompletion方法。如果 kafka 返回一個錯誤,onCompletion 方法會拋出一個非空(non null)異常,這裏我們只是簡單的把它打印出來,如果是生產環境需要更詳細的處理,然後在 send() 方法發送的時候傳遞一個 Callback 回調的對象。

生產者分區機制

Kafka 對於數據的讀寫是以分區為粒度的,分區可以分佈在多個主機(Broker)中,這樣每個節點能夠實現獨立的數據寫入和讀取,並且能夠通過增加新的節點來增加 Kafka 集群的吞吐量,通過分區部署在多個 Broker 來實現負載均衡的效果。

上面我們介紹了生產者的發送方式有三種:不管結果如何直接發送發送並返回結果發送並回調。由於消息是存在主題(topic)的分區(partition)中的,所以當 Producer 生產者發送產生一條消息發給 topic 的時候,你如何判斷這條消息會存在哪個分區中呢?

這其實就設計到 Kafka 的分區機制了。

分區策略

Kafka 的分區策略指的就是將生產者發送到哪個分區的算法。Kafka 為我們提供了默認的分區策略,同時它也支持你自定義分區策略。

如果要自定義分區策略的話,你需要显示配置生產者端的參數 Partitioner.class,我們可以看一下這個類它位於 org.apache.kafka.clients.producer 包下

public interface Partitioner extends Configurable, Closeable {
  
  public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);

  public void close();
  
  default public void onNewBatch(String topic, Cluster cluster, int prevPartition) {}
}

Partitioner 類有三個方法,分別來解釋一下

  • partition(): 這個類有幾個參數: topic,表示需要傳遞的主題;key 表示消息中的鍵值;keyBytes表示分區中序列化過後的key,byte數組的形式傳遞;value 表示消息的 value 值;valueBytes 表示分區中序列化后的值數組;cluster表示當前集群的原數據。Kafka 給你這麼多信息,就是希望讓你能夠充分地利用這些信息對消息進行分區,計算出它要被發送到哪個分區中。
  • close() : 繼承了 Closeable 接口能夠實現 close() 方法,在分區關閉時調用。
  • onNewBatch(): 表示通知分區程序用來創建新的批次

其中與分區策略息息相關的就是 partition() 方法了,分區策略有下面這幾種

順序輪訓

順序分配,消息是均勻的分配給每個 partition,即每個分區存儲一次消息。就像下面這樣

上圖表示的就是輪訓策略,輪訓策略是 Kafka Producer 提供的默認策略,如果你不使用指定的輪訓策略的話,Kafka 默認會使用順序輪訓策略的方式。

隨機輪訓

隨機輪訓簡而言之就是隨機的向 partition 中保存消息,如下圖所示

實現隨機分配的代碼只需要兩行,如下

List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
return ThreadLocalRandom.current().nextInt(partitions.size());

先計算出該主題總的分區數,然後隨機地返回一個小於它的正整數。

本質上看隨機策略也是力求將數據均勻地打散到各個分區,但從實際表現來看,它要遜於輪詢策略,所以如果追求數據的均勻分佈,還是使用輪詢策略比較好。事實上,隨機策略是老版本生產者使用的分區策略,在新版本中已經改為輪詢了。

按照 key 進行消息保存

這個策略也叫做 key-ordering 策略,Kafka 中每條消息都會有自己的key,一旦消息被定義了 Key,那麼你就可以保證同一個 Key 的所有消息都進入到相同的分區裏面,由於每個分區下的消息處理都是有順序的,故這個策略被稱為按消息鍵保序策略,如下圖所示

實現這個策略的 partition 方法同樣簡單,只需要下面兩行代碼即可:

List<PartitionInfo> partitions = cluster.partitionsForTopic(topic);
return Math.abs(key.hashCode()) % partitions.size();

上面這幾種分區策略都是比較基礎的策略,除此之外,你還可以自定義分區策略。

生產者壓縮機制

壓縮一詞簡單來講就是一種互換思想,它是一種經典的用 CPU 時間去換磁盤空間或者 I/O 傳輸量的思想,希望以較小的 CPU 開銷帶來更少的磁盤佔用或更少的網絡 I/O 傳輸。如果你還不了解的話我希望你先讀完這篇文章 ,然後你就明白壓縮是怎麼回事了。

Kafka 壓縮是什麼

Kafka 的消息分為兩層:消息集合 和 消息。一個消息集合中包含若干條日誌項,而日誌項才是真正封裝消息的地方。Kafka 底層的消息日誌由一系列消息集合日誌項組成。Kafka 通常不會直接操作具體的一條條消息,它總是在消息集合這個層面上進行寫入操作。

在 Kafka 中,壓縮會發生在兩個地方:Kafka Producer 和 Kafka Consumer,為什麼啟用壓縮?說白了就是消息太大,需要變小一點 來使消息發的更快一些。

Kafka Producer 中使用 compression.type 來開啟壓縮

private Properties properties = new Properties();
properties.put("bootstrap.servers","192.168.1.9:9092");
properties.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
properties.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
properties.put("compression.type", "gzip");

Producer<String,String> producer = new KafkaProducer<String, String>(properties);

ProducerRecord<String,String> record =
  new ProducerRecord<String, String>("CustomerCountry","Precision Products","France");

上面代碼錶明該 Producer 的壓縮算法使用的是 GZIP

有壓縮必有解壓縮,Producer 使用壓縮算法壓縮消息后併發送給服務器后,由 Consumer 消費者進行解壓縮,因為採用的何種壓縮算法是隨着 key、value 一起發送過去的,所以消費者知道採用何種壓縮算法。

Kafka 重要參數配置

在上一篇文章 中,我們主要介紹了一下 kafka 集群搭建的參數,本篇文章我們來介紹一下 Kafka 生產者重要的配置,生產者有很多可配置的參數,在文檔里(

key.serializer

用於 key 鍵的序列化,它實現了 org.apache.kafka.common.serialization.Serializer 接口

value.serializer

用於 value 值的序列化,實現了 org.apache.kafka.common.serialization.Serializer 接口

acks

acks 參數指定了要有多少個分區副本接收消息,生產者才認為消息是寫入成功的。此參數對消息丟失的影響較大

  • 如果 acks = 0,就表示生產者也不知道自己產生的消息是否被服務器接收了,它才知道它寫成功了。如果發送的途中產生了錯誤,生產者也不知道,它也比較懵逼,因為沒有返回任何消息。這就類似於 UDP 的運輸層協議,只管發,服務器接受不接受它也不關心。
  • 如果 acks = 1,只要集群的 Leader 接收到消息,就會給生產者返回一條消息,告訴它寫入成功。如果發送途中造成了網絡異常或者 Leader 還沒選舉出來等其他情況導致消息寫入失敗,生產者會受到錯誤消息,這時候生產者往往會再次重發數據。因為消息的發送也分為 同步異步,Kafka 為了保證消息的高效傳輸會決定是同步發送還是異步發送。如果讓客戶端等待服務器的響應(通過調用 Future 中的 get() 方法),顯然會增加延遲,如果客戶端使用回調,就會解決這個問題。
  • 如果 acks = all,這種情況下是只有當所有參与複製的節點都收到消息時,生產者才會接收到一個來自服務器的消息。不過,它的延遲比 acks =1 時更高,因為我們要等待不只一個服務器節點接收消息。

buffer.memory

此參數用來設置生產者內存緩衝區的大小,生產者用它緩衝要發送到服務器的消息。如果應用程序發送消息的速度超過發送到服務器的速度,會導致生產者空間不足。這個時候,send() 方法調用要麼被阻塞,要麼拋出異常,具體取決於 block.on.buffer.null 參數的設置。

compression.type

此參數來表示生產者啟用何種壓縮算法,默認情況下,消息發送時不會被壓縮。該參數可以設置為 snappy、gzip 和 lz4,它指定了消息發送給 broker 之前使用哪一種壓縮算法進行壓縮。下面是各壓縮算法的對比

retries

生產者從服務器收到的錯誤有可能是臨時性的錯誤(比如分區找不到首領),在這種情況下,reteis 參數的值決定了生產者可以重發的消息次數,如果達到這個次數,生產者會放棄重試並返回錯誤。默認情況下,生產者在每次重試之間等待 100ms,這個等待參數可以通過 retry.backoff.ms 進行修改。

batch.size

當有多個消息需要被發送到同一個分區時,生產者會把它們放在同一個批次里。該參數指定了一個批次可以使用的內存大小,按照字節數計算。當批次被填滿,批次里的所有消息會被發送出去。不過生產者井不一定都會等到批次被填滿才發送,任意條數的消息都可能被發送。

client.id

此參數可以是任意的字符串,服務器會用它來識別消息的來源,一般配置在日誌里

max.in.flight.requests.per.connection

此參數指定了生產者在收到服務器響應之前可以發送多少消息,它的值越高,就會佔用越多的內存,不過也會提高吞吐量。把它設為1 可以保證消息是按照發送的順序寫入服務器。

timeout.ms、request.timeout.ms 和 metadata.fetch.timeout.ms

request.timeout.ms 指定了生產者在發送數據時等待服務器返回的響應時間,metadata.fetch.timeout.ms 指定了生產者在獲取元數據(比如目標分區的首領是誰)時等待服務器返迴響應的時間。如果等待時間超時,生產者要麼重試發送數據,要麼返回一個錯誤。timeout.ms 指定了 broker 等待同步副本返回消息確認的時間,與 asks 的配置相匹配—-如果在指定時間內沒有收到同步副本的確認,那麼 broker 就會返回一個錯誤。

max.block.ms

此參數指定了在調用 send() 方法或使用 partitionFor() 方法獲取元數據時生產者的阻塞時間當生產者的發送緩衝區已捕,或者沒有可用的元數據時,這些方法就會阻塞。在阻塞時間達到 max.block.ms 時,生產者會拋出超時異常。

max.request.size

該參數用於控制生產者發送的請求大小。它可以指能發送的單個消息的最大值,也可以指單個請求里所有消息的總大小。

receive.buffer.bytes 和 send.buffer.bytes

Kafka 是基於 TCP 實現的,為了保證可靠的消息傳輸,這兩個參數分別指定了 TCP Socket 接收和發送數據包的緩衝區的大小。如果它們被設置為 -1,就使用操作系統的默認值。如果生產者或消費者與 broker 處於不同的數據中心,那麼可以適當增大這些值。

文章參考:

《Kafka 權威指南》

極客時間 -《Kafka 核心技術與實戰》

Kafka 源碼

關注公眾號獲取更多優質电子書,關注一下你就知道資源是有多好了

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

【其他文章推薦】

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

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

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

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

採礦業進駐 污染環境 阿根廷紅酒區爆水資源戰

摘錄自2019年12月25日明報報導

拉丁美洲最大葡萄酒產區、阿根廷門多薩省(Mendoza)爆發當地史上最大規模的示威,抗議省政府為擴大財源,修訂《水資源保護法》,容許使用大量水資源的採礦業進駐當地,並可在開採過程中使用氰化物和硫酸等有害物質,恐令當地水源受污染,並加劇旱情,損害葡萄種植戶、酒廠等的生計。

《水資源保護法》於2007年制定,限制省內的採礦過程中使用危險化學品,並禁止大量用水的採擴項目,以免影響環境。惟門多薩省議會上周五(20日)以大比數通過修例,批准省內的採礦活動使用氰化物、硫酸及其他有害化學物質。

省長蘇亞雷斯周日(22日)宣布已有19個開採鈾、銅、金、鉛、銀、鋅、鐵礦項目等待議會批准,進一步激起民憤。

省環境部長明戈蘭塞聲稱水資源不會因新政策受損,也不會對環境構成任何負面影響,強調環保糾察將規管省內每一個採礦項目對環境的影響,且將在礦場所在地辦公開聽證會。阿根廷新任總統費爾南德斯(Alberto Fernandez)表示支持礦業項目,認為對阿根廷從長期的經濟困境中復蘇至關重要。

千計群眾周一(23日)再次遊行到省府門多薩市的省長辦公室外抗議,高叫「別動水源」和修例違憲等。這場門多薩省史上最大型示威演變成警民衝突。憤怒的示威者向現場防暴警員擲石,遭警方動用橡膠子彈與催淚彈驅散。

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

【其他文章推薦】

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

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

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

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

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

日塑膠袋全面收費 趕東奧前2020年7月上路

摘錄自2019年12月25日中央社報導

日本有意推動全國零售店實施購物塑膠袋收費政策,原本訂明年4月上路,但因為宣導期及零售業準備時間不足,延後到明年7月實施,正好趕在東京奧運開幕前上路。

日本經濟新聞報導,日本經濟產業省與環境省今天(25日)公布塑膠袋全面收費制度的政策方針,將以超市、便利商店等所有零售店為對象,並在年底前完成修正容器包裝回收法的行政命令。這項政策目的是從日常生活中的塑膠袋全面收費,促使消費者意識到減塑重要性。

不過,如果塑膠袋是用對環境負擔較小的植物原料製作,就不用收費。

至於塑膠袋單價交由業者自行定價,在中央政府提出的政策方針中,介紹了已上路實施的收費案例,大多是一個塑膠袋收2日圓到5日圓,但不能低於一日圓,否則就不算收費。

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

【其他文章推薦】

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

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

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

「巴逢」平安夜登陸菲律賓 至少1死6失蹤

摘錄自2019年12月26日公視報導

昨(25日)耶誕節,台灣各地都有25度以上,度過一個溫暖的耶誕。鄰國菲律賓卻碰上罕見的冬颱攪局,颱風巴逢在平安夜這天登陸菲律賓中部,讓當地大批人民度過溼答答又驚恐的節日,還造成至少一人死亡、六人失蹤。

強風伴隨著大雨,巴逢颱風在平安夜登陸菲律賓中部,街道上水淹及膝,路上車輛和行人勉強涉水而過。耶誕佳節碰到罕見的冬颱攪局,風強雨大,瞬間最大陣風來到時速195公里,強勁的風勢把民宅鐵皮屋頂掀飛,飼養的牛隻也無法倖免於難。

維修人員冒險爬上傾斜的電線桿,希望能盡快恢復供電。菲律賓當局指出,有超過1萬6千人被迫在避難所度過平安夜,還有2萬5千多人無法搭上渡輪回家團圓。菲律賓中部各地,累積雨量普遍超過100毫米,部份地區甚至多達200多毫米。根據美國有線電視新聞網CNN報導,巴逢颱風至少造成一人死亡,還有六人被大水沖走,下落不明。

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

【其他文章推薦】

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

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

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

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

通用汽車與 Lyft 合作,無人計程車上路測試

未來一年內,通用汽車(General Motors,GM)將與 Lyft 合作,在一般道路上測試無人駕駛的最新款電動車  Chevrolet Bolt,並計畫以此車款成為叫車服務的車隊主力。通用汽車近期正試圖整合幾筆投資,以迎接矽谷科技巨頭對傳統汽車行業的挑戰,包含 Tesla 的電動車、Google 的自動駕駛以及 Uber 的分享出租服務。   根據《華爾街日報》報導,今年 1 月通用汽車曾投資 Lyft 高達 5 億美元,並以 10 億美元價格收購了位於舊金山的自動駕駛技術開發商 Cruise Automation,預期接下來的服務將仰賴該公司技術。   通用汽車與 Lyft 的合作主要針對 Google 和 Uber 而來。Google 的自動駕駛汽車技術目前遙遙領先,即便與福特汽車合作告吹,他們也順利另外和飛雅特─克萊斯勒(Fiat Chrysler)成功聯手。而作為 Lyft 難以撼動的競爭對手,Uber 也在匹茲堡成立了無人駕駛研究中心,並計劃於 2020 年將無人駕駛車投入車隊營運。   Lyft 高層表示,關於無人計程車測試的細節仍在研究當中,不過這一項測試將在某些城市供用戶參與。Lyft 目前擁有一款原型的智慧型手機應用,用戶藉此透過 Lyft 叫車,可以選擇是否由無人駕駛車前來接送。在發生問題時,用戶也可以聯繫通用汽車 OnStar 系統助理請求協助。這款應用還支援讓用戶指示車輛何時出發,以及車輛是否已達到目的地可以離開。   目前有加州、密西根州、內華達州、佛羅里達州與華盛頓特區等地通過無人駕駛車上路測試的相關法案,Google 則已經在這些地區以外的其他城市,包含奧斯汀、鳳凰城與華盛頓州的柯克蘭進行他們的自動駕駛車測試。這也意味著通用汽車和 Lyft 同樣可以選擇在某些立法未詳的州以實行他們的計畫。Lyft 和 Uber 高層之前都曾表示,無人駕駛車的主要障礙來自於監管法規如何適用於這類車輛,以及責任歸屬如何界定。為了解決監管問題,Lyft 最初仍會在無人駕駛車上配備司機,以在必要情況下進行人工介入。   除了無人駕駛車外,通用汽車最重要的如意算盤,就是讓 Lyft 及其司機團隊成為 Chevrolet Bolt 的主要客戶。這款電動車將於 2016 年底上市。目前通用汽車和 Lyft 在芝加哥將 Chevrolet Equinox 租給有需要的司機駕駛,而未來的主力車型將會是 Bolt,而不是作為 SUV 的 Equinox。   Bolt 比上一款 Chevrolet Volt 能儲存更多電力,續航力更強;電池位於車身底盤,因此車輛前半部多出了空間,讓後排乘客的腿部空間更大。通用汽車表示,這款車型非常適合需要更多空間,同時希望降低運營成本的司機。

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

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

【其他文章推薦】

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

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

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

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

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

中國電動車達規模前 特斯拉不會本地建廠

據《中國日報》報導,特斯拉的一位高管稱公司不會在中國建廠,除非電動轎車的銷量達到”關鍵量產”規模。

特斯拉聯合創始人和首席技術官J.B. Straubel對可能在中國建廠的猜測潑了冷水,因為此前有特斯拉高管稱可能在中國生產特斯拉Model 3車型。

Straubel是在德國雷茲格的國際運輸論壇上接受《中國日報》採訪時,給出上述言論的。

只有美國市場的特斯拉3預訂單超過中國,但IHS汽車供應商新聞報導稱,特斯拉擱置了在中國建設總裝廠的計畫,因為沒有合適的合資夥伴。

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

【其他文章推薦】

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

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

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

廣汽將與樂視聯手打造互聯網生態圈

6月6日晚間,廣汽集團正式發佈公告稱,公司董事會審議並通過了《關於調整廣汽集團汽車互聯網生態圈專案的議案》。公告正式公佈了廣汽集團汽車互聯網生態圈專案將由廣州汽車集團股份有限公司、樂視控股(北京)有限公司及眾誠汽車保險股份有限公司共同出資,三方股比分別為45%、40%和15%。

事實上,早在公告發佈之前,樂視與廣汽就各自在汽車電商方面有著完整的規劃與佈局。在不久之前的北京車展上,樂視超級汽車聯合創始人,全球副董事長丁磊就曾透露,樂視將於近期與國內一家一流汽車集團開展汽車電商方面的合作,探索全新的生態電商模式。而樂視生態O2O高級副總裁、樂視商城負責人趙一成也在發佈會上表示,樂視商城將進軍汽車領域,打造全球首家生態型O2O汽車電商。

廣汽集團在2015年7月已經宣佈將啟動汽車互聯網生態圈專案的實施,建設包括整車電商平臺、車生活平臺、車聯網平臺和創業投融資平臺等四個平臺。

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

【其他文章推薦】

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

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

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

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

Flink中異步AsyncIO的實現 (源碼分析)

先上張圖整體了解Flink中的異步io

 

阿里貢獻給flink的,優點就不說了嘛,官網上都有,就是寫庫不會柱塞性能更好

然後來看一下, Flink 中異步io主要分為兩種

  一種是有序Ordered

  一種是無序UNordered

主要區別是往下游output的順序(注意這裏順序不是寫庫的順序既然都異步了寫庫的順序自然是無法保證的),有序的會按接收的順序繼續往下游output發送,無序就是誰先處理完誰就先往下游發送

兩張圖了解這兩種模式的實現

 

有序:record數據會通過異步線程寫庫,Emitter是一個守護進程,會不停的拉取queue頭部的數據,如果頭部的數據異步寫庫完成,Emitter將頭數據往下游發送,如果頭元素還沒有異步寫庫完成,柱塞      

無序:record數據會通過異步線程寫庫,這裡有兩個queue,一開始放在uncompleteedQueue,當哪個record異步寫庫成功后就直接放到completedQueue中,Emitter是一個守護進程,completedQueue只要有數據,會不停的拉取queue數據往下游發送 

    

可以看到原理還是很簡單的,兩句話就總結完了,就是利用queue和java的異步線程,現在來看下源碼

這裏AsyncIO在Flink中被設計成operator中的一種,自然去OneInputStreamOperator的實現類中去找

於是來看一下AsyncWaitOperator.java

  

看到它的open方法(open方法會在taskmanager啟動job的時候全部統一調用,可以翻一下以前的文章)

這裏啟動了一個守護線程Emitter,來看下線程具體做了什麼

 

 1處拉取數據,2處就是常規的將拉取到的數據往下游emit,Emitter拉取數據,這裏先不講因為分為有序的和無序的

 這裏已經知道了這個Emitter的作用是循環的拉取數據往下游發送

 回到AsyncWaitOperator.java在它的open方法初始化了Emitter,那它是如何處理接收到的數據的呢,看它的ProcessElement()方法

 

    

 

 其實主要就是三個個方法

先是!!!將record封裝成了一個包裝類StreamRecordQueueEntry,主要是這個包裝類的構造方法中,創建了一個CompleteableFuture(這個的complete方法其實會等到用戶代碼執行的時候用戶自己決定什麼時候完成)

1處主要就是講元素加入到了對應的queue,這裏也分為兩種有序和無序的

 

這裏也先不講這兩種模式加入數據的區別

接着2處就是調用用戶的代碼了,來看看官網的異步io的例子

 

 給了一個Future作為參數,用戶自己起了一個線程(這裏思考一下就知道了為什麼要新起一個異步線程去執行,因為如果不起線程的話,那processElement方法就柱塞了,無法異步了)去寫庫讀庫等,然後調用了這個參數的complete方法(也就是前面那個包裝類中的CompleteableFuture)並且傳入了一個結果

看下complete方法源碼

 

 這個resultFuture是每個record的包裝類StreamRecordQueueEntry的其中一個屬性是一個CompletableFuture

 那現在就清楚了,用戶代碼在自己新起的線程中當自己的邏輯執行完以後會使這個異步線程結束,並輸入一個結果

 那這個幹嘛用的呢

 

最開始的圖中看到有序和無序實現原理,有序用一個queue,無序用兩個queue分別就對應了

OrderedStreamElementQueue類中

 

 UnorderedStreamElementQueue類中

 

回到前面有兩個地方沒有細講,一是兩種模式的Emitter是如何拉取數據的,二是兩種模式下數據是如何加入OrderedStreamElementQueue的

有序模式:

1.先來看一下有序模式的,Emitter的數據拉取,和數據的加入

    其tryPut()方法

      

      

     onComplete方法

       

       onCompleteHandler方法

        

  這裏比較繞,先將接收的數據加入queue中,然後onComplete()中當上一個異步線程getFuture() 其實就是每個元素包裝類裏面的那個CompletableFuture,當他結束時(會在用戶方法用戶調用complete時結束)異步調用傳入的對象的 accept方法,accept方法中調用了onCompleteHandler()方法,onCompleteHandler方法中會判斷queue是否為空,以及queue的頭元素是否完成了用戶的異步方法,當完成的時候,就會將headIsCompleted這個對象signalAll()喚醒

 

2.接着看有序模式Emitter的拉取數據

       

   這裡有序方式拉取數據的邏輯很清晰,如果為空或者頭元素沒有完成用戶的異步方法,headIsCompleted這個對象會wait住(上面可以知道,當加入元素的到queue且頭元素完成異步方法的時候會signalAll())然後將頭數據返回,往下游發送

 

這樣就實現了有序發送,因為Emitter只拉取頭元素且已經完成用戶異步方法的頭元素

 

無序模式: 

  這裏和有序模式就大同小異了,只是變成了,接收數據后直接加入uncompletedQueue,當數據完成異步方法的時候就,放到completedQueue裏面去並signalAll(),只要completedqueue裏面有數據,Emitter就拉取往下發

 

這樣就實現了無序模式,也就是異步寫入誰先處理完就直接放到完成隊列裏面去,然後往下發,不用管接收數據的順序

 

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

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

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

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

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

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

Medium高贊系列,如何正確的在Stack Overflow提問

在我們寫程序的時候,經常會遇到各色各樣的問題,在國內,小夥伴們經常去知乎、CSDN、博客園、思否、安卓巴士等地方提問並獲得答案。

這些地方彙集了很多優秀的、愛分享的國內資源。小編比較自豪的一件事情就是:當初學習dubbo期間,因為一個數據關閉錯誤一直找不到正確的解決方式,就順手把自己解決問題的步驟寫下,並附上參考資料中的方法,算是把那類問題做了一個增強版的總結,沒想過幾個月後,有位粉絲專門找上來感謝我,幫他解決了疑惑。

技術人,就是那麼容易得到滿足。得到別人的一句謝謝,開心的像個傻瓜。前行路上,愛分享、把資源提供給更多的人,是最開心和愉快的事情。

現在是移動互聯網的時代,倘若我們能鏈接到更多的人,倘若我們來連接的不僅僅有國內,還有國外,那豈不是更好?那麼如何在國外得到自己想要的答案?我們不妨去Stack Overflow這個平台去試試,優秀的問答平台,你們懂的。

但是提問也是一門藝術,所以趕緊來看看他們的總結,助你更好地在平台上提問。

原文地址:https://medium.com/better-programming/how-to-ask-a-question-that-gets-answered-on-stack-overflow-45f87f1a2fef

作者:Nabil Nalakath

時間:2019.11.12

當有人告訴我他們在開發中遇到的問題時,在大多數情況下,我的直接答覆是:“您在Stack Overflow上發現了什麼?”

但是,很多開發者會給出奇怪的答案,例如:“我不知道如何使用它,我因提出較差的問題而被禁止,人們總是不贊成我的帖子,或者給我有關如何提問的鏈接,”等。

Stack Overflow是互聯網上最有用,訪問最多的網站之一,但它也是互聯網上最殘酷的平台之一。

如果您犯了一個錯誤或提出了一個愚蠢的問題,人們不會理財你,這就是該平台自成立以來一直保持其標準的方式。因此,別指望有什麼收穫。

相反,我們需要習慣它並改變提問的方式。夠了,讓我們來看看您在提問時要注意哪些重要事項。

發布問題時要注意的事項

  1. 標題要具體(不要在標題中張貼整個問題或廣泛的問題)

  2. 使用正確的標籤(這對於快速獲得答案非常重要)

  3. 張貼代碼的相關部分,並在問題編輯器中使用代碼標籤將其格式化為代碼(如果代碼不是整齊的,大多數人都不會去回答)

  4. 如果您要解釋運行時出現的問題,請嘗試發布屏幕截圖

  5. 如果有日誌的話,發布正確的錯誤日誌(特別是在應用崩潰的情況下)

  6. 如果您的部分輸出沒有錯誤,並且想要對輸出進行特定的修改,而且您似乎無法弄清楚如何,將問題分為兩部分,在問題中清楚提及:

  • 你現在有什麼
  • 你需要達到的目標
  1. 如果與UI相關,請發布線框屏幕截圖,如果不可用,請嘗試在現有的UI屏幕截圖中使用諸如Paint之類的簡單工具標記所需的內容或您要進行的更改

  2. 如果您認為版本代碼可能與解決問題有關,請發布版本代碼(例如:果問題僅在舊版本的PHP或Android中發生,而在新版本中則沒有)

發布時要避免的錯誤

  • 切勿發布代碼中包含品牌名稱或公司名稱的部分

  • 裁剪屏幕截圖以僅显示相關內容

  • 如果代碼包含部分內容,例如鍵或密碼(例如PHP郵件程序代碼中的电子郵件密碼),請始終用****或特殊字符替換密碼字段

  • 不要發布自己創建的特殊算法或應用引擎代碼,除非您不介意其他人使用它或將其開源

壞問題和好問題

讓我們看一下146票贊成的這篇文章:

地址:https://stackoverflow.com/questions/3905734/how-to-send-100-000-emails-weekly?source=post_page-----45f87f1a2fef----------------------

如您在本示例中看到的,已發布的問題不是特定問題。如果您要這樣的教程類型答案,那麼Stack Overflow並不是一個好地方。

以該示例為例,在這種情況下,用戶要求每周使用PHP向100,000個用戶發送一封电子郵件。但問題並沒有显示用戶方面的任何努力。

到目前為止,還沒有提及用戶已經嘗試了什麼或他們面臨的任何特定錯誤。這是不能回答問題的完美範例。

另外,這裡有一些很好的示例問題供您參考。

地址:https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-processing-an-unsorted-array?source=post_page-----45f87f1a2fef----------------------

地址:https://stackoverflow.com/questions/51096796/how-to-enable-horizontal-scrolling-for-chart-js-in-ionic?source=post_page-----45f87f1a2fef----------------------

地址:https://stackoverflow.com/questions/47923524/app-is-crashing-on-some-devices-android-studio-shows-out-of-memory-exception-er?source=post_page-----45f87f1a2fef----------------------

如您所見,即使有人不回答,如果您以適當的方式提出問題,您仍然會獲得贊成票

致謝

最後,如果您得到查詢的答案並且符合您的要求,請將其標記為可接受的答案以關閉問題。

這將幫助發布答案的人獲得聲譽,並鼓勵他們幫助更多人。

畢竟,平台的存在僅是因為這些樂於助人的無私奉獻者願意為您提供幫助,因此這是您為他們所做的最少的事情。

結尾

提問是一門藝術,小編也經常遇到很多提問看不懂、看不明白的情況。無論是在團隊里還是平時和大家交流的過程中,多多少少會遇到互相不理解的情況,所以,做技術的我們實在是太難了,哈哈。

當然,如果學會了一些必要的技巧,提問對我們來說還是just so so,畢竟共同語言這麼多,雖然問題形形色色,但是茫茫人海,總會有人遇到你遇到的問題,總存在能解決問題的方法。

這是一篇很好的提問的範例,不僅僅是在Stack Overflow上,包括我們自己國內的平台、自己項目組、都可以用類似的技巧來提問,能大大節省溝通成本,獲得更高效率。

本文由博客一文多發平台 發布!

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

【其他文章推薦】

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

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

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

JVM 中你不得不知的一些參數

有的同學雖然寫了一段時間 Java 了,但是對於 JVM 卻不太關注。有的同學說,參數都是團隊規定好的,部署的時候也不用我動手,關注它有什麼用,而且,JVM 這東西,聽上去就感覺很神秘很高深的樣子,還是算了吧。

沒錯,部署的時候可能用不到你親自動手,但是出現問題了怎麼辦,難道不用你解決問題嗎,如果對 JVM 了解不夠的話,有些問題可能排查起來就很費力,或者根本無法解決。

本篇以 JDK Hotspot 8 為背景,介紹一下 JVM 的常用參數。建議你在做一些小項目、小 demo 的時候,也把這些參數加上,加深印象。以我的經驗來看,有些知識你剛開始接觸的時候會感覺很難理解,但是沒關係,萬事開頭難嘛,知識點都是需要消化時間的。第一天不理解,甚至過了一個月也不理解,但是總有那麼一刻,你會突然有種茅塞頓開的感覺,感覺一下子通了。最後心裏面感謝自己在多少多少天以前能夠開始學習並堅持學習這些知識點。

只介紹一些常用參數,除了這些常用參數外,Hotspot 還提供了很多其他的參數,每一個都值得考究。

在使用這些參數之前,你需要對 Java 內存模型有一定的了解,可以讀一下 了解一下內存模型。

還是要把內存模型圖放在這裏,方便理解。

堆參數:

-Xms: 堆的初始值,例如 -Xmx2048,初始堆大小為 2G

-Xmx: 堆的最大值,例如 -Xmx2048M,允許最大堆內存 2G

-Xmn: 新生代大小

-XX:SurvivorRatio:Eden 區所佔比例,默認是 8,也就是 80%,例如 -XX:SurvivorRatio=8

最好將 -Xms 和 -Xmx 的值設置成一樣的值,這樣做是為了防止隨着堆空間使用量增加,會動態的調整堆空間大小,有一定的性能損耗,不如開始就設置成相同的值,來規避性能損失。

棧參數

-Xss:棧空間大小,棧是線程獨佔的,所以是一個線程使用棧空間的大小,例如 -Xss256K,如果不設置此參數,默認值是 1M,一般來講設置成 256K 就足夠了。

Metaspace 參數

-XX:MetaspaceSize:Metaspace 空間初始大小,如果不設置的話,默認是20.79M,這個初始大小是觸發首次 Metaspace Full GC 的閾值,例如 -XX:MetaspaceSize=256M

-XX:MaxMetaspaceSize:Metaspace 最大值,默認不限制大小,但是線上環境建議設置,例如

-XX:MaxMetaspaceSize=256M

-XX:MinMetaspaceFreeRatio:最小空閑比,當 Metaspace 發生 GC 后,會計算 Metaspace 的空閑比,如果空閑比(空閑空間/當前 Metaspace 大小)小於此值,就會觸發 Metaspace 擴容。默認值是 40 ,也就是 40%,例如 -XX:MinMetaspaceFreeRatio=40

-XX:MaxMetaspaceFreeRatio:最大空閑比,當 Metaspace 發生 GC 后,會計算 Metaspace 的空閑比,如果空閑比(空閑空間/當前 Metaspace 大小)大於此值,就會觸發 Metaspace 釋放空間。默認值是 70 ,也就是 70%,例如 -XX:MaxMetaspaceFreeRatio=70

建議將 MetaspaceSize 和 MaxMetaspaceSize 設置為同樣大小,避免頻繁擴容。

GC 日誌

簡單日誌

-verbose:gc 或者 -XX:+PrintGC

日誌格式:

[GC (Allocation Failure)  7892K->5646K(19456K), 0.0060442 secs]
[GC (Allocation Failure) , 0.0066315 secs]
[Full GC (Allocation Failure)  19302K->13646K(19456K), 0.0032698 secs]

詳細日誌

#打印詳細日誌
-XX:+PrintGCDetails
#打印 GC 的時間點
-XX:+PrintGCDateStamps

日誌格式:

2019-11-13T14:06:46.099-0800: [GC (Allocation Failure) 2019-11-13T14:06:46.099-0800: [DefNew (promotion failed) : 9180K->9157K(9216K), 0.0084297 secs]2019-11-13T14:06:46.107-0800: [Tenured: 10145K->10145K(10240K), 0.0035768 secs] 13802K->13646K(19456K), [Metaspace: 3895K->3895K(1056768K)], 0.0120887 secs] [Times: user=0.00 sys=0.00, real=0.02 secs] 
2019-11-13T14:06:47.243-0800: [Full GC (Allocation Failure) 2019-11-13T14:06:47.244-0800: [Tenured: 10145K->10145K(10240K), 0.0042686 secs] 19304K->19146K(19456K), [Metaspace: 3895K->3895K(1056768K)], 0.0043232 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

以下幾個 GC 日誌相關的參數打印的內容比較多,生產環境可選擇性開啟,大多數時候不需要開啟。

GC 前後的堆信息

-XX:+PrintHeapAtGC

{Heap before GC invocations=0 (full 0):
 def new generation   total 9216K, used 7892K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,  96% used [0x00000007bec00000, 0x00000007bf3b5200, 
  xxx....
  class space    used 445K, capacity 462K, committed 512K, reserved 1048576K
Heap after GC invocations=1 (full 0):
 def new generation   total 9216K, used 1023K [0x00000007bec00000,
 xxx...
 Metaspace       used 3892K, capacity 4646K, committed 4864K, reserved 1056768K
  class space    used 445K, capacity 462K, committed 512K, reserved 1048576K
}

GC 導致的 Stop the world 時間

-XX:+PrintGCApplicationStoppedTime

Total time for which application threads were stopped: 0.0070384 seconds, Stopping threads took: 0.0000200 seconds

加載類信息

-verbose:class

[Loaded java.net.URLClassLoader$3$1 from /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/rt.jar]

GC 前後的類加載情況

-XX:+PrintClassHistogramBeforeFullGC
-XX:+PrintClassHistogramAfterFullGC
 num     #instances         #bytes  class name
----------------------------------------------
   1:           140       19016264  [B
   2:          2853         226256  [C
   3:           138         169072  [I
   4:           761          86240  java.lang.Class
   5:          2850          68400  java.lang.String
   6:           660          41024  [Ljava.lang.Object;

日誌輸出到文件

以上參數配置好之後,默認會輸出到控制台或者服務指定的統一日誌的位置。但是這裏還會有服務的一般性信息日誌、錯誤日誌等,都混在一起的話會比較亂,所以,一般都會把 jvm 日誌單獨存放。

#GC 活動日誌,根據配置的參數輸出內容
-Xloggc:/Users/fengzheng/jvmlog/gc.log

#致命錯誤日誌,只有在 jvm 發生崩潰的時候會輸出
-XX:ErrorFile=/Users/fengzheng/jvmlog/hs_err_pid%p.log

堆溢出現場保留

有些錯誤雖然不會導致 jvm 崩潰,但是對於服務而言也是非常嚴重的,比如stackOverflow、OutOfMemoryError,發生錯誤后,留存現場信息對分析錯誤原因是至關重要的。jvm 提供了保留堆溢出現場的方法,對於 JDK 8 而言,可能是 heap 溢出,也可能是 Metasapce 溢出。

-XX:HeapDumpPath=/Users/fengzheng/jvmlog
-XX:+HeapDumpOnOutOfMemoryError

最後出現異常后,保存的文件格式為 java_pidxxx.hprof,pid 後面是發生溢出的進程 id,之後可以用 VisualVM、JProfiler 等工具打開分析。

設置垃圾回收器類型

隨着 JDK 版本的升級,可使用的垃圾收集器類型也越來越多了。JDK 8 可使用的垃圾收集器有 7 種,當然有點只適用於年輕代,有點只使用於老年代,JDK 8 中最新的垃圾收集器是 G1,可以用於年輕代和老年代。到了 JDK 11,還出了 ZGC。

下圖是 JDK 8 中可使用的垃圾收集器以及它們配合使用的關係。

Serial、ParNew、Parallel Scavenge 只適用於年輕代,CMS、Serial Old、Parallel Old 只適用於老年代,而 G1 通用於年輕代和老年代。連線表示它們之間可配合使用的關係,其中 CMS 和 Serial Old 連線的意思是說 Serial Old 會作為 CMS 的后預案,當 CMS 發生 Concurrent Mode Failure 時啟用。

在 JDK 8 中,如果不指定垃圾收集器,默認使用參數 -XX:+UseParallelGC,新生代使用 Parallel Scavenge,老年代使用 Serial Old。

-XX:+UseSerialGC:使用 Serial + Serial Old ,運行於 client 模式下的默認設置

-XX:+UseConcMarkSweepGC:使用 ParNew+CMS+Serial Old,CMS 垃圾收集器

-XX:+UseParallelGC:Parallel Scavenge + Serial Old,JDK 8 server 模式下的默認設置

-XX:+UseParallelOldGC:Parallel Scavenge + Parallel Old

-XX:+UseG1GC:使用 G1 垃圾收集器

開啟遠程 JMX 監控

除了日誌外,當我們需要實時查看 JVM 運行情況的時候怎麼辦,當然可以到 JVM 所在服務器用 jstack、jmap、jinfo 等工具進行查看,但是又不夠直觀,這時候就需要開啟 JMX 遠程功能,使用 jConsole、VisualVM 等工具進行監控。或者自己開發監控平台,比如我之前就做了一個 web 版的簡易 VisualVm。

開啟參數如下:

-Dcom.sun.management.jmxremote
#指定 jvm 所在服務器 ip 或域名
-Djava.rmi.server.hostname=192.168.1.1
#指定端口
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.rmi.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
相關閱讀:

不要吝惜你的「推薦」呦

歡迎關注,不定期更新本系列和其他文章
古時的風箏 ,進入公眾號可以加入交流群

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

【其他文章推薦】

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

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

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

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