2021年12月12日 星期日

rocketMQ 4.x

下載點

文件

控制台:就是有畫面可以操作


※啟動注意事項

此文章使用的是 Windows 的 rocketMQ,使用 java8 可以跑得起來,但不能安裝在有空格的路徑,如 Program Files,網上有說用字串包起來可以解決,但我試不成功,但可以用 PROGRA~1 解決

9 10 不是 LTS 版,我沒試過,而 11 會出現 JVM 參數已經沒有的問題,會跑不起來,雖然網路上也有將沒有的 JVM 參數註解掉,但我試還是不成功

windows 要執行副檔名是 cmd 的;linux 要執行 sh 的

mqnamesrv.cmd 啟動 name server,內部會執行 runserver.cmd

mqbroker.cmd 啟動 broker,內部會執行 runbroker.cmd

以上這兩個用文件編輯器可打開查看,其中需要 ROCKETMQ_HOME 變數,所以要設環境變數

-Xms2g -Xmx2g 可以設小一點,設 256m 就夠測試了

我設的是 ROCKETMQ_HOME=C:\Users\bruce\Downloads\rocketmq-4.9.2,要在 bin 的上一層,最後在放到 path 裡,然後後面加上 bin

然後先啟動 name server,後啟動 broker,啟動成功畫面如下:


以上的命令可在官網的文件複製


※測試生產消費

啟好了之後,試試能不能生產和消費,官網說要設定 NAMESRV_ADDR="localhost:9876"

所以再開啟命令提示字元,set NAMESRV_ADDR=localhost:9876,官網前後有字串,但我試的結果不行,注意 set 設定的變數只有在這個視窗有效,要永久就要在環境變數裡設定

設定好之後,tools.cmd  org.apache.rocketmq.example.quickstart.Producer 就會看到畫面一直跑,

接著是消費者,再開一個命令提示字元,如果變數是暫時的,還要在設定 NAMESRV_ADDR,打上 tools.cmd  org.apache.rocketmq.example.quickstart.Consumer,就會看到開始消費了



※啟動主控台

就是這文章最上面的控制台,使用 ide 打開後,可改兩個地方,如下:


rocketmq.config.namesrvAddr 要設定 name server 的地址; server.port 可以改成這個主控台想要的 port

server.port 預設是 8080;rocketmq.config.namesrvAddr 預設是 localhost:9876

然後下 mvn clean package -Dmaven.test.skip=true,成功後會在 target 裡生成一個 jar

執行這個 jar,java -jar xxx.jar 即可啟動,在瀏覽器打上 localhost:8080


看到這畫面表示成功了啟動了,再生產一次資料後,可在 Message 活頁標籤裡搜尋 Topic 是   TopicTest 的,可以看到生產的資料


※關閉 name server 和 broker

和啟動相反,先關閉 broker,再關閉 name server

mqshutdown.cmd broker

mqshutdown.cmd namesrv 



※broker 的雙主雙從等

在 rocketMQ 目錄有個 conf,裡面有三個資料夾

2m-2s-async:雙主雙從加異步

2m-2s-sync:雙主雙從加同步

2m-noslave:雙主

在啟動 broker 時可以加上 -c 的參數,後面加檔案路徑,就可以抓到裡面的設定,但裡面的設定還不是很多,可到官網查看


※Message

這個是傳訊息要用到的 class

tag 可以再 topic 裡在過濾一層,如生產時 topic 是 animal,tag 有 cat、dog…等,消費者可以針對某一個 tag 進行過濾,如 tag 給 dog,就只抓 dog,給 * 會全抓

key 是用戶端自己生成的,可以把它寫成唯一 id



※持久化資料

windows 在 %userProfile%\store

commitlog:真正存資料的地方,預設一個檔案 1G

consumequeue:用 topic 區分,連到 commitlog 的索引,消費者群組來這裡找資料的

index:如果在生產時有給 key 就可以利用這個 key 和時間區間來找資料



※Queue 數量

預設的數量是 4,可以使用 producer.setDefaultTopicQueueNums 修改,但如果已經有 topic 改不了,所以是 setDefault,因為資料在讀或寫的時候,更改這個值會有影響,要用下面要說的 writeQueueNums 和 readQueueNums 

已經有 topic,可以刪除或修改,但要在控制台操作,如下:

每個橫條都是一個 topic,最右的按鈕可以刪除 topic

status 按鈕可以看有幾個 queue

topic config 按鈕可以修改幾個 queue,如下:


perm 有三種值 2 4 6,分別是可寫可讀可讀寫

writeQueueNums 是 Queue 的數量,改好可到 status 查看

