2022年7月10日 星期日

Linux 同時執行兩個 Redis

環境:
CentOS 7、已安裝 Redis


需求:
同時啟動兩個不同設定的 Redis,一個使用預設的 6379 PORT,另一個使用 6380 PORT


步驟:

  1. 原本 Redis 的工作資料夾在 /var/lib/redis,另外建立一個 /var/lib/redis2 當作第二個 Redis 的工作資料夾。
    (工作資料夾:Redis 存放 DB 的位置)
    # mkdir /var/lib/redis2
    # chown redis /var/lib/redis2
    # chgrp redis /var/lib/redis2
  2. 原本安裝的 Redis 設定檔在 /etc/redis.conf ,另外複製一個給第二個 Redis 用
    # cp /etc/redis.conf /etc/redis2.conf
    # chown redis /etc/redis2.conf
  3. 修改第二個 Redis 的設定檔
    # vi /etc/redis2.conf
    設定 logfile、dir、pidfile、port,以跟第一個 Redis 區別
    例如:
    logfile "/var/log/redis/redis2.log"
    dir "/var/lib/redis2"
    pidfile "/var/run/redis/redis2.pid"
    port 6380
  4. 原本安裝的 Redis 系統服務設定檔在 /usr/lib/systemd/system/redis.service,另外複製一個給第二個 Redis 用
    # cp /usr/lib/systemd/system/redis.service /usr/lib/systemd/system/redis2.service

    修改 redis2.service 內容,將關鍵部分,改為第二個 Redis,
    例如第一個 redis.service 內容為:
    [Unit]
    Description=Redis persistent key-value database
    After=network.target
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    ExecStart=/usr/bin/redis-server /etc/redis.conf --supervised systemd
    ExecStop=/usr/libexec/redis-shutdown
    Type=notify
    User=redis
    Group=redis
    RuntimeDirectory=redis
    RuntimeDirectoryMode=0755
    
    [Install]
    WantedBy=multi-user.target

    則第二個 redis2.service 內容改為:
    [Unit]
    Description=Redis persistent key-value database
    After=network.target
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    ExecStart=/usr/bin/redis-server /etc/redis2.conf --supervised systemd
    ExecStop=/usr/libexec/redis-shutdown redis2
    Type=notify
    User=redis
    Group=redis
    RuntimeDirectory=redis2
    RuntimeDirectoryMode=0755
    
    [Install]
    WantedBy=multi-user.target
    RuntimeDirectory(運行目錄):服務啟動時,會於 /run 底下建立指定的資料夾,服務關閉時,會刪除建立的資料夾。
    所以也將 RuntimeDirectory 設定值改成跟第一個 Redis 不一樣。
    如果有其他參數,可先了解該參數意義,判斷設定值是否須跟第一個 redis 有區別。
  5. 原本第一個 redis 有「drop-in」資料夾,所以也照樣複製一個給 redis2 用。(此步驟可視實際需要,決定是否也建立「drop-in」資料夾)
    # cp -pr /etc/systemd/system/redis.service.d /etc/systemd/system/redis2.service.d

    該資料夾底下有一個 limit.conf 檔案,設定了 LimitNOFILE 參數,用來限制 File descriptor 的最大數量。
    (將設定值寫在相對應的「drop-in」資料夾,可避免直接修改 .service 檔案,系統讀了.service 檔案,還會讀取相對應的「drop-in」資料夾)
    # If you need to change max open file limit
    # for example, when you change maxclient in configuration
    # you can change the LimitNOFILE value below
    # see "man systemd.exec" for information
    
    [Service]
    LimitNOFILE=10240
  6. 設定開機啟動 redis2
    # systemctl enable redis2
  7. 啟動 redis2
    # systemctl start redis2
  8. 查看執行的狀態
    # systemctl status redis.service
    ● redis.service - Redis persistent key-value database
       Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
      Drop-In: /etc/systemd/system/redis.service.d
               └─limit.conf
       Active: active (running)
     Main PID: 40341 (redis-server)
       CGroup: /system.slice/redis.service
               └─40341 /usr/bin/redis-server 127.0.0.1:6379 

    # systemctl status redis2.service
    ● redis2.service - Redis persistent key-value database
       Loaded: loaded (/usr/lib/systemd/system/redis2.service; enabled; vendor preset: disabled)
      Drop-In: /etc/systemd/system/redis2.service.d
               └─limit.conf
       Active: active (running)
      Process: 44005 ExecStop=/usr/libexec/redis-shutdown redis2 (code=exited, status=0/SUCCESS)
     Main PID: 44039 (redis-server)
       CGroup: /system.slice/redis2.service
               └─44039 /usr/bin/redis-server 127.0.0.1:6380
  9. 查看 Redis 使用的 PORT
    第一個 Redis,TCP 6379 PORT 網路連線
    # lsof -i:6379
    COMMAND     PID  USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
    redis-ser 40341 redis    4u  IPv4 10637133      0t0  TCP localhost:6379 (LISTEN)

    第二個 Redis,TCP 6380 PORT 網路連線
    # lsof -i:6380
    COMMAND     PID   USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
    redis-ser 40457  redis    4u  IPv4 10637186      0t0  TCP localhost:6380 (LISTEN)





