一、kafka理論
1、kafka是神馬?
kafka是分佈式發佈-訂閱消息系統。它最初由LinkedIn公司開發,之後成爲Apache項目的一部分。Kafka是一個分佈式的,可劃分的,冗餘備份的持久性的日誌服務。它主要用於處理活躍的流式數據。分佈式系統,易於向外擴展。所有的producer、broker和consumer都會有多個,均爲分佈式的。無需停機即可擴展機器。
2、kafka的設計方案
消息持久化及其緩存
磁盤性能:在傳統的磁盤寫入很慢,因爲它使用隨機寫入 50k/s(6個7200轉的sata硬盤組成的raid-5),但是線性寫入速度有300ms/s的速度,所以kafka利用線性寫入的方式。
線性寫入:將數據調用操作系統文件接口寫到文件系統裏面去這樣就緩存到操作系統的頁面緩存中,然後傳統意思來說將其flush一下到磁盤中,但是kafka並沒有這樣,而是保存在頁面緩存中(相當於放在內存當中)並沒有進行flush操作,這樣他就會提供比較高的讀的性能,下次讀就從內核頁面緩存中讀數據,但是內存中存儲數量不是無限大的,所以我們配置參數(每當接收到N條信息或者每過M秒),進行一個flush操作,從而可以爲系統硬件崩潰時“處於危險之中”的數據在量上加個上限。
kafka的緩存不是在內存中保存儘可能多的數據並在需要時將這些數刷新到文件系統,而是做完全相反的事情,將所有的數據立即寫入文件系統中的持久化的日誌中,但不進行刷刷新數據的調用,實際這麼做意味着數據被傳輸到os內核的頁面緩存中去了,隨後在根據配置刷新到硬盤。
持久化常量時間
以往的消息系統元數據的持久化數據結構往往採用BTree。BTree是目前最常用額數據結構,在消息系統中它可以用來廣泛支持多種不同的事物性活非事務性的語義,他的確帶來了一個非常高的處理開銷,Btree的運算時間的複雜度爲0(LOG n),Btree需要一種非常負責的頁面級或者行級鎖才能避免在每次操作時鎖定整顆樹。實現這種機器就要爲行級鎖定付出非常昂貴的代價,負責就必須所有的讀取操作進行串行化(serialize).因爲對磁盤尋道操作的高度依賴,就不太可能高效的從驅動器密碼的提高中獲得改善,因而就不得不使用容量較小(<100GB)轉速較快的sas驅動,以維持一種比較合理的數據與尋道容量之比。kafka的設計是什麼樣的呢?kafka利用按照通常的日誌解決方案的樣子構建,只是簡單的文件讀取和簡單地向文件中追加內容。當然相比的劣勢在於不支持Btree這樣事物和非事物的語義支持,但是優勢在於其所有的操作夫妻度都是0(1),讀取操作並不需要阻止寫入操作,而且反之亦然。這樣做顯然有性能優勢,因爲性能完全同數據大小之間脫離了關係。能夠存取到幾乎無限大的磁盤空間而無須付出性能代價,意味着,我們可以提供其他消息系統並不常見的功能,例如在kafka中,消息在使用完全後並沒有立即刪除,而是會將這些消息保存相當長一段時間,這樣可以利用offset功能進行多次消費,比如說 可以設置從某個offset id往下進行消費,當然一般只有是消費失敗纔回這麼做。
效率最大化
傳統的消息發送:
a、操作系統將數據從磁盤中讀取到內核空間裏的頁面緩存。
b、應用程序將數據從內核空間讀入到用戶空間的緩衝區。
c、應用程序將讀到的數據寫會內核空間並放入socket的緩衝區
d、操作系統將數據從socket的緩衝區拷貝到NIC(網絡接口卡,即網卡)的緩衝區,自此數據才能通過網絡發送出去。
這樣效率顯然很低,因爲裏面涉及到4此拷貝,2次系統調用。
kafka的信息發送是如何的呢?
kafka使用sendfile(0拷貝)就可以避免這些重複的拷貝操作,讓os直接將數據從頁面緩存發送到網絡中,其中只需最後一步中的將數據拷貝到NIC的緩衝區。
kafka採用全文所屬的sendfile拷貝優化方案,數據只需要拷貝到頁面緩存中一次,然後每次發送給使用者時都對他重複使用即可,一次拷貝發給多個消費者。
端到端的批量壓縮
在傳輸的過程中,傳輸前壓縮,到目標後在解壓縮。
二、kafka安裝
1、jdk安裝 wget -c http://118.186.220.66:8002/jdk-7u51-linux-x64.gz mkdir -p /usr/local/java tar zxf jdk-7u51-linux-x64.gz -C /usr/local/java ln -s /usr/local/java/jdk1.7.0_51/bin/java /usr/bin/java ln -s /usr/local/java/jdk1.7.0_51/bin/javac /usr/bin/javac ln -s /usr/local/java/jdk1.7.0_51/bin/javadoc /usr/bin/javadoc ln -s /usr/local/java/jdk1.7.0_51/bin/javaws /usr/bin/javaws # tail -3 ~/.bash_profile export JAVA_HOME=/usr/local/java/jdk1.7.0_51 export PATH=$PATH:$JAVA_HOME/bin exportCLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:$CLASSPATH java -version 2、zookeeper安裝 cd /Data/tools/software/ wget http://www.apache.org/dist//zookeeper/zookeeper-3.4.9/zookeeper-3.4.9.tar.gz tar zxvf zookeeper-3.4.9.tar.gz cd /Data/tools/software/zookeeper-3.4.9/conf cp zoo_sample.cfg zoo.cfg vim zoo.cfg server.1=10.0.0.1:2888:3888 server.2=10.0.0.2:2888:3888 server.3=10.0.0.3:2888:3888 # echo "1">/data/myid # echo "2">/data/myid # echo "3">/data/myid 3、kafka安裝 wget https://archive.apache.org/dist/kafka/0.8.1/kafka_2.10-0.9.0.1.tgz tar zxvf kafka_2.10-0.9.0.1.tgz nohup bin/kafka-server-start.sh config/server.properties &
二、配置文件詳解
#server.properties配置文件 broker.id=1 port=9092 host.name=10.0.0.8 zookeeper.connect=10.0.0.8:2181,10.0.0.0.9:2181,10.0.0.10:2181 num.network.threads=8 #broker處理消息的最大線程數 一般等於核心數 num.io.threads=8# 同上 socket.send.buffer.bytes=1048576 #socket 發送緩衝區 socket調優參數 socket.receive.buffer.bytes=1048576 #接收緩衝區 socket調優參數 socket.request.max.bytes=104857600 #socket請求最大數值,防止serverOOM log.dirs=/data/kafka/kafka-logs num.partitions=8 #默認制定分區 會被命令行參數覆蓋 log.retention.check.interval.ms=60000 #文件大小檢查週期 log.cleaner.enable=false #是否啓用壓縮 segment.ms=24*60*60 num.replica.fetchers=4 #leader 進行復制的線程數。 增大這個數值會增加follow的io default.replication.factor=2 # 創建topic的時候的副本數,可以創建topic時制定參數覆蓋 replica.fetch.max.bytes=2048000 # replicas 每次獲取數據的最大大小 replica.fetch.wait.max.ms=500 # replicas 同leader之間的通信的最大等待時間,失敗了會重試。 replica.high.watermark.checkpoint.interval.ms=5000 #每個replica檢查是否將最高水平進行固化的頻率 replica.socket.timeout.ms=30000 #follower與leader之間的socket超時時間 replica.socket.receive.buffer.bytes=65536 #leader複製時間的socket緩存大小 replica.lag.time.max.ms=10000 #replicas響應partition leader的最長等待時間,若是超過這個時間,就將replicas列入ISR(in-sync replicas),並認爲它是死的,不會再加入管理中 replica.lag.max.messages=4000 #如果follower落後與leader太多,將會認爲此follower[或者說partition relicas]已經失效 ##通常,在follower與leader通訊時,因爲網絡延遲或者鏈接斷開,總會導致replicas中消息同步滯後 ##如果消息之後太多,leader將認爲此follower網絡延遲較大或者消息吞吐能力有限,將會把此replicas遷移 ##到其他follower中. ##在broker數量較少,或者網絡不足的環境中,建議提高此值. controller.socket.timeout.ms=30000 # partition leader與replicas之間通訊時,socket的超時時間 controller.message.queue.size=10 #partition leader與replicas 數據同步時,消息的隊列尺寸 message.max.bytes=2048000 #消息體的最大大小 但是是字節 -------------------- auto.create.topics.enable=true #是否允許自動創建topic,若是false就需要通過命令創建topic log.index.interval.bytes=4096 #當執行一個fetch操作後,需要一定的空間來掃描最近的offset大小,設置越大,代表掃描速度越快,但是也更好內存,一般情況下不需要搭理這個參數 log.index.size.max.bytes=10485760 #對於segment日誌的索引文件大小限制,會被topic創建時的指定參數覆蓋 log.retention.hours=24 #數據存儲的最大時間超過這個時間會根據log.cleanup.policy設置的策略處理。 log.flush.interval.ms=10000 #僅僅通過interval來控制消息的磁盤寫入時機,是不足的.此參數用於控制"fsync"的時間間隔,如果消息量始終沒有達到閥值,但是離上一次磁盤同步的時間間隔達到閥值,也將觸發. -------- log.flush.interval.messages=20000 #log文件”sync”到磁盤之前累積的消息條數,因爲磁盤IO操作是一個慢操作,但又是一個”數據可靠性"的必要手段,所以此參數的設置,需要在"數據可靠性"與"性能"之間做必要的權衡.如果此值過大,將會導致每次"fsync"的時間較長(IO阻塞),如果此值過小,將會導致"fsync"的次數較多,這也意味着整體的client請求有一定的延遲.物理server故障,將會導致沒有fsync的消息丟失. log.flush.scheduler.interval.ms=2000 #檢查是否需要固化到硬盤的時間間隔 log.roll.hours=24 #這個參數會在日誌segment沒有達到log.segment.bytes設置的大小,也會強制新建一個segment會被 topic創建時的指定參數覆蓋 log.cleanup.interval.mins=30 #檢查處理規則間隔 log.segment.bytes=1073741824 #一個消息長度 超過在創建一個 zookeeper.connection.timeout.ms=6000 #zookeeper連接超時時間 zookeeper.sync.time.ms=2000 #一個zk flower能落後leader多久 fetch.purgatory.purge.interval.requests=1000 ## f防止oom 的參數 用於request 狀態轉變爲complete後從purgatory中移除。 producer.purgatory.purge.interval.requests=1000 ## f防止oom 的參數 用於request 狀態轉變爲complete後從purgatory中移除。
三、kafka常用操作
1、查看topic list
bin/kafka-topics.sh --list --zookeeper x.x.x.x:2181
2、創建topic
bin/kafka-topics.sh --create --zookeeper x.x.x.1:2181,x.x.x.2:2181,x.x.x.3:2181 --replication-factor 3 --partitions 9 --topic topic_name1
--topic test_kafka_14 --zookeeper 指定多個zookeeper服務器 --replication 創建副本數 3表示一共有3個複本,3臺broker的話,最大允許2臺宕機,如果複本2個的話最多就只能宕機一臺。
3、查看topic狀態
bin/kafka-topics.sh --describe --zookeeper x.x.x.1:2181 --topic test_kafka_14 --describe 描述參數 --zookeeper 指定一臺zookeeper 結果: Topic:test-0926PartitionCount:9ReplicationFactor:3Configs: Topic: test-0926Partition: 0Leader: 1Replicas: 1,2,0Isr: 2,0,1 Topic: test-0926Partition: 1Leader: 2Replicas: 2,0,1Isr: 2,0,1 Topic: test-0926Partition: 2Leader: 0Replicas: 0,1,2Isr: 2,0,1 Topic: test-0926Partition: 3Leader: 1Replicas: 1,0,2Isr: 2,0,1 Topic: test-0926Partition: 4Leader: 2Replicas: 2,1,0Isr: 2,0,1 Topic: test-0926Partition: 5Leader: 0Replicas: 0,2,1Isr: 2,0,1 Topic: test-0926Partition: 6Leader: 1Replicas: 1,2,0Isr: 2,0,1 Topic: test-0926Partition: 7Leader: 2Replicas: 2,0,1Isr: 2,0,1 Topic: test-0926Partition: 8Leader: 0Replicas: 0,1,2Isr: 2,0,1
單行代表:指標名稱 分區號 目前該分區負責讀寫的leader 該分區數據的複本所在leader 當前分區可用(可接管)的leader.
4、手動重新分配分區
bin/kafka-preferred-replica-election.sh --zookeeper x.x.x.1:2181,x.x.x.2:2181,x.x.x.3:2181
默認9.0.1版本也會自動調整分區即負載均衡在某個broker宕機又重新啓動後。
5、增加分區(kafka只支持增加不支持動態減少)
bin/kafka-add-partitions.sh --topic test --partition 2 --zookeeper 192.168.197.170:2181,192.168.197.171:2181 (爲topic test增加2個分區) bin/kafka-topics.sh --zookeeper 10.3.12.49:2181,10.3.12.53:2181,10.3.12.54:2181 -alter --partitions 6 --topic leo-ops-main-client1
6、控制檯接收消息
bin/kafka-console-consumer.sh --zookeeper 192.168.197.170:2181,192.168.197.171:2181 --from-beginning --topic test
7、控制檯發送消息
bin/kafka-console-producer.sh --broker-list 192.168.197.170:9092,192.168.197.171: 9092 --topic test
8、kafka之刪除topic
例如要刪除 test_kafka_1 1、先在kafka刪除topic ./bin/kafka-topics.sh --delete --zookeeper 【zookeeper server】 --topic test_kafka_1 ## 停止 kakfa 2、刪除kafka存儲目錄(server.properties文件log.dirs配置,默認爲"/tmp/kafka-logs") cd /KAFKADIR ; rm -rf test_kafka_1-* 3、zookeeper刪除topic zookeeper-3.4.9/bin/zkCli.sh -server 127.0.0.1:2181 rmr /brokers/topics/test_kafka_1 4、清空zookeeper admin下刪除topic rmr /admin/delete_topics/test_kafka_1 5、刪除zookeeper中的消費記錄 #刪除topic test的consumer group,如果有消費記錄的話 rmr /kafka/consumers/test_kafka_1* # 停止zookeeper 6、清空replication信息否則將一直報錯。 vi replication-offset-checkpoint 原文爲: 0 15 pjtest 4 0 pjtest 8 0 managejob 5 0 pjtest 6 0 pjtest 0 0 pjtest 5 0 pjtest 3 0 pjtest 7 0 pjtest 9 0 pjtest 2 0 managejob 9 0 managejob 1 0 managejob 3 0 pjtest 1 0 managejob 7 0 修改爲: 0 5 managejob 5 0 managejob 9 0 managejob 1 0 managejob 3 0 managejob 7 0 vi recovery-point-offset-checkpoint 同理修改