通常 writeQueueNums 和 readQueueNums 都是設成一樣的,只有在擴容或縮容時才會不一樣

假設 writeQueueNums 4; readQueueNums 8 會有 4 個消費者消費不到,想擴容時可暫時這樣設定

假設 writeQueueNums 8; readQueueNums 4 會有 4 個 queue 沒有消費,想縮容時可暫時這樣設定


※消費者組、主題、tag

當設定完消費者組、主題、tag 後,消費者組就會開始監聽,但只要同一個消費者組,不管主題、tag 是什麼都會收到資料,所以有可能收錯資料,而另一個資料丟失

正確的做法是消費者組、主題、tag 都要一樣,要訂閱不同主題時,也要用新的消費者組



※刷盤和複製策略

在下載好的 rocketmq\conf\broker.conf 有如下的設定

brokerRole = ASYNC_MASTER,表示異步複製,改同步只要去掉 A 即可,而 SLAVE 是接受方

flushDiskType = ASYNC_FLUSH,表示異步刷盤,改同步只要去掉 A 即可

這兩個預設都是異步的


複製策略

brokerRole 表示 MASTER 複製給 SLAVE 用什麼方式

1. ASYNC_MASTER 消息在記憶體並寫到 master 的硬碟後就回應,然後再寫到 slave

所以在還沒寫到硬碟時,忽然網路延遲或斷電,但生產者會以為已經送到 broker 了,這時會造成 slave 資料丟失

2. SYNC_MASTER 收到消息並寫到 master 和 slave 的硬碟後才回應已完成

3. SLAVE 接收 MASTER 的資料


刷盤策略

flushDiskType 表示消息在記憶體,寫入硬碟的方式

1. ASYNC_FLUSH 消息在記憶體就回應,然後再寫到碟碟

所以忽然網路延遲或斷電,就會認為沒有刷盤成功,然後再送出資料給消費者,造成消息重覆

2. SYNC_FLUSH 記憶體寫到硬碟後再回應



※Queue 和消費者

1.同個消費者組下的消費者可以消費同個主題的不同 queue;但同個主題的同個 queue 不能被多個消費者消費


如果想一個 queue 對應一個消費者,在 spring boot 裡,可以用

@RocketMQMessageListener(

    consumerGroup = "myConsumerGroup",

    topic = "myTopic",

    selectorExpression = "myTag",

    consumeMode = ConsumeMode.ORDERLY,

    consumeThreadMax = 1)

ConsumeMode.ORDERLY 表示一個 queue 對應一個消費者,注意原碼的註解 one queue, one thread,並不是指一個 thread,要指定一個 thread 要用下面的 consumeThreadMax = 1

consumeThreadMax 的數量是指藍色的線



2.不同消費者組下的消費者可以同時消費同個主題的同個 queue




3.同個消費者組下的消費者不可以同時消費不同 topic 的 queue






2021年12月10日 星期五

Mongodb

 官網連結


enterprise 需要錢,community 不用錢

下載解壓安裝,安裝過程會問要不要再安裝 compass,這個是 gui 工具,看要不要安裝或者安裝自己熟悉的 gui 工具,mongodb://127.0.0.1:27017 可以連自己的,但下面的 mongod 要執行成功

完成後,看要不要設定環境變數

啟動用 mongod,但會出現錯誤,說路徑要有 c:\data\db,自行創建後,啟動成功

或者用參數  mongod --dbpath 資料夾路徑名,這樣就可以使用自己喜歡的資料夾

port 預設是 27017,想改可用 mongod --port 2222,這要就可以改 port

然後再開一個視窗,打上 mongo 或 mongo --port 27017 即可連線,出現「>」表示連現成功


database 資料庫

collection 集合

document 文件

資料庫和集合不用手動創建,直接 use 名稱即可,在新增文件時,會自動新增資料庫和文件

show dbs 或 shw databases 看有什麼資料庫

db 看目前在哪個資料庫

show collections 或 show tables看當前資料庫有什麼集合


官方開發文件

新增文件 db.<collection>.insertOne   insertMany

 db.zoo.insertOne(name:"monkey");  zoo 是這行才開始新增的 collection,如果資料庫沒新增也會一併新增,insertOne 裡的 bson 就是 document

其他 deleteOne、deleteMany、updateOne、updateMany、find 都看官方文件即可


※NoSQLBooster for MongoDB

這也是個 IDE


projection 是投影的意思,在這裡表示哪些欄位要顯示,1顯示,0不顯示

另一種方法是將 document 寫在 find 的第二個參數裡,這樣就不用寫 projection 了



※索引

預設 _id 是 PK,就已經是索引了