參考:

2022年7月5日 星期二

Linux 搜尋資料夾下檔案內的文字內容

例如,想要找「/home/test/」資料夾底下所有文件,含有「abc」內容的檔案名稱、在第幾行。

指令:

有出現「abc」的行即匹配。例如:「aaaabcccc」
grep -rn '/home/test/' -e 'abc'

加上-w參數,則該行有一完整單詞都符合才匹配。例如:「xxxx    abc     yyyyy」
grep -rnw '/home/test/' -e 'abc'


說明:
-r, --recursive 遞迴讀取每個目錄下的文件
      Read  all files under each directory, recursively,
      following symbolic links only if they are on the command line.
      This is equivalent to the -d recurse option.

-n, --line-number 標行號
      Prefix each line of output with the 1-based line number within its input file.
      (-n is specified by POSIX.)

-w, --word-regexp 完整單詞匹配
      Select only those lines containing matches that form whole words.
      The test is that the matching substring must either be at  the  beginning
      of the line, or preceded by a non-word constituent character.
      Similarly, it must be either at the end of the line or followed by a non-word
      constituent character.  Word-constituent characters are letters, digits, and the underscore.
-e PATTERN, --regexp=PATTERN 設定匹配文字樣式
      Use PATTERN as the pattern.  This can be used to specify multiple search patterns,
      or to protect a pattern beginning with a hyphen (-).  (-e is specified by POSIX.)


其他:
  • 只搜尋「.php」 附檔名的檔案
  • grep -rnw '/home/test/' -e 'abc' --include=\*.php
  • 只搜尋「.php」、「.txt」 附檔名的檔案
  • grep -rnw '/home/test/' -e 'abc' --include=\*.{php,txt}
  • 排除「aa」目錄底下的檔案(目錄底下的目錄也算)
  • grep -rnw '/home/test/' -e 'abc' --exclude-dir=aa
  • 排除「aa開頭」目錄底下的檔案(目錄底下的目錄也算)
  • grep -rnw '/home/test/' -e 'abc' --exclude-dir=aa*
  • 排除「aa」、「bb」目錄底下的檔案(目錄底下的目錄也算)
  • grep -rnw '/home/test/' -e 'abc' --exclude-dir={aa,bb}
  • 排除「aa開頭」、「bb」目錄底下的檔案(目錄底下的目錄也算)
  • grep -rnw '/home/test/' -e 'abc' --exclude-dir={aa*,bb}


參考:



遠端桌面 windows 鎖定螢幕

[環境]
Win10


[問題]
使用 Chrome 遠端桌面完,想將螢幕鎖定,但無法直接按「Win」+「L」,也沒傳送「Win」+「L」功能。


[解決]
方法一:
先選擇傳送 「Ctrl」+「Alt」+「Del」,即可選擇「鎖定」。

方法一:
於 CMD,下螢幕鎖定指令:
rundll32.exe user32.dll, LockWorkStation



參考:



2022年6月23日 星期四

連結的 HTTP Referer 不見?

[狀況]
從 https://aa.example.com 連結到 http://bb.example.com
但在 http://bb.example.com 的 request header 沒有 Referer 資料


[原因]
瀏覽器(Chrome 103.0.5060.53)的 Referrer-Policy 預設值為 strict-origin-when-cross-origin
此時從 HTTPS 的網站,連結到 HTTP 網站,不傳送 Referer 資料


