標籤: 潭子電動車

  • TCP 重置攻擊的工作原理

    TCP 重置攻擊的工作原理

    原文鏈接:https://fuckcloudnative.io/posts/deploy-k3s-cross-public-cloud/

    TCP 重置攻擊 是使用一個單一的數據包來執行的,只有幾個字節大小。攻擊者製作併發送一個偽造的 TCP 重置包來干擾用戶和網站的連接,欺騙通信雙方終止 TCP 連接。我們偉大的 xx 長城便運用了這個技術來進行 TCP 關鍵字阻斷。

    理解 TCP 重置攻擊並不需要具備深厚的網絡知識功底,只需要一台筆記本就可以對自己進行模擬攻擊。本文將會帶你了解 TCP 重置攻擊的原理,同時會幫助你理解很多關於 TCP 協議的特性。本文主要內容:

    • 回顧 TCP 協議的基礎知識
    • 了解 TCP 重置攻擊的原理
    • 使用一個簡單的 Python 腳本來模擬攻擊

    下面開始分析 TCP 重置攻擊原理。

    1. 偉大的 xx 長城是如何利用 TCP 重置攻擊的?

    這一段略過,原因你懂得,感興趣的請直接看原文。

    2. TCP 重置攻擊的工作原理

    在 TCP 重置攻擊中,攻擊者通過向通信的一方或雙方發送偽造的消息,告訴它們立即斷開連接,從而使通信雙方連接中斷。正常情況下,如果客戶端收發現到達的報文段對於相關連接而言是不正確的,TCP 就會發送一個重置報文段,從而導致 TCP 連接的快速拆卸。

    TCP 重置攻擊利用這一機制,通過向通信方發送偽造的重置報文段,欺騙通信雙方提前關閉 TCP 連接。如果偽造的重置報文段完全逼真,接收者就會認為它有效,並關閉 TCP 連接,防止連接被用來進一步交換信息。服務端可以創建一個新的 TCP 連接來恢復通信,但仍然可能會被攻擊者重置連接。萬幸的是,攻擊者需要一定的時間來組裝和發送偽造的報文,所以一般情況下這種攻擊只對長連接有殺傷力,對於短連接而言,你還沒攻擊呢,人家已經完成了信息交換。

    從某種意義上來說,偽造 TCP 報文段是很容易的,因為 TCP/IP 都沒有任何內置的方法來驗證服務端的身份。有些特殊的 IP 擴展協議(例如 IPSec)確實可以驗證身份,但並沒有被廣泛使用。客戶端只能接收報文段,並在可能的情況下使用更高級別的協議(如 TLS)來驗證服務端的身份。但這個方法對 TCP 重置包並不適用,因為 TCP 重置包是 TCP 協議本身的一部分,無法使用更高級別的協議進行驗證。

    儘管偽造 TCP 報文段很容易,但偽造正確的 TCP 重置報文段並完成攻擊卻並不容易。為了理解這項工作的難度,我們需要先了解一下 TCP 協議的工作原理。

    3. TCP 協議工作原理

    TCP 協議的目標是向客戶端發送一份完整的數據副本。例如,如果我的服務器通過 TCP 連接向你的計算機發送我的網站的 HTML,你的計算機的 TCP 協議棧應該能夠以我發送的形式和順序輸出 HTML

    然而現實生活中我的 HTML 內容並不是按順序發送的,它被分解成許多小塊(稱為 TCP 分組),每個小塊在網絡上被單獨發送,並被重新組合成原來發送的順序。這種重新組合后的輸出被稱為 TCP 字節流

    將分組重建成字節流並不簡單,因為網絡是不可靠的。TCP分組可能會被丟棄,可能不按發送的順序到達客戶端,也可能會被重複發送、報文損壞等等。因此,TCP 協議的職責是在不可靠的網絡上提供可靠的通信。TCP 通過要求連接雙方保持密切聯繫,持續報告它們接收到了哪些數據來實現可靠通信,這樣服務端就能夠推斷出客戶端尚未接收到的數據,並重新發送丟失的數據。

    為了進一步理解這個過程,我們需要了解服務端和客戶端是如何使用序列號(sequence numbers)來標記和跟蹤數據的。

    TCP 序列號

    TCP 協議的通信雙方, 都必須維護一個序列號(sequence numbers),對於客戶端來說,它會使用服務端的序列號來將接收到的數據按照發送的順序排列。

    當通信雙方建立 TCP 連接時,客戶端與服務端都會向對方發送一個隨機的初始序列號,這個序列號標識了其發送數據流的第一個字節。TCP 報文段包含了 TCP 頭部,它是附加在報文段開頭的元數據,序列號就包含在 TCP 頭部中。由於 TCP 連接是雙向的,雙方都可以發送數據,所以 TCP 連接的雙方既是發送方也是接收方,每一方都必須分配和管理自己的序列號。

    確認應答

    當接收方收到一個 TCP 報文段時,它會向發送方返回一個 ACK 應答報文(同時將 TCP 頭部的 ACK 標誌位置 1),這個 ACK 號就表示接收方期望從發送方收到的下一個字節的序列號。發送方利用這個信息來推斷接收方已經成功接收到了序列號為 ACK 之前的所有字節。

    TCP 頭部格式如下圖所示:

    一個確認應答報文的 TCP 頭部必須包含兩個部分:

    • ACK 標誌位置位 1
    • 包含確認應答號(ACK number)

    TCP 總共有 6 個標誌位,下文就會講到其中的 RST 標誌位。

    TCP 頭部包含了多個選項,其中有一個選擇確認選項(SACK),如果使用該選項,那麼當接收方收到了某個範圍內的字節而不是連續的字節時,就會發送 SACK 告知對方。例如,只收到了字節 1000~30004000~5000,但沒有收到 3001~3999。為了簡單起見,下文討論 TCP 重置攻擊時將忽略選擇確認選項。

    如果發送方發送了報文後在一段時間內沒有收到 ACK,就認為報文丟失了,並重新發送報文,用相同的序列號標記。這就意味着,如果接收方收到了重複的報文,可以使用序列號來判斷是否見過這個報文,如果見過則直接丟棄。網絡環境是錯綜複雜的,往往並不是如我們期望的一樣,先發送的數據包,就先到達目標主機,反而它很騷,可能會由於網絡擁堵等亂七八糟的原因,會使得舊的數據包,先到達目標主機。一般分兩種情況:

    1. 發送的數據包丟失了
    2. 發送的數據包被成功接收,但返回的 ACK 丟失了

    這兩種情況對發送方來說其實是一樣的,發送方並不能區分是哪種情況,所以只能重新發送數據包。

    只要不頻繁重複發送數據,額外的開銷基本可以忽略。

    為偽造的重置包選擇序列號

    構建偽造的重置包時需要選擇一個序列號。接收方可以接收序列號不按順序排列的報文段,但這種容忍是有限度的,如果報文段的序列號與它期望的相差甚遠,就會被直接丟棄。

    因此,一個成功的 TCP 重置攻擊需要構建一個可信的序列號。但什麼才是可信的序列號呢?對於大多數報文段(除了重置包,即 RST 包)來說,序列號是由接收方的接收窗口大小決定的。

    TCP 滑動窗口大小

    想象一下,將一台上世紀 90 年代初的古老計算機,連接到現代千兆光纖網絡。閃電般快速的網絡可以以令人瞠目結舌的速度向這台古老的計算機傳送數據,速度遠遠超過該計算機的處理能力。但並沒有什麼卵用,因為只有接收方接收並處理了報文,才能認為這個報文已經被收到了。

    TCP 協議棧有一個緩衝區,新到達的數據被放到緩衝區中等待處理。但緩衝區的大小是有限的,如果接收方的處理速度跟不上發送方的發送速度,緩衝區就會被填滿。一旦緩衝區被填滿,多餘的數據就會被直接丟棄,也不會返回 ACK。因此一旦接收方的緩衝區有了空位,發送方必須重新發送數據。也就是說,如果接收方的處理速度跟不上,發送方的發送速度再快也沒用。

    緩衝區到底有多大?發送方如何才能知道什麼時候可以一次發送更多的數據,什麼時候該一次發送很少的數據?這就要靠 TCP 滑動窗口了。接收方的滑動窗口大小是指發送方無需等待確認應答,可以持續發送數據的最大值。 假設接收方的通告窗口大小為 100,000 字節,那麼發送方可以無需等待確認應答,持續發送 100,000 個字節。再假設當發送方發送第 100,000 個字節時,接收方已經發送了前 10,000 個字節的 ACK,這就意味着窗口中還有 90,000 個字節未被確認,發送方還可以再持續發送 10,000 個字節。如果發送了 10,000 個字節的過程中沒有收到任何的 ACK,那麼接收方的滑動窗口將被填滿,發送方將停止發送新數據(可以繼續發送之前丟失的數據),直到收到相關的 ACK 才可以繼續發送。

    TCP 連接雙方會在建立連接的初始握手階段通告對方自己窗口的大小,後續還可以動態調整。TCP 緩衝區大的服務器可能會聲明一個大窗口,以便最大限度提高吞吐量。TCP 緩衝區小的服務器可能會被迫聲明一個小窗口,這樣做會犧牲一定的吞吐量,但為了防止接收方的 TCP 緩衝區溢出,還是很有必要的。

    換個角度來看,TCP 滑動窗口大小是對網絡中可能存在的未確認數據量的硬性限制。我們可以用它來計算髮送方在某一特定時間內可能發送的最大序列號(max_seq_no):

    max_seq_no = max_acked_seq_no + window_size
    

    其中 max_acked_seq_no 是接收方發送的最大 ACK 號,它表示發送方知道接收方已經成功接收的最大序列號。window_size 是窗口大小,它表示允許發送方最多發送的未被確認的字節。所以發送方可以發送的最大序列號是:max_acked_seq_no + window_size

    TCP 規範規定,接收方應該忽略任何序列號在接收窗口之外的數據。例如,如果接收方確認了所有序列號在 15,000 以下的字節,且接收窗口大小為 30,000,那麼接下來接收方只能接收序列號範圍在 15,000 ~ 45,000 之間的數據。如果一個報文段的部分數據在窗口內,另一部分數據在窗口外,那麼窗口內的數據將被接收確認,窗口外的數據將被丟棄。注意:這裏忽略了選擇確認選項,再強調一遍!

    對於大多數 TCP 報文段來說,滑動窗口的規則告訴了發送方自己可以接收的序列號範圍。但對於重置報文來說,序列號的限制更加嚴格,這是為了抵禦一種攻擊叫做盲目 TCP 重置攻擊(blind TCP reset attack),下文將會解釋。

    TCP 重置報文段的序列號

    對於 TCP 重置報文段來說,接收方對序列號的要求更加嚴格,只有當其序列號正好等於下一個預期的序列號時才能接收。繼續搬出上面的例子,接收方發送了一個確認應答,ACK 號為 15,000。如果接下來收到了一個重置報文,那麼其序列號必須是 15,000 才能被接收。

    如果重置報文的序列號超出了接收窗口範圍,接收方就會直接忽略該報文;如果其序列號在接收窗口範圍內,那麼接收方就會返回一個 challenge ACK,告訴發送方重置報文段的序列號是錯誤的,並告之正確的序列號,發送方可以利用 challenge ACK 中的信息來重新構建和發送重置報文。

    其實在 2010 年之前,TCP 重置報文段和其他報文段的序列號限制規則一樣,但無法抵禦盲目 TCP 重置攻擊,後來才採取這些措施施加額外的限制。

    盲目 TCP 重置攻擊

    如果攻擊者能夠截獲通信雙方正在交換的信息,攻擊者就能讀取其數據包上的序列號和確認應答號,並利用這些信息得出偽裝的 TCP 重置報文段的序列號。相反,如果無法截獲通信雙方的信息,就無法確定重置報文段的序列號,但仍然可以批量發出盡可能多不同序列號的重置報文,以期望猜對其中一個序列號。這就是所謂的盲目 TCP 重置攻擊(blind TCP reset attack)。

    在 2010 年之前 TCP 的原始版本中,攻擊者只需要猜對接收窗口內的隨便哪一個序列號即可,一般只需發送幾萬個報文段就能成功。採取額外限制的措施后,攻擊者需要發送數以百萬計的報文段才有可能猜對序列號,這幾乎是很難成功的。更多細節請參考 RFC-5963。

    4. 模擬攻擊

    以下實驗是在 OSX 系統中完成的,其他系統請自行測試。

    現在來總結一下偽造一個 TCP 重置報文要做哪些事情:

    • 嗅探通信雙方的交換信息。
    • 截獲一個 ACK 標誌位置位 1 的報文段,並讀取其 ACK 號。
    • 偽造一個 TCP 重置報文段(RST 標誌位置為 1),其序列號等於上面截獲的報文的 ACK 號。這隻是理想情況下的方案,假設信息交換的速度不是很快。大多數情況下為了增加成功率,可以連續發送序列號不同的重置報文。
    • 將偽造的重置報文發送給通信的一方或雙方,時其中斷連接。

    為了實驗簡單,我們可以使用本地計算機通過 localhost 與自己通信,然後對自己進行 TCP 重置攻擊。需要以下幾個步驟:

    1. 在兩個終端之間建立一個 TCP 連接。
    2. 編寫一個能嗅探通信雙方數據的攻擊程序。
    3. 修改攻擊程序,偽造併發送重置報文。

    下面正式開始實驗。

    建立 TCP 連接

    可以使用 netcat 工具來建立 TCP 連接,這個工很多操作系統都預裝了。打開第一個終端窗口,運行以下命令:

    $ nc -nvl 8000
    

    這個命令會啟動一個 TCP 服務,監聽端口為 8000。接着再打開第二個終端窗口,運行以下命令:

    $ nc 127.0.0.1 8000
    

    該命令會嘗試與上面的服務建立連接,在其中一個窗口輸入一些字符,就會通過 TCP 連接發送給另一個窗口並打印出來。

    嗅探流量

    編寫一個攻擊程序,使用 Python 網絡庫 scapy 來讀取兩個終端窗口之間交換的數據,並將其打印到終端上。完整的代碼參考我的 GitHub 倉庫,代碼的核心是調用 scapy 的嗅探方法:

    t = sniff(
            iface='lo0',
            lfilter=is_packet_tcp_client_to_server(localhost_ip, localhost_server_port, localhost_ip),
            prn=log_packet,
            count=50)
    

    這段代碼告訴 scapylo0 網絡接口上嗅探數據包,並記錄所有 TCP 連接的詳細信息。

    • iface : 告訴 scapy 在 lo0(localhost)網絡接口上進行監聽。
    • lfilter : 這是個過濾器,告訴 scapy 忽略所有不屬於指定的 TCP 連接(通信雙方皆為 localhost,且端口號為 8000)的數據包。
    • prn : scapy 通過這個函數來操作所有符合 lfilter 規則的數據包。上面的例子只是將數據包打印到終端,下文將會修改函數來偽造重置報文。
    • count : scapy 函數返回之前需要嗅探的數據包數量。

    發送偽造的重置報文

    下面開始修改程序,發送偽造的 TCP 重置報文來進行 TCP 重置攻擊。根據上面的解讀,只需要修改 prn 函數就行了,讓其檢查數據包,提取必要參數,並利用這些參數來偽造 TCP 重置報文併發送。

    例如,假設該程序截獲了一個從(src_ip, src_port)發往 (dst_ip, dst_port)的報文段,該報文段的 ACK 標誌位已置為 1,ACK 號為 100,000。攻擊程序接下來要做的是:

    • 由於偽造的數據包是對截獲的數據包的響應,所以偽造數據包的源 IP/Port 應該是截獲數據包的目的 IP/Port,反之亦然。
    • 將偽造數據包的 RST 標誌位置為 1,以表示這是一個重置報文。
    • 將偽造數據包的序列號設置為截獲數據包的 ACK 號,因為這是發送方期望收到的下一個序列號。
    • 調用 scapysend 方法,將偽造的數據包發送給截獲數據包的發送方。

    對於我的程序而言,只需將這一行取消註釋,並註釋這一行的上面一行,就可以全面攻擊了。按照步驟 1 的方法設置 TCP 連接,打開第三個窗口運行攻擊程序,然後在 TCP 連接的其中一個終端輸入一些字符串,你會發現 TCP 連接被中斷了!

    進一步實驗

    1. 可以繼續使用攻擊程序進行實驗,將偽造數據包的序列號加減 1 看看會發生什麼,是不是確實需要和截獲數據包的 ACK 號完全相同。
    2. 打開 Wireshark,監聽 lo0 網絡接口,並使用過濾器 ip.src == 127.0.0.1 && ip.dst == 127.0.0.1 && tcp.port == 8000 來過濾無關數據。你可以看到 TCP 連接的所有細節。
    3. 在連接上更快速地發送數據流,使攻擊更難執行。

    總的來說,TCP 重置攻擊既深奧又簡單,祝你實驗順利。

    Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包發布地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs加載問題, 修復lvscare社區netlink與3.10內核不兼容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經集成sealos的機器人實時可以看到sealos的動態。

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

    【其他文章推薦】

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

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

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

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

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

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

  • 世界水資源週上談淹水 WWF:自由流動的河很重要

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

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

    【其他文章推薦】

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

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

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

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

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

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

  • 圖解MySQL索引(三)—如何正確使用索引?

    圖解MySQL索引(三)—如何正確使用索引?

    MySQL使用了B+Tree作為底層數據結構,能夠實現快速高效的數據查詢功能。工作中可怕的是沒有建立索引,比這更可怕的是建好了索引又沒有使用到。
    本文將圍繞着如何優雅的使用索引,圖文並茂地和大家一起探討索引的正確打開姿勢,不談底層原理,只求工作實戰。

    1. 索引的特點

    page之間是雙鏈表形式,而每個page內部的數據則是單鏈表形式存在。當進行數據查詢時,會限定位到具體的page,然後在page中通過二分查找具體的記錄。

    並且索引的順序不同,數據的存儲順序則也不同。所以在開發過程中,一定要注意索引字段的先後順序。

    最左匹配原則

    當一個索引中包含多個字段時,可以稱之為組合索引。MySQL中有個很重要的規則,即最左匹配原則用來定義組合索引的命中規則,它是指在檢索數據時從聯合索引的最左邊開始匹配。假設對用戶表建立一個聯合索引(a,b,c),那麼條件a,(a,b),(a,b,c)都會用到索引。

    在匹配過程中會優先根據最左前面的字段a進行匹配,然後再判斷是否用到了索引字段b,直到無法找到對應的索引字段,或者對應的索引被”破壞“(下文中會介紹)。

    以下是本文中操作實踐用到的初始化語句,有條件的同學可以再本地執行,建議使用MySQL5.6+版本,畢竟實操才是學習的最佳途徑。

    SET NAMES utf8mb4;
    -- ----------------------------
    -- Table structure for test_table
    -- ----------------------------
    DROP TABLE IF EXISTS `test_table`;
    CREATE TABLE `test_table` (
      `id` bigint(20unsigned NOT NULL AUTO_INCREMENT,
      `a` varchar(255COLLATE utf8mb4_bin NOT NULL,
      `b` varchar(255COLLATE utf8mb4_bin NOT NULL,
      `c` varchar(255COLLATE utf8mb4_bin NOT NULL,
      `d` varchar(255COLLATE utf8mb4_bin NOT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_a_b_c` (`a`,`b`,`c`)
    ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

    -- ----------------------------
    -- Records of test_table
    -- ----------------------------
    BEGIN;
    INSERT INTO `test_table` VALUES 
    (1'zhangsan''12222222222''23''aafasd'),
    (2'lisi''13333333333''21''cxvcxv'),
    (3'wanger''14444444444''24''dfdf'),
    (4'liqiang''18888888888''18''ccsdf');
    COMMIT;

    2. 正確創建索引

    盡量使用自增長主鍵

    使用自增長主鍵的原因筆者認為有兩個。首先能有效減少頁分裂,MySQL中數據是以頁為單位存儲的且每個頁的大小是固定的(默認16kb),如果一個數據頁的數據滿了,則需要分成兩個頁來存儲,這個過程就叫做頁分裂。

    如果使用了自增主鍵的話,新插入的數據都會盡量的往一個數據頁中寫,寫滿了之後再申請一個新的數據頁寫即可(大多數情況下不需要分裂,除非父節點的容量也滿了)。

    自增主鍵

    非自增主鍵

    其次,對於緩存友好。系統分配給MySQL的內存有限,對於數據量比較多的數據庫來說,通常只有一小部分數據在內存中,而大多數數據都在磁盤中。如果使用無序的主鍵,則會造成隨機的磁盤IO,影響系統性能。

    選擇性高的列優先

    關注索引的選擇性。索引的選擇性,也可稱為數據的熵。在創建索引的時候通常要求將選擇性高的列放在最前面,對於選擇性不高的列甚至可以不創建索引。如果選擇性不高,極端性情況下可能會掃描全部或者大多數索引,然後再回表,這個過程可能不如直接走主鍵索引性能高。

    索引列的選擇往往需要根據具體的業務場景來選擇,但是需要注意的是索引的區分度越高則價值就越高,意味着對於檢索的性價比就高。索引的區分度等於count(distinct 具體的列) / count(*),表示字段不重複的比例。

    唯一鍵的區分度是1,而對於一些狀態值,性別等字段區分度往往比較低,在數據量比較大的情況下,甚至有無限接近0。假設一張表中用data_status來表示數據的狀態,1-有效,2-刪除,則數據的區分度為 1/500000。如果100萬條數據中只有1條被刪除,並且在查詢數據時查找data_status = 0 的數據時,需要進行全表掃描。由於索引也是需要佔用內存的,所以在內存較為有限的環境下,區分度不高的索引幾乎沒有意義。

    聯合索引優先於多列獨立索引

    聯合索引優先於多列獨立索引, 假設有三個字段a,b,c, 索引(a)(a,b),(a,b,c)可以使用(a,b,c)代替。MySQL中的索引並不是越多越好,各個公司的規定中往往會限制單表中的索引的個數。原因在於,索引本身也會佔用一定的空間,並且維護一個索引時有一定的代碼的,所以在滿足需求的情況下一定要盡可能創建更少的索引。

    執行語句:

    explain select * from test_table where a = "zhangsan";
    explain select * from test_table where a = "zhangsan" and b = "188466668888";
    explain select * from test_table where a = "zhangsan" and b = "188466668888" and c = "23";

    執行結果分析:

    實際上建立(a, b, c)聯合索引時,其作用相當於(a), (a, b), (a, b, c) 三個索引。所以以上三種查詢方式均會命中索引。

    覆蓋索引避免回表

    覆蓋索引如果執行的語句是 select ID from T where k between 3 and 5,這時只需要查 ID 的值,而 ID 的值已經在 k 索引樹上了,因此可以直接提供查詢結果,不需要回表。也就是說,在這個查詢裏面,索引 k 已經“覆蓋了”我們的查詢需求,我們稱為覆蓋索引。由於覆蓋索引可以減少樹的搜索次數,顯著提升查詢性能,所以使用覆蓋索引是一個常用的性能優化手段。

    覆蓋索引的查詢優化

    覆蓋索引同時還會影響索引的選擇,對於(a,b,c)索引來說,理論上來說不滿足最左匹配原則,但是實際上也會走索引。原因在於,優化器認為(a,b,c)索引的性能會高於全表掃描,實際情況也是這樣的,感興趣的小夥伴不妨分析一下上文中介紹的數據結構。

    explain select a,b,c from test_table where b = "188466668888" and c = "23";

    執行結果:

    滿足查詢和排序

    索引要滿足查詢和排序。大部分同學在創建索引時,通常第一反應是查詢條件來選擇索引列,需要注意的是查詢和排序同樣重要,我們建立的索引要同時滿足查詢和排序的需求.

    包含要排序的列

    select c, d from test_table  where a = 1 and b = 2 order by c;

    雖然查詢條件只使用了a,b兩個字段,但是由於排序用到了c字段,我們能可以建立(a,b,c)聯合索引來進行優化。

    保證索引字段順序

    如上文中的介紹,索引的字段順序決定了索引數據的組織順序。要想更高性能的檢索數據,一定要盡可能的藉助底層數據結構的特點來進行。如,索引(a, b)的默認組織形式就是先根據a排序,在a相同的情況下再根據b排序。

    考慮索引的大小

    內存中的空間十分寶貴,而索引往往又需要在內存中。為了在有限的內存中存儲更多的索引,在設計索引時往往要考慮索引的大小。比如我們常用的郵箱,xxxx@xx.com, 假設都是abc公司的,則郵箱後綴完全一致為@abc.com, 索引的區分度完全取決於@前面的字符串。

    針對上述情況,MySQL 是支持前綴索引的,也就是說,你可以定義字符串的一部分作為索引。默認地,如果你創建索引的語句不指定前綴長度,那麼索引就會包含整個字符串。

    如果使用的 email 整個字符串的索引結構執行順序是這樣的:從 index1 索引樹找到滿足索引值是’liqiang156@11.com’的這條記錄,取得 id (主鍵)的值ID2;到主鍵上查到主鍵值是ID2的行,將這行記錄加入結果集;

    取 email 索引樹上剛剛查到的位置的下一條記錄,發現已經不滿足 email=’liqiang156@qq.com’的條件了,循環結束。這個過程中,只需要回主鍵索引取一次數據,所以系統認為只掃描了一行。但是它的問題就是索引的後半部分都是重複的,浪費內存。

    這時我們可以考慮使用前綴索引,如果使用的是 index2 (email(7) 索引結構),執行順序是這樣的:從 index2 索引樹找到滿足索引值是’liqiang’的記錄,找到的第一個是 ID1,到主鍵上查到主鍵值是 ID1 的行,判斷出 email 的值是’liqiang156@xxx.com’,加入結果集。

    取 index2 上剛剛查到的位置的下一條記錄,發現仍然是’liqiang’,取出 ID2,再到 ID 索引上取整行然後判斷,這次值仍然不對,則丟棄繼續往下取。
    重複上一步,直到在 index2 上取到的值不是’liqiang’或者索引搜索完畢之後,循環結束。在這個過程中,要回主鍵索引取 4 次數據,也就是掃描了 4 行。通過這個對比,你很容易就可以發現,使用前綴索引后,可能會導致查詢語句讀數據的次數變多。

    不過方法總比困難多,我們在建立索引時可以先通過語句查看一下索引的區分度,或者提前預估餘下前綴長度,對於上述問題我們可以將前綴長度調整為9即可達到效果。索引,在使用前綴索引時,一定要充分考慮數據的特徵,選擇合適的

    對於一些比較長的字段的等值查詢,我們也可以採用其他方式來縮短索引的長度。比如url一般都是比較長,我們可以冗餘一列存儲其Hash值

     select field_list from t where id_card_crc=crc32('input_id_card_string'and id_card='input_id_card_string'

    對於我們國家的身份證號,一共 18 位,其中前 6 位是地址碼,所以同一個縣的人的身份證號前 6 位一般會是相同的。為了提高區分度,我們可以將身份證號碼倒序存儲

     select field_list from t where id_card = reverse('input_id_card_string');

    3. 正確使用索引

    建立合適的索引是前提,想要取得理想的查詢性能,還應保證能夠用到索引。避免索引失效即是優化。

    不在索引上進行任何操作

    索引上進行計算,函數,類型轉換等操作都會導致索引從當前位置(聯合索引多個字段,不影響前面字段的匹配)失效,可能會進行全表掃描。

    explain select * from test_table where upper(a) = "ZHANGSAN" 

    對於需要計算的字段,則一定要將計算方法放在“=”後面,否則會破壞索引的匹配,目前來說MySQL優化器不能對此進行優化。

    explain select * from test_table where a = lower("ZHANGSAN")

    隱式類型轉換

    需要注意的是,在查詢時一定要注意字段類型問題,比如a字段時字符串類型的,而匹配參數用的是int類型,此時就會發生隱式類型轉換,相當於相當於在索引上使用函數。

    explain select * from test_table where a = 1;


    a是字符串類型,然後使用int類型的1進行匹配,此時就發生了隱式類型轉換,破壞索引的使用。

    只查詢需要的列

    在日常開發中很多同學習慣使用 select * … 來構建查詢語句,這種做法也是極不推薦的。主要原因有兩個,首先查詢無用的列在數據傳輸和解析綁定過程中會增加網絡IO,以及CPU的開銷,儘管往往這些消耗可以被忽略,但是我們也要避免埋坑。

    explain select a,b,c from test_table where a="zhangsan" and b = "188466668888" and c = "23";

    其次就是會使得覆蓋索引”失效”, 這裏的失效並非真正的不走索引。覆蓋索引的本質就是在索引中包含所要查詢的字段,而 select * 將使覆蓋索引失去意義,仍然需要進行回表操作,畢竟索引通常不會包含所有的字段,這一點很重要。

    explain select * from test_table where a="zhangsan" and b = "188466668888" and c = "23";

    不等式條件

    查詢語句中只要包含不等式,負向查詢一般都不會走索引,如 !=, <>, not in, not like等。

    explain select * from test_table where a !="1222" and b="12222222222" and c = 23;
    explain select * from test_table where a <>"1222" and b="12222222222" and c = 23;
    explain select * from test_table where a not in ("xxxx");

    模糊匹配查詢

    最左前綴在進行模糊匹配時,一般禁止使用%前導的查詢,如like “%zhangsan”。

    explain select * from test_table where a like "zhangsan";
    explain select * from test_table where a like "%zhangsan";
    explain select * from test_table where a like "zhangsan%";

    最左匹配原則

    索引是有順序的,查詢條件中缺失索引列之後的其他條件都不會走索引。比如(a, b, c)索引,只使用b, c索引,就不會走索引。

    explain select * from test_table where b = "188466668888" and c = "23";

    如果索引從中間斷開,索引會部分失效。這裏的斷開指的是缺失該字段的查詢條件,或者說滿足上述索引失效情況的任意一個。不過這裏的仍然會使用到索引,只不過只能使用到索引的前半部分。

    explain select * from test_table where a="zhangsan" and b != 1 and c = "23"

    值得注意的是,如果使用了不等式查詢條件,會導致索引完全失效。而上一個例子中即使用了不等式條件,也使用了隱式類型轉換卻能用到索引。

    同理,根據最左前綴匹配原則,以下如果使用b,c作為查詢條件則不會使用(a, b, c)索引。

    執行語句:

    explain select * from test_table where b = "188466668888" and c = "23";

    執行結果:

    索引下推

    在說索引下推之前,我們先執行一下SQL。

    執行語句:

    explain select * from test_table where a = "zhangsan" and c = "23";

    上述的最左前綴匹配原則相信大家都能很容易的理解,那麼使用(a, c)條件查詢能夠利用(a, b, c)嗎?答案是肯定的,正如上圖所示。即使沒有索引下推也會會根據最左匹配原則,使用到索引中的a字段。有了索引下推之後會增加查詢的效率。

    在面試中通常會問到這樣一個問題,已知有索引(a,b,c)則根據條件(a,c)查詢時會不會走索引呢?答案是肯定的,但是是有版本限制的。

    而 MySQL 5.6 引入的索引下推優化(index condition pushdown), 可以在索引遍歷過程中,對索引中包含的字段先做判斷,直接過濾掉不滿足條件的記錄,減少回表次數,是對查詢的一種優化,感興趣的同學可以看一下官方說明https://dev.mysql.com/doc/refman/8.0/en/index-condition-pushdown-optimization.html。

    上述是沒有索引下推,每次查詢完之後都會回表,取到對應的字段進行匹配。

    利用索引下推,每次盡可能在輔助索引中將不符合條件數據過濾掉。比如,索引中已經包含了name和age,索引不妨暫且忽略破壞索引匹配的條件直接匹配。

    查詢優化-自適應索引順序

    查詢時,mysql的優化器會優化sql的執行,即使查詢條件的順序沒有按照定義順序來使用,也是可以使用索引的。但是需要注意的是優化本身也會消耗一定的性能,所以還是推薦按照索引的定義來書寫sql。

    explain select  * from test_table where b="12222222222" and a="zhangsan" and c = 23;
    explain select  * from test_table where a="zhangsan" and b="12222222222" and c = 23;

    4. 總結

    索引並不是什麼高深的技術,從底層來看,不過是一個數據結構罷了。要想使用好索引,一定要先將B+Tree理解透徹,在此基礎上對於日常使用和面試則是信手拈來。

    脫離業務的設計都是耍流氓,技術的意義在於服務業務。所以,索引的設計需要充分考慮業務的需求與設計原則之間做一些取捨,滿足需求是基礎。

    在工作中,各個公司的版本可能大不相同,會存在一些奇奇怪怪,不確定的問題。所以為了驗證索引的有效性,強烈推薦把主要的查詢sql都通過explain查看一下執行計劃,是否會用到索引。

    參考資料:
    [1] 《MySQL 45講》—極客時間
    [2] 《InnoDB存儲引擎》
    [3] 《高性能MySQL》
    [4] https://dev.mysql.com/doc/refman/8.0/en/

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

    【其他文章推薦】

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

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

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

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

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

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

    聚甘新

  • 車王電電動工具訂單貢獻續看升,能見度達明年4月

    車王電電動工具訂單貢獻續看升,能見度達明年4月

      車王電11月30日召開法說會,董事長蔡裕慶表示,目前電動工具訂單受惠於美國通路商挹注,產能滿載、訂單能見度看到2018年4月;此外,投資入股的華德動,預期在未來2年,可成為公司獲利金雞母。   蔡裕慶指出,看好電動車將是未來趨勢,新能源、儲能、電動巴士及汰役電池等,將是車王電未來經營重點。此外,華德動為是唯一可接受交通部補助的電動巴士廠商,其透過與日本住友等廠商,將電動巴士技術及供應鏈輸出至全球,預期未來2年,可望成為公司獲利金雞母。   另外,在電動工具部份,車王電表示,整體訂單能見度可看到明年4月,同時,預期第四季電動工具出貨將年成長3、4成,今年佔營收比重將從去年17%攀升至25%,且明年電動工具出貨更將比今年成長40%以上。     (本文內容由授權使用。首圖來源:華德動)  

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

    【其他文章推薦】

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

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

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

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

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

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

    聚甘新

  • 中國大陸公布電動車違規業者,市場趨緩?

    先前北京重金支持環保車,新能源車飆速成長,人人都想分杯羹。如今當局態度驟變、開始教訓業者,接連兩天公布違規廠商名單。北京政策大轉彎,新能源車恐怕會從生機蓬勃的春天一夕轉為料峭刺骨的寒冬。

    BusinessKorea、路透社報導,中國財政部8日懲處了至少五家車廠,指控他們的電動車和油電混合車計畫不實,非法取得人幣10億元補助,決定吊銷蘇州吉姆西客車製造(Suzhou Gemsea Coach Manufacturing)的生產執照,並對另外四家車廠處以罰款,其中包括中國第七大轎車廠奇瑞控股(Chery Holding)的子公司。

    專家指出,這表示中國新能源車政策出現劇變,中國企業工業協會(CAAM)副秘書長Xu Yanhua說,這對車業是一大打擊,對執法有重大影響。9日北京當局再次出擊,官媒中國證券報再公布了20家違規車廠,包括日本的日產汽車(Nissan)、韓國的現代汽車、中國的吉利汽車、江淮汽車(JAC)、比亞迪(BYD)子公司等。

    北京調查騙補,勢必會影響新能源車銷售,難以達到年度銷售70萬輛的目標。今年前八個月,新能源車僅售出24.5萬輛,和目標差距極大,當局又當頭澆下冷水,沒了補助誘因,車商更沒動力推出電動車,車市恐會驟然轉冷。

    台灣電動車概念股包括康普、F-貿聯、和大、F-乙盛、胡連、健和興、台達電等。

    北京政策急轉彎有跡可循,當局為了降低財庫負擔、促進技術發展,決定調整政策,未來擬降低補貼、拉高准入門檻,讓新能源車行業告別「野蠻生長」、迎來一輪優勝劣汰的洗牌。不過,這也意味著大陸目前超過200家的新能源車新創業者有超過9成5恐在兩年內被淘汰出局。

    大陸官營的人民日報8月27日報導,由於新能源車補貼政策的激勵和准入門檻較低,行業在快速發展的同時也產生不少問題,比如重複建設、低品質、同質化產品現象嚴重,甚至出現了企業騙補的情況。對此,財政部官員透露,近期將調整新能源汽車的補貼政策。中國已在去(2015)年超越美國成為全球最大新能源車(包括電動車、插電式油電混合車以及燃料電池車)市場。

    (本文內容由授權提供)

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

    【其他文章推薦】

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

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

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

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

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

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

    聚甘新

  • 001.OpenShift介紹

    001.OpenShift介紹

    一 OpenShift特性

    1.1 OpenShift概述


    Red Hat OpenShijft Container Platform (OpenShift)是一個容器應用程序平台,它為開發人員和IT組織提供了一個雲應用程序平台,用於在安全的、可伸縮的資源上部署新應用程序,而配置和管理開銷最小。

    OpenShift構建於Red Hat Enterprise Linux、Docker和Kubernetes之上,為當今的企業級應用程序提供了一個安全且可伸縮的多租戶操作系統,同時還提供了集成的應用程序運行時和庫。

    OpenShift帶來了健壯、靈活和可伸縮的特性。容器平台到客戶數據中心,使組織能夠實現滿足安全性、隱私性、遵從性和治理需求的平台。不願意管理自己的OpenShift集群的客戶可以使用Red Hat提供的公共雲平台OpenShift Online。

    1.2 OpenShift特性


    OpenShift容器平台和OpenShift Online都是基於OpenShift Origin開源軟件項目的,該項目本身使用了許多其他開源項目,如Docker和Kubernetes。

    應用程序作為容器運行,容器是單個操作系統內的隔離分區。容器提供了許多與虛擬機相同的好處,比如安全性、存儲和網絡隔離,同時需要的硬件資源要少得多,啟動和終止也更快。OpenShift使用容器有助於提高平台本身及其承載的應用程序的效率、靈活性和可移植性。

    OpenShift的主要特性如下:

    • 自助服務平台:OpenShift允許開發人員使用Source-to-Image(S21)從模板或自己的源代碼管理存儲庫創建應用程序。系統管理員可以為用戶和項目定義資源配額和限制,以控制系統資源的使用。
    • 多語言支持:OpenShift支持Java、Node.js、PHP、Perl以及直接來自Red Hat的Ruby。同時也包括來自合作夥伴和更大的Docker社區的許多其他代碼。MySQL、PostgreSQL和MongoDB數據庫。Red Hat還支持在OpenShift上本地運行的中間件產品,如Apache httpd、Apache Tomcat、JBoss EAP、ActiveMQ和Fuse。
    • 自動化:OpenShift提供應用程序生命周期管理功能,當上游源或容器映像發生更改時,可以自動重新構建和重新部署容器。根據調度和策略擴展或故障轉移應用程序。
    • 用戶界面:OpenShift提供用於部署和監視應用程序的web UI,以及用於遠程管理應用程序和資源的CLi。它支持Eclipse IDE和JBoss Developer Studio插件,以便開發人員可以繼續使用熟悉的工具,並支持REST APl與第三方或內部工具集成。
    • 協作:OpenShift允許在組織內或與更大的社區共享項目。
    • 可伸縮性和高可用性:OpenShift提供了容器多租戶和一個分佈式應用程序平台,其中包括彈性,以處理隨需增加的流量。它提供了高可用性,以便應用程序能夠在物理機器宕機等事件中存活下來。OpenShift提供了對容器健康狀況的自動發現和自動重新部署。
    • 容器可移植性:在OpenShift中,應用程序和服務使用標準容器映像進行打包,組合應用程序使用Kubernetes進行管理。這些映像可以部署到基於這些基礎技術的其他平台上。
    • 開源:沒有廠商鎖定。
    • 安全性:OpenShift使用SELinux提供多層安全性、基於角色的訪問控制以及與外部身份驗證系統(如LDAP和OAuth)集成的能力。
    • 動態存儲管理:OpenShift使用Kubernetes持久卷和持久卷聲明的方式為容器數據提供靜態和動態存儲管理
    • 基於雲(或不基於雲):可以在裸機服務器、活來自多個供應商的hypervisor和大多數IaaS雲提供商上部署OpenShift容器平台。
    • 企業級:Red Hat支持OpenShift、選定的容器映像和應用程序運行時。可信的第三方容器映像、運行時和應用程序由Red Hat認證。可以在OpenShift提供的高可用性的強化安全環境中運行內部或第三方應用程序。
    • 日誌聚合和metrics:可以在中心節點收集、聚合和分析部署在OpenShift上的應用程序的日誌信息。OpenShift能夠實時收集關於應用程序的度量和運行時信息,並幫助不斷優化性能。
    • 其他特性:OpenShift支持微服務體繫結構,OpenShift的本地特性足以支持DevOps流程,很容易與標準和定製的持續集成/持續部署工具集成。

    二 OpenShift架構

    2.1 OpenShift架構概述


    OpenShift容器平台是一組構建在Red Hat Enterprise Linux、Docker和Kubernetes之上的模塊化組件和服務。OpenShift增加了遠程管理、多租戶、增強的安全性、應用程序生命周期管理和面向開發人員的自服務接口。

    OpenShift的架構:



    • RHEL:基本操作系統是Red Hat Enterprise Linux;
    • Docker:提供基本的容器管理API和容器image文件格式;
    • Kubernetes:管理運行容器的主機集群(物理或虛擬主機)。它處理描述由多個資源組成的多容器應用程序的資源,以及它們如何互連;
    • Etcd:一個分佈式鍵值存儲,Kubernetes使用它來存儲OpenShift集群中容器和其他資源的配置和狀態信息。


    OpenShift在Docker + Kubernetes基礎設施之上添加了提供容器應用程序平台所需的更富豐的功能:

    OpenShift-Kubernetes extensions:其它資源類型存儲在Etcd中,由Kubernetes管理。這些額外的資源類型形成OpenShift內部狀態和配置,以及由標準 Kubernetes管理的應用程序資源;

    Containerized services:完成許多基礎設施功能,如網絡和授權。其中一些一直運行,另一些則按需啟動。OpenShift使用Docker和Kubernetes來實現大多數內部功能。即大多數OpenShift內部服務作為由Kubernetes管理的容器;

    Runtimes and xPaaS:供開發人員使用的 base image,每個image都預配置了特定的runtime或db。xPaaS提供了一組用於JBoss中間件產品(如JBoss EAP和ActiveMQ)的 base image;

    DevOps tools and user experience:OpenShift提供了Web UI和CLI管理工具,從而實現配置和監視應用程序、OpenShift服務和資源。Web和CLI工具都是由相同的REST api構建的,可供IDE和CI平台等外部工具使用。OpenShift 還可以訪問外部SCM存儲庫和容器registry,並將它們的構件引入OpenShift Cloud。

    OpenShift不會向開發人員和系統管理員屏蔽Docker和Kubernetes的核心基礎設施。相反,它將它們用於內部服務,並允許將Docker和Kubernetes資源導入OpenShift集群,同時原始Docker和資源可以從OpenShift集群導出,並導入到其他基於docker的基礎設施中。

    OpenShift添加到Docker + Kubernetes的主要價值是自動化開發工作流,因此應用程序的構建和部署在OpenShift集群中按照標準流程進行。開發者不需要知道底層Docker的細節。OpenShift接受應用程序,打包它,並將其作為容器啟動。

    2.2 Master和nodes


    OpenShift集群是一組節點服務器,它們運行容器,並由一組主服務器集中管理。服務器可以同時充當master和node,但是為了增加穩定性,這些角色通常是分開的。

    OpenShift工作原理和交互視圖:




    master節點運行OpenShift核心服務,如身份驗證,並未管理員提供API入口。

    nodes節點運行包含應用程序的容器,容器又被分組成pod。

    OpenShift master運行Kubernetes master服務和Etcd守護進程;

    node運行Kubernetes kubelet和kube-proxy守護進程。

    雖然在描述中通常沒有聲明,但實際上master本身也是node。

    scheduler和management/replication是Kubernetes主服務,而Data Store是Etcd守護進程。

    Kubernetes的調度單元是pod,它是一組共享虛擬網絡設備、內部IP地址、TCP/UDP端口和持久存儲的容器。pod可以是任何東西,從完整的企業應用程序(包括作為不同容器的每一層)到單個容器中的單個微服務。例如,一個pod,一個容器在Apache下運行PHP,另一個容器運行MySQL。

    Kubernetes管理replicas來縮放pods。副本是一組共享相同定義的pod。

    三 管理OpenShift

    3.1 OpenShift項目及應用


    除了Kubernetes的資源(如pods和services)之外,OpenShift還管理projects和users。一個projects對Kubernetes資源進行分組,以便用戶可以使用訪問權限。還可以為projects分配配額,從而限制了已定義的pod、volumes、services和其他資源。

    OpenShift中沒有application的概念,OpenShift client提供了一個new-app命令。此命令在projects中創建資源,但它們都不是應用程序資源。這個命令是為標準開發人員工作流配置帶有公共資源的proiect的快捷方式。

    OpenShift使用lables(標籤)對集群中的資源進行分類。默認情況下,OpenShift使用app標籤將相關資源分組到應用程序中。

    3.2 使用Source-to-image構建映像


    OpenShift允許開發人員使用標準源代碼管理倉庫(SCM)和集成開發環境(ide)來發布應用。

    OpenShift中的source -to-lmage (S2I)流程從SCM倉庫中提取代碼,自動判斷所需的runtime,基於runtime啟動一個pod,在pod中編譯應用。

    當編譯成功時,將在runtime image中添加層並形成新的image,推送進入OpenShift internal registry倉庫,接着基於這個image將創建新的pod,運行應用程序。

    S2I可被視為已經內置到OpenShift中的完整的CI/CD管道。

    CI/CD有不同的形式,根據具體場景表現不同。例如,可以使用外部CI工具(如Jenkins)啟動構建並運行測試,然後將新構建的映像標記為成功或失敗,將其推送到QA或生產。

    3.2 管理OpenShift資源

    OpenShift資源定義,如image、container、pod、service、builder、template等,都存儲在Etcd中,可以由OpenShift CLI, web控制台或REST API進行管理。

    OpenShift的資源科通過JSON或YAML文件查看,並且在類似Git或版本控制的SCM中共享。OpenShift甚至可以直接從外部SCM檢索這些資源定義。

    大多數OpenShift操作不需要實時響應,OpenShift命令和APIs通常創建或修改存儲在Etcd中的資源描述。Etcd然後通知OpenShift控制器,OpenShift控制器會就更改警告這些資源。

    這些控制器採取行動,以便使得資源的最終態反應達到更改效果。例如,如果創建了一個新的pod資源,Kubernetes將在node上調度並啟動該pod,使用pod資源確定要使用哪個映像、要公開哪個端口,等等。或者一個模板被更改,從而指定應該有更多的pod來處理負載,OpenShift會安排額外的pod(副本)來滿足更新后的模板定義。

    注意:雖然Docker和Kubernetes是OpenShift的底層,但是必須主要使用OpenShift CLi和OpenShift APls來管理應用程序和基礎設施。OpenShift增加了額外的安全和自動化功能,當直接使用Docker或Kubernetes命令和APls時,這些功能必須手動配置,或者根本不可用。因此強烈建議不要使用docker或Kubernetes的命令直接管理應用。

    四 OpenShift網絡

    4.1 OpenShift網絡概述


    Docker網絡相對簡單,Docker創建一個虛擬內核橋接器(docker0網卡),並將每個容器網絡接口連接到它。

    Docker本身沒有提供允許一個主機上的pod連接到另一個主機上的pod的方法。Docker也沒有提供嚮應用程序分配公共固定IP地址的方法,以便外部用戶可以訪問它。

    但Kubernetes提供service和route資源來管理pods之間的網絡,以及從外部到pods的路由流量。service在不同pods之間提供負載均衡用於接收網絡請求,同時為service的所有客戶機(通常是其他pods)提供一個內部IP地址。

    container和pods不需要知道其他pods在哪裡,它們只連接到service。route為service提供一個固定的惟一DNS名稱,使其對OpenShift集群之外的客戶端可見。

    Kubernetes service和route資源需要外部(功能)插件支持。service需要軟件定義的網絡(SDN),它將在不同主機上的pod之間提供通信,route需要轉發或重定向來自外部客戶端的包到服務內部IP。

    OpenShift提供了一個基於Open vSwitch的SDN,路由由分佈式HAProxy farm提供。

    五 OpenShift持久性存儲

    5.1 永久存儲


    pod可以在一個節點上停止,並隨時在另一個節點上重新啟動。同時pod的默認存儲是臨時存儲,通過對於類似數據庫需要永久保存數據的應用不適合。

    Kubernetes為管理容器的外部持久存儲提供了一個框架。Kubernetes提供了PersistentVolume資源,它可以在本地或網絡中定義存儲。pod資源可以使用PersistentVolumeClaim資源來訪問對應的持久存儲卷。

    Kubernetes還指定了一個PersistentVolume資源是否可以在pod之間共享,或者每個pod是否需要具有獨佔訪問權的自己PersistentVolume。當pod移動到另一個節點時,它將保持與相同的PersistentVolumeClaim和PersistentVolumne資源的關聯。這意味着pod的持久存儲數據跟隨它,而不管它將在哪個節點上運行。

    OpenShift向Kubernetes提供了多種VolumeProvider,如NFS、iSCSI、FC、Gluster或OpenStack Cinder。

    OpenShift還通過StorageClass資源為應用程序提供動態存儲。使用動態存儲,可以選擇不同類型的後端存儲。後面存儲根據應用程序的需要劃分為不同的“tiers”。例如,可以定義一個名為“fast”的存儲類和另一個名為“slow”的存儲類,前者使用更高速的後端存儲,後者提供普通的存儲。當請求存儲時,最終用戶可以指定一個Persistentvolumeclaim,並使用一個註釋指定他們所需的StorageClass。

    六 OpenShift高可用

    6.1 OpenShift高可用概述


    OpenShift平台集群的高可用性(HA)有兩個不同的方面:

    OpenShift基礎設施本身的HA(即主機);

    以及在OpenShift集群中運行的應用程序的HA。

    默認情況下,OpenShift為master提供了完全支持的本機HA機制。

    對於應用程序或“pods”,如果pod因任何原因丟失,Kubernetes將調度另一個副本,將其連接到服務層和持久存儲。如果整個節點丟失,Kubernetes會為它所有的pod安排替換節點,最終所有的應用程序都會重新可用。pod中的應用程序負責它們自己的狀態,因此它們需要自己維護應用程序狀態(如HTTP會話複製或數據庫複製)。

    七 Image Streams

    7.1 Image Streams


    要在OpenShift中創建一個新的應用程序,除了應用程序源代碼之外,還需要一個base image(S2I builder image)。如果源代碼或image任何一個更新,就會生成一個新的image,並且基於此新image創建新的pod,同時替換舊的pod。

    即當應用程序代碼發生更改時,容器映像需要更新,但如果構建器映像發生更改,則部署的pod也需要更新。

    Image Streams包括由tag標識的大量的image。應用程序是針對Image Streams構建的。Image Streams可用於在創建新image時自動執行操作。構建和部署可以監視Image Streams,以便在添加新image時接收通知,並分別執行構建或部署。

    OpenShift默認情況下提供了幾個Image Streams,包括許多流行的runtime和frameworks。

    Image Streams tag是指向Image Streams中的image的別名。通常縮寫為istag。它包含一個image歷史記錄,表示為tag曾經指向的所有images的堆棧。

    每當使用特定的istag標記一個新的或現有的image時,它都會被放在歷史堆棧的第一個位置(標記為latest)。之前tag再次指向舊的image。同時允許簡單的回滾,使標籤再次指向舊的image。 本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

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

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

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

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

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

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

    聚甘新

  • 服務設計思考:平台化

    服務設計思考:平台化

    平台是一套完整的服務。也是一套內部自洽的系統。核心在於分離,業務與通用服務隔離,業務與通用功能隔離。

    目標:

    • 對需求方: 快速響應。可以敏捷地進行需求迭代。

    • 對第三方業務方: 以產品的方式提供服務。所見即所得。所有功能對業務方透明。

    • 對測試方: 簡易明了的測試方式。利於自動化測試,灰度測試。

    • 對運維方: 持續集成,自動化編排,自動化部署。

    • 數據方: 提供多維度,詳盡的服務數據。可以給數據方提供簡便的數據分析。

    • 內部開發: 敏捷開發。迅速集成。

    實現:

    • 如何實現需求的快速響應?
      明確的方向,清晰的邊界。確認通用語言,核心領域。敏捷開發,快速迭代。AB 測試。

    • 如何為第三方提供產品式的服務?

      所見即所得。詳盡的文檔。第三方調試平台,第三方管理平台。

    • mock 服務,自動化測試,swagger 文檔。

    • Devops,CI,DI 等持續集成,服務監控。

    • 業務數據與分析數據異構存儲。提供易於分析的數據服務。

    • 組內服務負責制度,人類最佳的合作人數是 2-3 人。所以兩人維護一個項目,一人主導,一人輔助,兩人交叉合作是一個很好的團隊合作模式。如圖形成一個網狀模式(紅色線代表主導,黑色線輔助)。這樣每一個項目都將有兩個熟悉的人。

    原則

    1. 單一職責。
    2. 業務關注業務,功能關注功能。
    3. 確認邊界,確認核心領域。
    4. 所見即所得。

    實施

    如何推進業務開發快速響應?

    1. 抽離變化與不變。形成基礎服務

      如下面一套用戶體系,將服務抽離,將變與不變隔離。

      用戶 api: 主要提供用戶相關的接口,變化大,更偏向於業務;

      用戶中心: 主要管理用戶核心領域,變動不大,需穩定高可用的服務;

      鑒權授權中心: 變動不大,主要管理用戶憑證核心領域;

    1. 抽離通用功能。

      那些非業務的通用功能應隔離於業務之外:組件化工具化服務化

      來源監控接口限流日誌分析應用監控服務依賴配置管理系統部署等(業務人員不必關心這些功能相關的事情,只需要關注於具體的業務領域)。關注點分離。

      如上面所涉及的,從Spring Cloud的各大組件可以看出,最終的方案都將走上相近的道路。

    1. 領域上下文劃分。劃分微服務項目。業務隔離,數據去中心化。服務組件化。

      Spring cloud 技術棧:

      • 服務治理: 註冊中心,服務調用,衍生的容錯(熔斷器)
      • api 網關: 來源監控,接口限流(Spring Cloud gateway、zuul)
      • **配置中心: ** 配置管理(Apollo)
      • 自動化部署: Jenkins、docker、k8s
      • 日誌與監控: prometheus、influxdb、skywalking、elk
      • 數據可視化: druid、kylin、superset
    1. 細節管控

      接口版本管理, gitflow 管理,項目迭代 release 版本管理,標準化,敏捷開發。

    歡迎關注我的公眾號。

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

    【其他文章推薦】

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

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

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

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

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

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

    聚甘新

  • Spring Data 教程 – Redis

    Spring Data 教程 – Redis

    1. Redis簡介

    Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value 數據庫,並提供多種語言的API。Redis 是一個高性能的key-value數據庫。 redis的出現,在部分場合可以對關係數據庫起到很好的補充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。

    Redis支持主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹複製。存盤可以有意無意的對數據進行寫操作。由於完全實現了發布/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發布記錄。同步對讀取操作的可擴展性和數據冗餘很有幫助。

    redis的key都是字符串String類型,它的value是多樣化的,如下圖:

    redis數據類型 ENCODING返回的編碼 底層對應的數據結構
    string int long類型的整數
    string embstr embstr編碼的簡單動態字符串
    string raw 簡單動態字符串
    list ziplist 壓縮列表
    list linkedlist 雙向鏈表
    hash ziplist 壓縮列表
    hash ht 字典
    set intset 整數集合
    set ht 字典
    zset ziplist 壓縮列表
    zset skiplist 跳錶

    2. Redis的五種數據類型

    2.1 字符串對象(String)

    字符串對象的模型:

    redis底層提供了三種不同的數據結構實現字符串對象,根據不同的數據自動選擇合適的數據結構。這裏的字符串對象並不是指的純粹的字符串,数字也是可以的。

    • int:當數據是long類型的整数字符串時,底層使用long類型的整數實現。這個值會直接存儲在字符串對象的ptr屬性中,同時OBJECT ENCODING為int。

    • raw:當數據為長度大於44字節的字符串時,底層使用簡單動態字符串實現,說到這裏就不得不提下redis的簡單隨機字符串(Simple Dynamic String,SDS),SDS有三個屬性,free,len和buf。free存的是還剩多少空間,len存的是目前字符串長度,不包含結尾的空字符。buf是一個list,存放真實字符串數據,包含free和空字符。針對SDS本文不做詳細介紹,歡迎點擊SDS了解。

    • embstr:當數據為長度小於44字節的字符串時,底層使用embstr編碼的簡單動態字符串實現。相比於raw,embstr內存分配只需要一次就可完成,分配的是一塊連續的內存空間。

    2.2 列表對象(List)

    列表對象的模型:

    redis中的列表對象經常被用作消息隊列使用,底層採用ziplist和linkedlist實現。大家使用的時候當作鏈表使用就可以了。

    • ziplist

      列表對象使用ziplist編碼需要滿足兩個要求,一是所有字符串長度都小於設定值值64字節(可以在配置文件中修改list-max-ziplist-value字段改變)。二是所存元素數量小於設定值512個(可以在配置文件中修改list-max-ziplist-entries字段改變)。ziplist類似與python中的list,佔用一段連續的內存地址,由此減小指針內存佔用。

      zlbytes:占內存總數

      zltail:到尾部的偏移量

      zllen:內部節點數

      node:節點

      zlend:尾部標識

      previous_entry_length:前一節點的長度

      encoding:數據類型

      content:真實數據

      遍歷的時候會根據zlbytes和zltail直接找到尾部節點nodeN,然後根據每個節點的previous_entry_length反向遍歷。增加和刪除節點會導致其他節點連鎖更新,因為每個節點都存儲了前一節點的長度。

    • linkedlist

      linkedlist有三個屬性,head,tail和len。head指向鏈表的頭部,tail指向鏈表的尾部,len為鏈表的長度。

    2.3 哈希類型對象(Hash)

    哈希類型對象的模型:

    redis的value類型hash類型,其實就是map類型,就是在值的位置放一個map類型的數據。大家想詳細了解一下,可以參考一下這篇文章:https://www.jianshu.com/p/658365f0abfc 。

    2.4 集合對象(Set)

    集合對象類型的模型:

    Set類型的value保證每個值都不重複。

    redis中的集合對象底層有兩種實現方式,分別有整數集合和hashtable。當所有元素都是整數且元素數小於512(可在配置文件中set-max-intset-entries字段配置)時採用整數集合實現,其餘情況都採用hashtable實現。hashtable請移駕上文鏈接查閱,接下來介紹整數集合intset。intset有三個屬性,encoding:記錄数字的類型,有int16,int32和int64等,length:記錄集合的長度,content:存儲具體數據。具體結構如下圖:

    2.5 有序集合對象

    有序集合對象(zset)和集合對象(set)沒有很大區別,僅僅是多了一個分數(score)用來排序。

    redis中的有序集合底層採用ziplist和skiplist跳錶實現,當所有字符串長度都小於設定值值64字節(可以在配置文件中修改list-max-ziplist-value字段改變),並且所存元素數量小於設定值512個(可以在配置文件中修改list-max-ziplist-entries字段改變)使用ziplist實現,其他情況均使用skiplist實現,跳躍表的實現原理這裏偷個懶,給大家推薦一篇寫的非常好的博客,點擊查看跳躍表原理。

    3. Redis的安裝

    可以去官網或者中文網下載Redis。redis的windows版本現在已經不更新了,所以我們安裝redis的6.0.3版本,這個版本支持的東西很多,在此次教程中,我們只對redis的五種數據類型做解釋和學習。

    官網:https://redis.io/

    中文網:https://www.redis.net.cn/

    本教程安裝的redis版本為6.0.3版本,redis使用C語言編寫的,CentOS7的gcc自帶版本為4.8.5,而redis6.0+需要的gcc版本為5.3及以上,所以需要升級gcc版本。

    下載Linux版本的tar.gz包,解壓以後進入解壓產生的包:

    cd redis-6.0.3
    

    發現沒有bin目錄,這裏需要通過make進行安裝。

    # 先檢查gcc的環境 
    gcc -v 
    # 查看gcc版本 
    yum -y install centos-release-scl 
    # 升級到9.1版本 
    yum -y install devtoolset-9-gcc devtoolset-9-gcc- c++ devtoolset-9-binutils 
    
    scl enable devtoolset-9 bash 
    #以上為臨時啟用,如果要長期使用gcc 9.1的話: 
    echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile 
    # 進入redis解壓文件 
    make 
    # 6.0的坑,gcc版本 9.0 以上
    # 等待完畢
    

    執行完make操作之後,就可以在redis目錄看到src目錄了。進入src目錄后就可以看到redis-serverredis-cli

    這裏建議將Redis的配置文件複製,保留一份原生的配置文件。

    redis的配置大家可以在網上搜一下常用的配置,在這裏給大家推薦一個常用的配置,比較詳細:

    https://blog.csdn.net/ymrfzr/article/details/51362125

    到這裏redis就可以啟動並且正常訪問了。

    注意:一定要將redis的IP地址綁定註釋掉,允許所有的IP地址訪問,不然我們從Windows訪問就訪問不了。

    註釋掉下面的這一行:

    同時關閉Redis的服務保護模式,將protected-mode設置為no。如下:

    4. Spring Boot 整合 Redis

    • 4.1 搭建工程,引入依賴

      搭建工程的操作我這裏就不在寫出來了。直接上pom.xml

      <!--springboot父工程-->
      <parent>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-parent</artifactId>
          <version>2.2.2.RELEASE</version>
          <relativePath/> <!-- lookup parent from repository -->
      </parent>
      
      <dependencies>
          <!--springboot-web組件-->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-web</artifactId>
              <version>2.2.2.RELEASE</version>
          </dependency>
          <!--redis整合springboot組件-->
          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-redis</artifactId>
              <version>2.3.0.RELEASE</version>
          </dependency>
          <!--lombok組件-->
          <dependency>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
              <version>1.18.10</version>
          </dependency>
      </dependencies>
      
    • 4.2 redis的配置

      項目的配置文件,application.yml

      butterflytri:
        host: 127.0.0.1
      server:
        port: 8080 # 應用端口
        servlet:
          context-path: /butterflytri # 應用映射
      spring:
        application:
          name: redis # 應用名稱
        redis:
          host: ${butterflytri.host} # redis地址
          port: 6379 # redis端口,默認是6379
          timeout: 10000 # 連接超時時間(ms)
          database: 0 # redis默認情況下有16個分片,這裏配置具體使用的分片,默認是0
          jedis: # 使用連接redis的工具-jedis
            pool:
              max-active: 8 # 連接池最大連接數(使用負值表示沒有限制) 默認 8
              max-wait: -1 # 連接池最大阻塞等待時間(使用負值表示沒有限制) 默認 -1
              max-idle: 8 # 連接池中的最大空閑連接 默認 8
              min-idle: 0 # 連接池中的最小空閑連接 默認 0
      

      另外還有額外的配置類RedisConfig.java

      package com.butterflytri.config;
      
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.data.redis.connection.RedisConnectionFactory;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
      import org.springframework.data.redis.serializer.RedisSerializer;
      import org.springframework.data.redis.serializer.StringRedisSerializer;
      
      /**
       * @author: WJF
       * @date: 2020/5/24
       * @description: RedisConfig
       */
      
      @Configuration
      public class RedisConfig {
      
          /**
           * redis鍵值對的值的序列化方式:通用方式
           * @return RedisSerializer
           */
          private RedisSerializer redisValueSerializer() {
              return new GenericJackson2JsonRedisSerializer();
          }
      
          /**
           * redis鍵值對的健的序列化方式:所有的健都是字符串
           * @return RedisSerializer
           */
          private RedisSerializer redisKeySerializer() {
              return new StringRedisSerializer();
          }
      
          @Bean("redisTemplate")
          public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
              RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
              redisTemplate.setConnectionFactory(redisConnectionFactory);
              redisTemplate.setKeySerializer(redisKeySerializer());
              redisTemplate.setValueSerializer(redisValueSerializer());
              return redisTemplate;
          }
      
      }
      
    • 4.3 redisTemplate的使用

      value類型的值的CRUD:

      ValueServiceImpl.java

      package com.butterflytri.service.impl;
      
      import com.butterflytri.service.ValueService;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.stereotype.Service;
      
      import javax.annotation.Resource;
      
      /**
       * @author: WJF
       * @date: 2020/5/27
       * @description: ValueServiceImpl
       */
      @Service
      public class ValueServiceImpl implements ValueService {
      
          @Resource
          private RedisTemplate<String, Object> redisTemplate;
      
          @Override
          public void addValue(String key, Object value) {
              redisTemplate.opsForValue().set(key,value);
          }
      
          @Override
          public Object get(String key) {
              return redisTemplate.opsForValue().get(key);
          }
      
          @Override
          public Object update(String key, Object newValue) {
              return redisTemplate.opsForValue().getAndSet(key,newValue);
          }
      
          @Override
          public void delete(String key) {
              redisTemplate.delete(key);
          }
      }	
      

      List類型的值的CRUD:

      這裏我加了枚舉類型用來控制增加的位置,因為List類型對應的是鏈表。

      ListServiceImpl.java

      package com.butterflytri.service.impl;
      
      import com.butterflytri.enums.OpsType;
      import com.butterflytri.service.ListService;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.stereotype.Service;
      
      import javax.annotation.Resource;
      import java.util.List;
      
      /**
       * @author: WJF
       * @date: 2020/5/28
       * @description: ListServiceImpl
       */
      @Service
      public class ListServiceImpl implements ListService {
      
          @Resource
          private RedisTemplate<String, Object> redisTemplate;
      
          @Override
          public void addList(String key, List<Object> list, OpsType type) {
              switch (type) {
                  case RIGHT:
                      redisTemplate.opsForList().rightPushAll(key, list);
                      break;
                  case LEFT:
                      redisTemplate.opsForList().leftPushAll(key, list);
                      break;
                  default:
                      throw new RuntimeException("type不能為null");
              }
          }
      
          @Override
          public void add(String redisKey, Object value, OpsType type) {
              switch (type) {
                  case RIGHT:
                      redisTemplate.opsForList().rightPush(redisKey, value);
                      break;
                  case LEFT:
                      redisTemplate.opsForList().leftPush(redisKey, value);
                      break;
                  default:
                      throw new RuntimeException("type不能為null");
              }
          }
      
          @Override
          public List<Object> get(String key) {
              return redisTemplate.opsForList().range(key, 0, -1);
          }
      
          @Override
          public Object update(String key, Object value, Integer index) {
              Object obj = redisTemplate.opsForList().index(key, index);
              redisTemplate.opsForList().set(key,index,value);
              return obj;
          }
      
          @Override
          public void delete(String key) {
              redisTemplate.delete(key);
          }
      
          @Override
          public void deleteValue(String redisKey, OpsType type) {
              switch (type) {
                  case RIGHT:
                      redisTemplate.opsForList().rightPop(redisKey);
                      break;
                  case LEFT:
                      redisTemplate.opsForList().leftPop(redisKey);
                      break;
                  default:
                      throw new RuntimeException("type不能為null");
              }
          }
      }
      

      Hash類型的值的CRUD:

      hash類型是我們使用最常用的類型。

      HashServiceImpl.java:

      package com.butterflytri.service.impl;
      
      import com.butterflytri.service.HashService;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.stereotype.Service;
      
      import javax.annotation.Resource;
      import java.util.Map;
      
      /**
       * @author: WJF
       * @date: 2020/5/28
       * @description: HashServiceImpl
       */
      @Service
      public class HashServiceImpl implements HashService {
      
          @Resource
          private RedisTemplate<String, Object> redisTemplate;
      
          @Override
          public void addHashAll(String key, Map<String, Object> value) {
              redisTemplate.opsForHash().putAll(key, value);
          }
      
          @Override
          public void addHash(String redisKey, String key, Object value) {
              redisTemplate.opsForHash().put(redisKey, key, value);
          }
      
          @Override
          public Object get(String redisKey, String key) {
              return redisTemplate.opsForHash().get(redisKey, key);
          }
      
          @Override
          public Object update(String redisKey, String key, Object value) {
              Object obj = this.get(redisKey, key);
              this.delete(redisKey,key);
              redisTemplate.opsForHash().put(redisKey, key, value);
              return obj;
          }
      
          @Override
          public void delete(String redisKey, String key) {
              redisTemplate.opsForHash().delete(redisKey, key);
          }
      
          @Override
          public void deleteAll(String redisKey) {
              redisTemplate.delete(redisKey);
          }
      }
      

      Set的值的CRUD:

      package com.butterflytri.service.impl;
      
      import com.butterflytri.service.SetService;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.stereotype.Service;
      
      import javax.annotation.Resource;
      import java.util.Set;
      
      /**
       * @author: WJF
       * @date: 2020/5/28
       * @description: SetServiceImpl
       */
      @Service
      public class SetServiceImpl implements SetService {
      
          @Resource
          private RedisTemplate<String, Object> redisTemplate;
      
      
          @Override
          public void addAll(String key, Set<Object> set) {
              redisTemplate.opsForSet().add(key,set);
          }
      
          @Override
          public void add(String key, Object value) {
              redisTemplate.opsForSet().add(key,value);
          }
      
          @Override
          public Set<Object> findAll(String key) {
              return redisTemplate.opsForSet().members(key);
          }
      
          @Override
          public void deleteValue(String key, Object value) {
              redisTemplate.opsForSet().remove(key,value);
          }
      
          @Override
          public void delete(String key) {
              redisTemplate.delete(key);
          }
      }
      

      ZSet類型的值的CRUD:

      package com.butterflytri.service.impl;
      
      import com.butterflytri.service.SortedSetService;
      import org.springframework.data.redis.core.RedisTemplate;
      import org.springframework.stereotype.Service;
      
      import javax.annotation.Resource;
      import java.util.LinkedHashSet;
      
      /**
       * @author: WJF
       * @date: 2020/5/28
       * @description: SortedSetServiceImpl
       */
      @Service
      public class SortedSetServiceImpl implements SortedSetService {
      
          @Resource
          private RedisTemplate<String, Object> redisTemplate;
      
          @Override
          public void add(String key, String value, Double score) {
              redisTemplate.opsForZSet().add(key, value, score);
          }
      
          @Override
          public LinkedHashSet<Object> findAll(String key) {
              return (LinkedHashSet<Object>) redisTemplate.opsForZSet().range(key,0,-1);
          }
      
          @Override
          public Long count(String key, Double scoreFrom, Double scoreTo) {
              return redisTemplate.opsForZSet().count(key,scoreFrom,scoreTo);
          }
      
          @Override
          public LinkedHashSet<Object> findByScore(String key, Double scoreFrom, Double scoreTo) {
              return (LinkedHashSet<Object>) redisTemplate.opsForZSet().rangeByScore(key,scoreFrom,scoreTo);
          }
      
          @Override
          public Long rank(String key, Object value) {
              return redisTemplate.opsForZSet().rank(key,value);
          }
      
          @Override
          public void remove(String key, String value) {
              redisTemplate.opsForZSet().remove(key,value);
          }
      
          @Override
          public void delete(String key) {
              redisTemplate.delete(key);
          }
      
      }
      

      redis的Java客戶端有很多,在這裏我們使用的是jedis,還有一個很好的Java語言的客戶端叫lettuce,大家可以去了解一下,Spring從不重複造輪子,只會簡化輪子的使用,redisTemplate就是一個超級簡單的使用實現。到這裏redis整合Spring Boot 就結束了。

    5. 項目地址

    本項目傳送門:

    • GitHub —> spring-data-redis
    • Gitee —> spring-data-redis

    此教程會一直更新下去,覺得博主寫的可以的話,關注一下,也可以更方便下次來學習。

    • 作者:Butterfly-Tri
    • 出處:Butterfly-Tri個人博客
    • 版權所有,歡迎保留原文鏈接進行轉載

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

    【其他文章推薦】

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

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

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

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

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

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

    聚甘新

  • 氣候模擬:廣設風光發電 有助撒哈拉沙漠綠化

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

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

    【其他文章推薦】

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

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

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

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

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

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

    聚甘新

  • 特斯拉自駕車晶片 傳將改由三星代工

    特斯拉自駕車晶片 傳將改由三星代工

    三星搶攻車用晶片商機再下一成,產業界消息傳出,三星電子成功打入特斯拉電動車供應鏈,雙方已簽署特殊應用晶片(ASIC)代工合約。

    按照合約內容,三星將按特斯拉的特殊規格,量身設計、生產客製化系統單晶片(SOC),將應用於無人駕駛車上。據估計,三星從晶片開發到量產,須要約三年時間。(韓國經濟日報)

    此前,特斯拉自駕車晶片都是由以色列Mobileye所提供,但今年五月特斯拉電動車主在自駕模式出了意外身亡,才讓特斯拉動了尋找替代供應商的念頭。

    另外,三星正在考慮將旗下系統LSI部門分拆成設計與代工兩個事業單位,原因是顧慮到特斯拉擔心三星可能將晶片設計應用在自家產品上。

    (本文內容由 授權提供。照片來源: shared by CC 2.0)

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

    【其他文章推薦】

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

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

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

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

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

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

    聚甘新