db.<collection>.createIndex(

  { field1: 1 } ,

  { field2: -1 }

);

對 field1 做正序,對 field2 做倒序

查看 index: db.<collection>.getIndexes();


如圖,表示有兩個索引,key 為索引的欄位名稱,第二個是我建的複合索引


查看執行計畫,官方文檔

db.<collection>.explain("queryPlanner");

裡面可以寫三種值 queryPlanner、executionStats、allPlansExecution

看結果的 winningPlan,有個 stage,如下


stage 包括五種

COLLSCAN:掃描 collection,全表掃描的意思

IXSCAN:掃描 index,表示吃到索引了

FETCH:用於檢索文件

SHARD_MERGE:用於合併分片的結果

SHARDING_FILTER:用於從分片中過濾掉孤立文件


2021年10月2日 星期六

LBCC 和 MVCC

 LBCC (Lock Base Concurrency Control) 基於鎖的併發控制

英文文件中文文件

※行鎖鎖的是索引,沒索引會變成表鎖,有 PK 會自動有主鍵索引

SELECT * FROM bruce_test.bruce_tbl where id = 1 for update; 假設沒主鍵,第一個 session 鎖住後,不管資料庫有沒有資料都會鎖表,所以 SELECT * FROM bruce_test.bruce_tbl for update; 會阻塞

※自動提交

SET AUTOCOMMIT=0; # 關閉自動提交

show variables like 'autocommit';

※關閉不可寫的指令 

SET SQL_SAFE_UPDATES=0; # 這樣才可以新增、修改、刪除

show variables like 'sql_safe_updates';

※開啟事務 

START TRANSACTION 或 BEGIN

※回滾和提交

ROLBACK、COMMIT

※隔離等級

# READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE

mysql 預設是 REPEATABLE-READ

set session transaction_isolation='REPEATABLE-READ'; # 不寫 session 也行,預設就是 session

set global transaction_isolation='REPEATABLE-READ';

SELECT @@global.transaction_isolation;

SELECT @@session.transaction_isolation;

兩個 session 隔離等級不同,如 A 是 READ-UNCOMMITTED,B 是 READ-COMMITTED,以自己設定的為準,A 讀 B 的會有髒資料;相反則不會


紅框為同一個 session,如果改了活頁籤其中一個,同一個 session 都會改到;綠框為不同 session,mysql workbench 要在圖的下方再按一次就會出現


※準備測試資料

CREATE TABLE `bruce_tbl` (

  `id` int DEFAULT NULL,

  `name` varchar(10) DEFAULT NULL,

  KEY `id_index` (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;


INSERT INTO bruce_test.bruce_tbl (`id`,`name`) VALUES (1,'abc');

INSERT INTO bruce_test.bruce_tbl (`id`,`name`) VALUES (5,'bbb');

INSERT INTO bruce_test.bruce_tbl (`id`,`name`) VALUES (9,'ccc');

INSERT INTO bruce_test.bruce_tbl (`id`,`name`) VALUES (11,'ddd');


以下的測試是用 8.0.23 版

以下的測試都是用鎖的,如 selec * from table 是沒有鎖的,不管怎樣都可以執行的,不在這裡說明的範圍

以下的測試第一次都要先 SET AUTOCOMMIT=0; 而且還要執行 start transaction 或 begin 再執行以下要測試的語句,然後都測試完後,再 rollback 或 commit


※exclusive locks 排他鎖、shared locks 共享鎖

排他鎖:在 select 最後加 for update、增刪改

共享鎖:在 select 最後加 for share 或 lock in share mode,但後者還可以有更多選項,如會阻塞就直接返回

排他鎖只能一個,一個 sql 取得了排他鎖,其他的鎖都會阻塞要查的出資料才有鎖

共享鎖可以多個,但不能有排他鎖,要查的出資料才有鎖

測試排他鎖:

A session:

SELECT * FROM bruce_test.bruce_tbl where id = 1 for update; # 執行到這裡先停,然後執行 B session


B session:

SELECT * FROM bruce_test.bruce_tbl where id = 1 for update; # 會阻塞

SELECT * FROM bruce_test.bruce_tbl where id = 5 for update; # 不會阻塞

# 資料庫的 id 有四筆,1 5 9 11,如果不是這四個值也不會阻塞


測試共享鎖:

A session:

SELECT * FROM bruce_test.bruce_tbl where id = 1 for share;


B session:

SELECT * FROM bruce_test.bruce_tbl where id = 1 for share; # 不會阻塞

SELECT * FROM bruce_test.bruce_tbl where id = 1 for update; # 會阻塞


※Intentioin locks 意向鎖

分成意向共享鎖和意向排他鎖,都是表鎖,無法人工增加,是 mysql 自動幫我們加上的

事務要取得排他鎖先取得意向鎖排他鎖;事務要取得排他鎖要先取得意向共享鎖

意向鎖目的是為了加快效能,如某一行被 for update,就表示有意向排他鎖和排他鎖,另一個 session 想鎖這張表 (lock tables talble_name read) 會發現有意向排他鎖,就知道有其中一行被鎖了,這樣就不用一行一行去找哪一行被鎖了 

這兩個鎖都可以多個而且互相都是相容的

以下是官網截出來的表,IX 表示意向排他鎖;IS 表示意向共享鎖,指的都是表鎖,共享和排他的例子鎖的是行,mysql 是可以同時有表鎖和行鎖的


首先看直的,排他鎖只能有一個,所以全部都是 confilict

再來是共享鎖,可以多個共享鎖和意向共享鎖,其他有排他的都不行

意向共享除了排他外都是可以的

意向排他只能和意向排他和意向共享,其他都不行,連共享鎖也不行



※record locks 記錄鎖

測試方法同測試排他鎖


※gap locks 間隙鎖

隔離等級為 RR 才有用,範圍條件裡沒有命中記錄時為間隙鎖,不能新增記錄,但可以用排他鎖查詢,因為都是沒有記錄的範圍

  ● A 是 RR,B 是 RC,A 的範圍沒有記錄,會有間隙鎖,這時 B 想新增範圍裡的資料會等待

  ● 資料庫的 id 是 1 5 9 11

測試一 A session:

SELECT * FROM bruce_test.bruce_tbl where id > 5 and id < 9 for update; # 這個範圍裡資料庫沒有資料才能叫間隙鎖


測試一 B session:

SELECT * FROM bruce_test.bruce_tbl where id = 8 for update;

主鍵索引:都沒鎖

唯一索引:5不會鎖,鎖的是 9

普通索引:5不會鎖,鎖的是 9


insert into bruce_test.bruce_tbl (id, name) values (5, 'xxx');

主鍵索引:鎖的是 6~8,也就是 where 的範圍

唯一索引:鎖的是 6~9

普通索引:鎖的是 5~8


測試二 A session:

SELECT * FROM bruce_test.bruce_tbl where id > 15 for update;


測試二 B session:

insert into bruce_test.bruce_tbl (id, name) values (11, 'xxx'); 

# 主鍵索引:鎖 12(含)之後

# 唯一索引:鎖 12(含)之後

# 普通索引:鎖 11(含)之後


寫的很好的文章


※next-key locks 臨鍵鎖

為記錄鎖 + 間隙鎖,隔離等級為 RR 才有用

  ●  假設資料庫的 id(index) 是 1 5 9 11,這時 id > 5 and id < 10,除了不能新增外也不可用排他鎖

A session:

SELECT * FROM bruce_test.bruce_tbl where id > 5 and id < 10 for update;


B session:

SELECT * FROM bruce_test.bruce_tbl where id = 11 for update;

# 主鍵、唯一、普通索引都是鎖 9 和 11,不鎖 5


insert into bruce_test.bruce_tbl (id, name) values (8, 'xxx');

# 主鍵索引:鎖 6~10

# 唯一索引:鎖 6~11

# 普通索引:鎖 5~10


測試二 A session:

SELECT * FROM bruce_test.bruce_tbl where id > 5 for update;


測試二 B session:

SELECT * FROM bruce_test.bruce_tbl where id = 9 for update;

# 主鍵、唯一、普通索引都是鎖 9 和 11,不鎖 5


insert into bruce_test.bruce_tbl (id, name) values (9, 'xxx');

# 主鍵索引:鎖 6(含) 以上

# 唯一索引:鎖 6(含) 以上

# 普通索引:鎖 5(含) 以上



MVCC (Multi-Version Concurrency Control) 多版本併發控制

snapshot read 快照讀:像照相機一樣照起來,以後資料都從這邊拿

current read 當前讀:直接去資料庫拿,所以拿的都是最新的資料

在兩個讀之間有增刪改其中之一,會觸發當前讀

目的是想解決幻讀,但必竟隔離等級是 RR,不是 SERIALIZABLE,所以只解決了一部分,在第一次讀的時候用的是快照讀,之後其他 session 新增了記錄,此時在查詢一次並不會產生新的記錄,會有問題的如下:


測試:

A session:# 執行第一行後時先停一下,然後執行 B session,然後再繼續

SELECT * FROM bruce_test.bruce_tbl where id = 1; # 假設查出來的 name 是 aaa

update bruce_test.bruce_tbl set name = CONCAT(name, '123') where id = 1; # 這行產生了讀已提交的資料

SELECT * FROM bruce_test.bruce_tbl where id = 1; # sesion 還沒結束,name 應該要是 aaa123,但確變成了 abc123,因為觸發了當前讀


B session:

update bruce_test.bruce_tbl set name = 'abc' where id = 1; # 直接提交

2021年8月15日 星期日

浮點數

 整數的 1/0 會出 by zero 的例外,但浮點數不會,有三種型式,「/」左右邊其中一個是 .0 就不會出錯了

1.0/0.0 = Infinity (正無限)

-1.0/0.0 = -Infinity (負無限)

0.0/0.0 = NaN (非數字)

Math.sqrt(-2) = NaN (只要是負數就會 NaN,但 0 沒關係)

其中只有 NaN 不等於自己,所以 Float 和 Double 的 isNaN 原碼如下:

public static boolean isNaN(float v) {return (v != v);}

public static boolean isNaN(double v) {return (v != v);}


isInfinite 是否是正無限或負無限 (不包括 NaN)

isFinite 只要不是正無限、負無限、NaN 其中之一就會回傳 true



IEEE 754

程式用的是 IEEE 754 的規則,維基連結

會將浮點數分成三部分

sign + exponent + fraction => 正負數+指數+小數,sign 佔一位,0是正數;1是負數

Float 32 位元為 1 + 8 + 23,指數(10進位)要加 127

Double 64位元為 1 + 11 + 52,指數(10進位)要加 1023

指數的正規化:整數只留一位,而且一定是 1,假設 10 進位是 0.5,轉成二進位是 0.1,第一個必需是 1,所以要改成 1 * 2^-1 次方

0 01111110 00000000000000000000000 中間的是 -1 + 127  = 126 的二進位


Infinity 正無限:0 + 指數全是 1 + 小數全是 0

-Infinity 負無限:1 + 指數全是 1 + 小數全是 0

NaN 非數字:指數全是 1 + 小數不是 0,java 定義為 指數全是 1 + 小數第一個是 1 後面都是 0


※驗證:

一、以 8.5 為例,轉二進制不會循環,1000.1 轉成左邊只有一位 => 1.0001 * 2^3 (二的3次方,3是指數)

32 位元 (可用 Float.floatToIntBits(8.5F) 驗證):

0 3+127 0001000...

0 10000010 0001+19個0 => 01000001000010000000000000000000 => 1091043328


64位元(可用 Double.doubleToLongBits(8.5) 驗證)

0 3+1023 00010000000...

0 10000000010 (1後8個0) 0001+48個0 => 0100000000100001000000000000000000000000000000000000000000000000 => 4620974692658839552


二、以 12.4 為例,轉二進制會循環,1100.0110 0110 0110...(0110 沒完沒了) => 1.1000110 0110 0110...*2^3

只舉例 32 位元,看懂了自己算算看 64 位元

0 3+127 1000110 0110 0110 0110....

0 10000010 1000110 0110 0110 0110 0110 => 01000001010001100110011001100110 => 1095132774


三、正負無限

32位元

0 + 8個1 + 23個0 01111111100000000000000000000000 --> 7F800000

1 + 8個1 + 23個0 11111111100000000000000000000000 --> FF800000


64位元

0 + 11個1 + 52個0 0111111111110000000000000000000000000000000000000000000000000000 --> 7FF0000000000000

1 + 11個1 + 52個0 1111111111110000000000000000000000000000000000000000000000000000 --> FFF0000000000000


四、NaN

32位元

0 + 8個1 + 頭一個是1後面都是0

01111111110000000000000000000000 --> 7FC00000


64位元

0 + 11個1 + 頭一個是1後面都是0

0111111111111000000000000000000000000000000000000000000000000000

7FF8000000000000





2021年3月1日 星期一

Intellij 反組譯

 File --> Settings

重啟後,就有反組譯功能了


到安裝 IntelliJ 的地方有個 plugins,我的是 C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.2.3\plugins\java-decompiler\lib

開啟 cmd,用最高權限開

cd 上面的路徑後,下 java -cp java-decompiler.jar org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true ooo.jar xxx

其中 ooo.jar 是想反組譯的 jar,xxx 是資料夾,必需先建,建在 cd 路徑的下層,下完指令後,反組譯的 .java 檔會在裡面

成功的畫面:



2021年2月18日 星期四

sentinel + gateway

一、sentinel 下載

啟動命令:java -Dserver.port=9090 -jar sentinel-dashboard-1.8.1.jar
這裡和只有 sentinel 時一模一樣

二、maven

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>


三、設定檔

server:
port: 8057
spring:
application:
name: sentinel-gateway-cloud
main:
allow-bean-definition-overriding: true # 因為報錯的提示,才加的
cloud:
sentinel:
transport:
port: 8719
dashboard: localhost:9090 #對應 sentinel port
eager: true
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
routes:
- id: sentinel_gateway_bruce
uri: lb://provider-cloud
predicates:
- Path=/xxx/**
filters:
- StripPrefix=1

※以上可以寫在 application.yml 或 nacos 之類的伺服器上


四、啟動

啟動專案時要加上 VM 參數 -Dcsp.sentinel.app.type=1


左邊是整合後的畫面;右邊是沒有整合的畫面

2021年2月15日 星期一

Mysql8 主從複製(Windows)

 一、安裝完注意事項

mysql 安裝完後,執行打 services.msc


在紅框按右鍵內容,綠框的路徑有 my.ini,有改過想生效要按紅框右鍵的重新啟動,我的路徑如下:

"C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe" --defaults-file="C:\ProgramData\MySQL\MySQL Server 8.0\my.ini" MySQL80

注意 ProgramData 是隱藏資料夾,注意 [mysqld] 裡的 server-id 預設是 1,主和從必需不一樣

主還要在 [mysqld] 增加 binlog-do-db=bruce_test,bruce_test 為想複製的資料庫名稱,複製時是從當下複製,之前有的不會複製

如果有多個資料庫要複製,要寫多個 k=v,不是加逗號


二、網路

我使用 Oracle VM VirtualBox,必需先 ping 通

網路可以使用橋接介面卡或 NAT,兩個都是主機可上網就可以上網,但使用 NAT 時,虛擬機之間不能連線;而橋接都可以

關防火牆或開 port 使機器可以 ping 通


三、讓從機連主機

※主

SELECT * FROM mysql.user; 

可以看到所有使用者和權限

host 欄位:表示什麼 IP 可以連到 mysql server,預設是 localhost,將想給別人用的帳號(主)的 host 內容改成從的 IP,或者用 %,表示任何 IP 都可以連

plugin 欄位:預設是 caching_sha2_password,改成 mysql_native_password 才能被連



也可以新增使用者,這個使用者是要給從的 mysql 連的帳號

CREATE USER '帳號'@'%' IDENTIFIED BY '密碼';

ALTER USER '帳號'@'%' IDENTIFIED BY '密碼';

GRANT REPLICATION SLAVE ON *.* TO '帳號'@'%';

ALTER USER 'aaa'@'%' IDENTIFIED WITH mysql_native_password BY 'aaa';


update mysql.user set host='%' where user='root'; //aaa

show variables like '%safe_updates%';

SET SQL_SAFE_UPDATES=0;  // 預設安全性是開的(1),所以不能下修改的語法

FLUSH PRIVILEGES; // 改完後要重整

show master status; // 每次 flush privileges 後會不一樣


從機會用到 File 和 Position 欄位,Binlog_Do_DB 是要複製的資料庫、Binlog_Ignore_DB 是要忽略的資料庫


※從

從機打指令要下如下的語法才能連

mysql -uroot -p -h192.168.1.104 -P3306 --default-auth=mysql_native_password

mysql 指令在安裝目錄底下的 bin,也可增加環境變數

我的在 C:\Program Files\MySQL\MySQL Server 8.0\bin

有些語法在這一版還能用,但已經 deprecated 了,下面的語法,有註解的是 deprecated

// stop slave;
stop replica;


// change master to master_host='192.168.1.104',master_port=3306,master_user='bbb',master_password='bbb',master_log_file='BRUCE-HOME-bin.000015',master_log_pos=2357;

// 用 SOURCE_USER 和 SOURCE_PASSWORD 會有警告
CHANGE REPLICATION SOURCE to SOURCE_HOST='192.168.1.104',SOURCE_PORT=3306,SOURCE_USER='bbb',SOURCE_PASSWORD='bbb',SOURCE_LOG_FILE='BRUCE-HOME-bin.000015',SOURCE_LOG_POS=2357;

CHANGE REPLICATION SOURCE to SOURCE_HOST='192.168.1.104',SOURCE_PORT=3306,SOURCE_LOG_FILE='主的 FIle',SOURCE_LOG_POS=主的 Position;

// start slave;
start replica USER='bbb' PASSWORD='bbb';

show slave status; // 命令提示字元最後加個 \G,會比較好看
Slave_IO_Running 和 Slave_SQL_Running 為 Yes 就正確了
Slave_SQL_Running 為 No,通常都是 SOURCE_LOG_FILE、SOURCE_LOG_POS 不正確,要對應主的設定
Slave_IO_Running 為 Connecting 通常都是連線不正確,密碼錯誤、網路問題,還有主的一定要改成 mysql_native_password

如果有錯 last_sql_error、last_io_error 可以看到錯誤訊息
有錯要改必需先 stop replica --> 修改 --> start replica


主從複製在主機新增資料庫、表並 insert,從機也能看到就正確了,而在從機做的只有在從機能看到

2021年1月16日 星期六

SpringBoot 整合 Flyway

 maven:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>


yml:

spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/flyway_db?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: 123456
jpa:
show-sql: true
flyway:
enabled: true # flyway 的開關,一關就等同沒有 flyway
url: ${spring.datasource.url}
user: ${spring.datasource.username}
password: ${spring.datasource.password}
locations: classpath:db/migration # 預設會在這個路徑找 sql 檔,多個可用逗號隔開
check-location: true
encoding: utf-8 # 預設就是 utf-8
table: flyway_schema_history #預設就是這張表,可以改

baseline-on-migrate: true # 如果 table 的表已有,又改了表,在資料庫就會有兩張表,這時就要為 true
baseline-version: 62 # baseline-on-migrate true ,且真的有執行才有用,預設是 1
#table version 欄位,會從這個版本開始往上增加,<=這個版本的sql不會執行


預設在 class 下(src/main/resources) 要有 db/migration,想改照上面的圖改就可以了,裡面的檔案要照一定的格式才可以使用 flyway,不照做在啟動時就會報錯


flyway有兩個版本,commity 和 teams,teams 要付錢

分成 V、U、R,但 U 要付錢的版本才能用,V 和 U 後接版本號,然後再接兩個底線,內容放資料庫的操作

springboot 啟動後就會執行裡面的東西,預設會先創建 flyway_schema_history,想改照上面的 yml 改就行

※以 V 來說會執行數字最小的,然後一直往數字大的執行,可以跳號

※執行到錯誤就停止或執行到最新的一筆

※flyway_schema_history 裡的東西不能改,一啟會報錯,而且還不好抓錯誤

※db/migration 的檔名一執行過就不要改了,一啟動也會報錯,但可以用 flyway repair 後再執行可以解決,下面會說明怎麼安裝

※但 db/migration 檔案裡的內容不在 flyway 的控管範圍,假設用 flyway 創建了一張表,然後自己去資料庫改了欄位名稱,只要在新的內容裡對應好就不會報錯,只是失去了版本控管的意義而已


flyway 指令

官網下載好後解壓,以 windows 為例

conf 可以設定資料庫連線,設定四個就可以玩了,flyway.url   flyway.driver  flyway.user  flyway.password,前面的 # 是註解,要拿掉

在這個資料夾的同一層有 flyway 用在linux    flyway.cmd 用在windows,linux 要在前面加「./」就可以用這個指令了,想在認何地方用這個指令,要自己加環境變數


clean 會將 flyway_schema_history 所在的所有 table,不管是不是版控裡建的,都會drop 掉,可怕的指令

info 會將 flyway_schema_history 表列出來

baseline 和上面的 yml 的作用一樣

repair 最常用的一個指令,如有錯時,大部分都用這個指令,然後再執行就可以解決大部分的事

github 連結


2021年1月11日 星期一

Springboot 整合 XXL Job

文檔連結
下載連結(2.2版)
重大提示:
v2.1.0 移除 quartz 依賴   
v2.2.0 移除 JobHanler,用 @XxlJob 替代
下載後,執行 doc\db 裡的 SQL
xxl-job-admin 的 application.properties,資料庫連線相關的設定一下

doc/db/tables_xxl_job.sql 裡的腳本要先執行

以下為官網說明截取的:
xxl-job-admin:调度中心
xxl-job-core:公共依赖
xxl-job-executor-samples:执行器Sample示例(选择合适的版本执行器,可直接使用,也可以参考其并将现有项目改造成执行器)
    :xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器,推荐这种方式;
    :xxl-job-executor-sample-spring:Spring版本,通过Spring容器管理执行器,比较通用;
    :xxl-job-executor-sample-frameless:无框架版本;

先啟動 xxl-job-admin 調度中心,再啟動 executor-samples,如用 sprinboot 就啟動 springboot
http://localhost:8080/xxl-job-admin 預設帳密 admin/123456



至少要有一個執行器,在任務管理新增的時候會用到,綠框有很多功能,舊版的左邊有分執行一次和 cron 的,新版的全部都用 cron 了,且 cron 也有工具,點一點就生成了

2021年1月9日 星期六

反向代理、負載均衡、動靜分離 (nginx 三)

 http {

#負載均衡

upstream clusterNacos {

#負載策略

預設什麼都不寫是輪詢,按時間順序逐一分配,如果伺服器當機,也能自動跳過

weight; #預設為1,數字越大分配的越多

ip_hash; #一個ip固定一個後端伺服器

fair; #後端回應短的優先分配

server 127.0.0.1:9000;

server 127.0.0.1:9001;

server 127.0.0.1:9002;

}


server {

listen 9003;

server_name localhost;

location / {

proxy_pass http://clusterNacos;

}

}

#反向代理

server {

listen 9004;

server_name localhost;

location ~ /xxx/ {

proxy_pass http://127.0.0.1:9003;

}

location ~ /ooo/ {

proxy_pass http://127.0.0.1:9004;

}

}

#動靜分離

server {

listen 9005;

server_name localhost;

location /www/ {

index.html;

}

location /image/ {

root /jpg;

autoindex on;

}

}

}

Sentinel ( SpringCloud 2.x 九)

和 Nacos 一樣,要先下載 sentinel 並啟動,以 1.8 為例

下載連結

下載 sentinel-dashboard-1.8.0.jar 之後,是個 jar 檔,用以下指令啟動:

java -jar -Dserver.port=8080 sentinel-dashboard-1.8.0.jar #-Dserver.port 預設就是8080

登入 localhost:8080,帳密預設都是 sentinel,想改可再加 -D

-Dsentinel.dashboard.auth.username=sentinel

-Dsentinel.dashboard.auth.password=123456

文檔連結


然後在瀏覽器打 localhost:port 加上帳密就可以進去了,但要先有請求,左邊才會長出來讓你設定
所以要在專案增加 maven 和設定

pom.xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

application.yml
server:
port: 8056
spring:
cloud:
sentinel:
transport:
port: 8719
dashboard: localhost:9090 #對應 sentinel port

寫個 controller 並請求,sentinel 的左邊就長出來了;如果没有請求,預設是懶加載,如下的圖,綠框不會出現
如果不想懶加載,可用 spring.cloud.sentinel.eager=true,這時綠框出來了,但最後是(0/1),但只有欄位名而已,如 資源名、通過 QPS…等,如下圖,所以還是要有請求才能做限流







※綠框是長出來的樣子,點擊簇鏈路會出現如上的樣子,四個按鈕對應左邊的選項,是一樣的功能


※流控規則



資源名:如 GetMapping 裡的路徑,包括「/」
針對來源:可針對微服務做限流,寫微服務名,全部都限流就寫 default
閾值類型:QPS 才有最下面的流控效果;線程數只有快速失敗
單機閾值:數字,如 QPS 又寫了2,表示一秒超過兩個請求就會限流,至於哪種限流,要看流控效果,被限流時,網頁會顯示「Blocked by Sentinel (flow limiting)」
線程數+單機閾值為 1 表示線程只有 1 個,如果線程第 1 個還沒處理完又來一個請求,就會限流,可以在方法加 sleep 來試


※關聯


※如上圖,/testRelated 如果每秒超過1個請求,那 /testSentinel 就不能訪問


※鏈路

※如上圖,/testChain1 如果呼叫資源 abcdef,那每秒超過1個請求就會限流
abcdef 是寫在註解上的,這個註解只能放在方法上,blockHandler 是失敗時呼叫的方法
@SentinelResource(value = "abcdef", blockHandler = "chainHandler")

※但使用鏈路時還得抓 maven 和設定,版本用自己下載 sentinel 的版本
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.0</version>
</dependency>
https://github.com/alibaba/Sentinel/issues/1213
官網說可以用 spring.cloud.sentinel.web-context-unify=false,但我一開始試沒有用,只有用這個網址 main 方法裡的 sentinelFilterRegistration方法才可以
後來發現父 POM 的 spring-cloud-alibaba-dependencies 版本是 2.2.1.RELEASE,下載的 sentinel 是 1.7.1 的,但我用的是 1.8,我改成 2.2.2.RELEASE,會變成 1.8 版本的,這時候就好使了




※預熱


原碼找 WarmUpController,codeFactor 是寫死的3

以此例來說,官網說一開始是 6/3,每秒超過2個請求就會限流,經過5秒後,每秒超過6個請求才會限流,但我沒試出來


※排隊等待


排隊等待會用平均的速度對待每個 request
1000(毫秒數) / 單機閾值,如果寫 1 就是每秒;寫 2 就是每 500 毫秒,依此類推
此例就是平均每秒 1 個 request,超過 5 秒就放棄
單機閾值不能 > 1000