[解決]
因為我只需要 https://aa.example.com/ 這樣的 Origin(<scheme>://<hostname>:<port>) 資料,
不需要後面的 path、querystring,
所以於 https://aa.example.com 網站,將 Referrer-Policy 改為 origin,
如此在 HTTPS -> HTTP 時,仍會傳送包含  https://aa.example.com/ 的 Referer 資料
(注意:以下設定都是用正確拼寫的 Referrer)
  • 方法1:
    於 Web Server(以 Nginx 為例),設定 header ,將 Referrer-Policy 改為 origin:
    add_header 'Referrer-Policy' 'origin';
  • 方法2:
    於 HTML 頁面,設定 referrer ,將 Referrer-Policy 改為 origin:
    <meta name="referrer" content="origin">
  • 方法3:
    於連結,設定 referrerpolicy ,將 Referrer-Policy 改為 origin:
    <a href="http://bb.example.com/" referrerpolicy="origin" target="_blank">test</a>



[Referrer-Policy 的設定值]
引用:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
  • no-referrer:
    The Referer header will be omitted: sent requests do not include any referrer information.
  • no-referrer-when-downgrade:
    Send the origin, path, and querystring in Referer when the protocol security level stays the same or improves (HTTP→HTTP, HTTP→HTTPS, HTTPS→HTTPS). Don't send the Referer header for requests to less secure destinations (HTTPS→HTTP, HTTPS→file).
  • origin:
    Send only the origin in the Referer header. For example, a document at https://example.com/page.html will send the referrer https://example.com/.
  • origin-when-cross-origin:
    When performing a same-origin request to the same protocol level (HTTP→HTTP, HTTPS→HTTPS), send the origin, path, and query string . Send only the origin for cross origin requests and requests to less secure destinations (HTTPS→HTTP).
  • same-origin:
    Send the origin, path, and query string for same-origin requests. Don't send the Referer header for cross-origin requests.
  • strict-origin:
    Send only the origin when the protocol security level stays the same (HTTPS→HTTPS). Don't send the Referer header to less secure destinations (HTTPS→HTTP).
  • strict-origin-when-cross-origin (default):
    Send the origin, path, and querystring when performing a same-origin request. For cross-origin requests send the origin (only) when the protocol security level stays same (HTTPS→HTTPS). Don't send the Referer header to less secure destinations (HTTPS→HTTP).



參考:

2022年5月5日 星期四

MySQL(MariaDB) INSERT INTO ... ON DUPLICATE KEY UPDATE,只更新符合條件的資料

INSERT INTO ... ON DUPLICATE KEY UPDATE 沒辦法用 WHERE 條件過濾出要更新的資料,
但要更新的值,可以用 IF 條件來控制。
讓不欲更新的資料,用原值更新,效果便猶如沒更新過,而只更新其他資料。

[範例]
一資料表test,三個欄位 id(主鍵)、aa(int)、bb(int)。
新增(INSERT INTO)資料時,若資料(id)已存在,則更新 aa、bb 兩欄位資料,
但若原本的 bb 資料小於 100,則不更新 bb:
INSERT INTO test (id, aa, bb)
  VALUES (8, 123, 456)
ON DUPLICATE KEY UPDATE
  aa = VALUES(aa),
  bb = IF(bb<100, bb, VALUES(bb));


[注意]
如果有一筆資料(id, aa, bb) => (10, 1, 2)
INSERT INTO test (id, aa, bb)
  VALUES (10, 100, 200)
ON DUPLICATE KEY UPDATE
  aa = VALUES(aa),
  bb = aa;
得到的結果是 (id, aa, bb) => (10, 100, 100)

將最後兩行順序調換:
INSERT INTO test (id, aa, bb)
  VALUES (10, 100, 200)
ON DUPLICATE KEY UPDATE
  bb = aa,
  aa = VALUES(aa);
得到的結果是 (id, aa, bb) => (10, 100, 1)

可發現,順序不同,結果不同
=> ON DUPLICATE KEY UPDATE 若要取其他欄位的原值,須排在其他欄位修改之前。



所以最初的例子「若原本的 bb 資料小於 100,則不更新 bb」,
如果改成「若原本的 bb 資料小於 原本aa,則不更新 bb」,
則須注意 aa、bb 修改的順序,避免比較到 aa 修改後的值:
INSERT INTO test (id, aa, bb)
  VALUES (8, 123, 456)
ON DUPLICATE KEY UPDATE
  bb = IF(bb<aa, bb, VALUES(bb)),
  aa = VALUES(aa);



參考: