<code>本⽂先介紹如何從源代碼編譯安裝Greenplum、初始化Greenplum集群。然後介紹SQL在Greenplum中的典型執⾏路徑,最後介紹⼀些調試技巧。/<code>
源 代 碼 使 ⽤ Greenplum 開 源 社 區 最 新 源 代 碼 6X_STABLE 分 ⽀ :ghttps://github.com/greenplum-db/gpdb%EF%BC%8C 內核代碼基於 PostgreSQL9.4。⽬前(2019/04/23) 主⼲分⽀的代碼基於 PostgreSQL 9.4 。合併到 PostgreSQL 9.5 的⼯作也已經開始, 有關最新⼯作進展請參⻅:https://github.com/greenplum-db/gpdb-postgres-merge%E3%80%82
1 從源代碼編譯 Greenplum
Greenplum ⽬前官⽅⽀持 Redhat/Centos/SuSE/Ubuntu 等Linux系統。⼤量開發⼈員包括我⾃⼰使⽤Mac系統,但是不在官⽅⽀持列表中。
1.1 在 Mac系統上編譯
⾸先需要關閉蘋果操作系統的 SIP 特性,否則⽆法初始化集群。
- 重啟操作系統
- 重啟過程中按下 command+R進⼊恢復模式
- 從 Utilities菜單選擇 Terminal
- 執 ⾏ csrutildisable
- 重啟操作系統
其次,安裝Greenplum管理腳本依賴的 Python 包
<code>$ wgethttps:
//bootstrap.pypa.io/get
-pip.py $ sudo python get-pip.py $ sudo pip install psutil lockfile paramiko setuptools epydoc/<code>
然後,需要安裝 openssl,否則⽆法編譯
<code>$ brewinstall
zstd openssl && brewlink
openssl $ CPPFLAGS="-I/usr/local/include/ -I/usr/local/opt/openssl/include"
\ LDFLAGS="-L/usr/local/lib -L/usr/local/opt/openssl/lib"
\ CFLAGS="-O0 -g3 -ggdb3"
\ ./configure $ make [-j4] $ makeinstall
/<code>
最後,在蘋果系統上初始化Greenplum單節點集群時,需要做些準備⼯作:
- 添加export PGHOST=localhost⾄~/.bash_profile
- 將本機的hostname與127.0.0.1的map寫到/etc/hosts中。例如
<code> 127.0
.0
.1
yydzero
yydzero
.local
/<code>
- 修改/etc/sysctl.conf⽂件,並重啟:
<code>kern.sysv.shmmax=2147483648 kern.sysv.shmmin=1 kern.sysv.shmmni=64 kern.sysv.shmseg=16 kern.sysv.shmall=524288 kern.maxfiles=65535 kern.maxfilesperproc=65535 net.inet.tcp.msl=60
cd
gpAux/gpdemo
source
$HOME
/gpdb.master/greenplum_path.sh
export
PGHOST=`hostname`make
source
gpdemo-env.shpsql postgres
SELECT version()
/<code>
有關更詳細的信息請參考 README.macOS.md。
1.2 在 Redhat/Centos系統上編譯
本⼩節以 RHEL7 為例介紹如何編譯Greenplum。
⾸先,下載 Greenplum 源代碼
<code>$ gitclone
https:/<code>
其次,Greenplum Database 編譯和運⾏依賴於各種系統庫和Python庫。需要先安裝這些依賴:
<code>$ sudo yum groupinstall'Development Tools'
$ sudo yum install curl-devel bzip2-devel python-devel openssl-devel readline-devel libzstd-devel $ sudo yum install perl-ExtUtils-Embed $ sudo yum install libxml2-devel $ sudo yum install openldap-devel $ sudo yum install pam pam-devel $ sudo yum install perl-devel $ wgethttps:
//bootstrap.pypa.io/get
-pip.py $ sudo python get-pip.py $ sudo pip install psutil lockfile paramiko setuptools epydoc/<code>
再次,編譯 Greenplum Database 源代碼,假定安裝到 $HOME/gpdb.master ⽬錄下
<code>$ CFLAGS="-O0 -g3 -ggdb3"
\ ./configure --with-perl --with-python --with-libxml --enable
-debug --enable
-cassert \ --disable
-orca --disable
-gpcloud --disable
-gpfdist \ --prefix=/home/gpadmin/gpdb.master $ make $ make install/<code>
<code>
cd
gpAux/gpdemo
source
/home/gpadmin/gpdb.master/greenplum_path.sh
export
PGHOST=`hostname`make
source
gpdemo-env.sh/<code>
<code>$
psql
postgres
postgres#
SELECT
version()
version
-----------------------------------------------------------------
PostgreSQL
8.3
.23
(Greenplum
Database
5.4
.1
+dev.56.gcdfadd9
build
dev)
...
/<code>
<code>postgres= dbid| content |
role| preferred_role |
mode| status |
port| hostname |
address| replication_port ------+---------+------+----------------+------+--------+-------+----------+---------+------------------ 1 |
-1
| p |
p| s |
u| 15432 |
g20
| g20 |
2
| 0 |
p| p |
s| u |
25432
| g20 |
g20
| 25438 3 |
1
| p |
p| s |
u| 25433 |
g20
| g20 |
25439
4
| 2 |
p| p |
s| u |
25434
| g20 |
g20
| 25440 5 |
0
| m |
m| s |
u| 25435 |
g20
| g20 |
25441
6
| 1 |
m| m |
s| u |
25436
| g20 |
g20
| 25442 7 |
2
| m |
m| s |
u| 25437 |
g20
| g20 |
25443
/<code>
2 初始化 Greenplum 集群
前⾯編譯部分介紹瞭如何使⽤ Greenplum 源代碼中的 demo 集群腳本創建集群。這種⽅法簡單快捷,讓⽽屏蔽了很多細節。
2.1 ⼿⼯集群初始化
下⾯介紹如何⼿⼯部署⼀個單機集群:在⼀檯筆記本上安裝⼀個Greenplum的集群,包括⼀個master,兩個segments。
- step 0. 系統環境配置
<code>$
/etc/sysctl.conf
kernel.shmmax
=
500000000
kernel.shmmni
=
4096
kernel.shmall
=
4000000000
kernel.sem
=
250
512000
100
2048
kernel.sysrq
=
1
kernel.core_uses_pid
=
1
kernel.msgmnb
=
65536
kernel.msgmax
=
65536
kernel.msgmni
=
2048
net.ipv4.tcp_syncookies
=
1
net.ipv4.conf.default.accept_source_route
=
0
net.ipv4.tcp_tw_recycle
=
1
net.ipv4.tcp_max_syn_backlog
=
4096
net.ipv4.conf.all.arp_filter
=
1
net.ipv4.ip_local_port_range
=
10000
65535
net.core.netdev_max_backlog
=
10000
net.core.rmem_max
=
2097152
net.core.wmem_max
=
2097152
vm.overcommit_memory
=
2
$
cat
/etc/security/limits.conf
*
soft
nofile
65536
*
hard
nofile
65536
*
soft
nproc
131072
*
hard
nproc
131072
$
sudo
reboot
/<code>
- step 1. source⼀些環境變量, 例如PATH
<code>
source
$HOME
/gpdb.master/greenplum_path.sh/<code>
- step 2. 交換集群中所有機器的ssh密鑰, 我們這⾥只有⼀臺機器
<code>$ gpssh-exkeys -h`hostname`
/<code>
- step 3. ⽣成三個配置⽂件:env.sh, hostfile, gpinitsystem_config
<code>$ cat env.shsource
$HOME
/gpdb.master/greenplum_path.shexport
PGPORT=5432export
MASTER_DATA_DIRECTORY=$HOME
/data/master/gpseg-1/<code>
# hostfile 包括集群中所有機器的hostname, 我們這⾥只有⼀臺
<code>cat hostfile
cat gpinitsystem_config
ARRAY_NAME
="Open Source Greenplum"
SEG_PREFIX
=gpseg
PORT_BASE
=40000
/<code>
# 根據需要,修改下⾯的路徑和主機名
# 有⼏個DATA_DIRECTORY, 每個節點上便會啟動⼏個segments
<code>declare
-a DATA_DIRECTORY=(/path
/to
/your/data
/path
/to
/your/data
)/<code>
# master的主機名, 路徑和端⼝
<code>MASTER_HOSTNAME
=your_hostnameMASTER_DIRECTORY
=/path/to/your/data/masterMASTER_PORT
=5432
TRUSTED_SHELL
=sshCHECK_POINT_SEGMENTS
=8
ENCODING
=UNICODEMACHINE_LIST_FILE
=hostfile/<code>
- step 4. 初始化Greenplum 集群
<code>
source
env.shgpinitsystem -c gpinitsystem_config -a
/<code>
- step 5. 初始化成功後,運⾏下⾯命令驗證系統狀態
<code>$ psql -l $ gpstate/<code>
- step 6. 簡單測試
<code>$ createdbtest
$ psqltest
test
test
gp_segment_id | count ---------------+--------- 0 | 501 1 | 499/<code>
有關如何安裝多節點集群,請參考Greenplum官方安裝文檔。
2.2 集群初始化問題調試
有時候 gpinitsystem 會失敗,但是不清楚失敗原因是什麼。下⾯提供⼀些思路來 RCA:
2.2.1 使⽤ gpinitsystem調試模式
gpinitsystem有⼀個 -D選項,使⽤這個選項可以看到更多的輸出信息,根據這些額外的輸出信息可以發現並解決⼤部分問題。
2.2.2 查看⽇志
常⽤的⽇志⽂件有兩類,⼀種是 gpinitsystem 的⽇志,⼀種是數據庫的⽇志。它們分別保存在不同的⽬錄下:
2.2.3 初始化 master數據庫失敗
⼿動執⾏initdb查看詳細錯誤信息,然後分析具體錯誤信息採取相應錯誤。不同的版本可能參數不同,可以通過在 gpinitsystem 腳本中找到完整的命令。
<code>$ initdb -E UNICODE -D /data/master/gpseg-1
/<code>
2.2.4 master起不來
使⽤下⾯命令,⼿動啟動master觀看⽇志是否有問題。下⾯使⽤ Utility 模式啟動master, 僅僅允許utility 模式連接。
<code>$
postgres
-D
/data/master/gpseg-1
-i
-p
5432
-c
gp_role=utility
-M
master
-b
1
-C
-1
-z
0
-m
/<code>
2.2.5 啟動Segment出錯
如果啟動 segment 時出錯,並且看不到具體錯誤信息(通常由於錯誤信息被重定向到/dev/null 了),則可以嘗試⼿動啟動 segment。
⼿動啟動segment的命令參考下⾯,需要根據⾃⼰的環境修改某些路徑或者參數:
<code>export LD_LIBRARY_PATH=/home/gpadmin
/build/gpdb
.master/lib:
/lib:
;export PGPORT=40006
;/home/gpadmin
/build/gpdb
.master/bin/pg_ctl -w -l /data2/primary/gpseg18/pg_log/startup.log -D /data2/primary/gpseg18 -o"-i -p 40006 -M mirrorless -b 20 -C 18 -z 0"
start/<code>
有時候單獨執⾏各種命令沒有問題,但是使⽤ SSH 執⾏時報錯。
這通常是由於 ssh 改變了環境變量造成的,查看 .bash_profile, .bashrc, 發現 .bashrc 設置了不同的默認 PGHOST,刪除這個配置後就可以了。
2.2.6 不能連接到server:找不到domain socket
<code>○ → PGOPTIONS='-c gp_session_role=utility'
/Users/yydzero/work/build/master/bin/psql postgres psql: couldnot
connect
to server: No such fileor
directory Is the server running locallyand
accepting connections on Unix domainsocket
"/var/pgsql_socket/.s.PGSQL.5432"
?/<code>
這個通常是由於不同的 psqlbinary造成的,也就是說⾃⼰編譯的 psql調⽤了系統的 libpq 庫。可以通過 ldd或者 otool-L查看。
解決⽅法:
<code>export
LD_LIBRARY_PATH=/path/
to/your/psql/lib/<code>
2.2.7 gpstart失敗,並且原因不明
$gpstart-v//使⽤ verbose模式,顯示每個執⾏的命令以及其結果。遇到的⼀個問題報錯如下:
<code>unable toimport
module
: Nomodule
named psutil/<code>
原因是 psutil 這個python包沒有安裝,但是使⽤ python 驗證,發現已經安裝了。⽽使⽤ssh 驗證發現使⽤了不同路徑的 python。
2.2.8 關閉 IPv6
如果遇到下⾯錯誤,則關閉 IPv6:
<code>ping
cmdStr='/bin/ping6 -c 1 gp1′ had result: cmd had rc=2 completed=True halted=False
stdout
=”
stderr
='connect: Invalid argument'
/<code>
如何關閉 IPv6:
加⼊以下兩⾏到⽂件:/etc/sysctl.conf
<code>net.ipv6.conf.all.disable_ipv6
=1
net.ipv6.conf.default.disable_ipv6
=1
/<code>
然後 $ sysctl -p
2.2.9 小技巧
Greenplum使⽤ Bash和 Python腳本初始化集群和管理集群。可以通過在合適的地⽅設置⽇志或者調試信息可以幫助分析某些難以解決的問題。
- 集群初始化⼯具 gpinitsystem 是Bash腳本⼯具,有些時候它的報錯信息很不清楚。這個時候可以
- 使⽤ -D 選項
- gp_bash_functions.sh 是內部⼀個被頻繁調⽤執⾏系統命令的函數,可以通過set -x 可以打印出所有執⾏的命令的詳細信息。對調試 hang 問題很有效。
- 在合適的代碼處啟⽤ Python 調試器,如果不知道什麼地⽅合適,則在⼊⼝處。
3 Greenplum SQL執⾏流程概要
下⾯介紹下 Greenplum 中 SQL 執⾏的簡單過程。例⼦中集群⼀個 Master 兩個Segments。
準備簡單的數據:
<code>CREATE
TABLE
students (id
int
,name
text
)DISTRIBUTED
BY
(id
);CREATE
TABLE
classes(id
int
, classnametext
, student_idint
)DISTRIBUTED
BY
(id
);INSERT
INTO
studentsVALUES
(1
,'steven'
), (2
,'changchang'
), (3
,'guoguo'
);INSERT
INTO
classesVALUES
(1
,'math'
,1
), (2
,'math'
,2
), (3
,'physics'
,3
);/<code>
以下⾯的SQL為例⼦,瞭解 SQL 在 Greenplum 中的執⾏過程:
<code>SELECT
s.name student_name, c.classnameFROM
students s, classes cWHERE
s.id=c.student_id;/<code>
3.1 查詢計劃
其對應的查詢計劃如下所示:
<code>test=#
explain
SELECT
s.name
student_name,
c.classname
test-#
FROM
students
s,
classes
c
test-#
WHERE
s.id=c.student_id;
QUERY
PLAN
-----------------------------------------------------------------------------------------------
Gather
Motion
2
:1
(slice2;
segments:
2
)
(cost=2.07..4.21
rows=4
width=14)
->
Hash
Join
(cost=2.07..4.21
rows=2
width=14)
Hash Cond:
c.student_id
=
s.id
->
Redistribute
Motion
2
:2
(slice1;
segments:
2
)
(cost=0.00..2.09
rows=2
width=10)
Hash Key:
c.student_id
->
Seq
Scan
on
classes
c
(cost=0.00..2.03
rows=2
width=10)
->
Hash
(cost=2.03..2.03
rows=2
width=12)
->
Seq
Scan
on
students
s
(cost=0.00..2.03
rows=2
width=12)
Optimizer status:
legacy
query
optimizer
/<code>
使用 explain.pl 可以生成如下的查詢計劃圖:(把上面的explain結果保存到一個名為 a.plainplan 的文件中)
<code> $ explain.pl -opt jpg/tmp/a
.plainplan >/tmp/a
.jpg/<code>
從上圖可以很明顯看出該計劃包含兩個 slice,slice 使⽤的motion為重分佈。
hashjoin的兩個表為students和classes, 它們的分佈鍵都是其 id, ⽽ join的鍵值是student.id=classes.student_id其中 student的join鍵是其主鍵, 因⽽不需要數據移動(motion);⽽classes的關聯鍵是 student_id,和其分佈鍵不同,因⽽需要數據移動(motion),以保證相同關聯鍵的數據都在同⼀個 segment 上。
感興趣的讀者可以嘗試把 stendent 的分佈鍵改成其他字段,看看計劃有什麼變化。
3.2 查詢執行
QD(Query Dispatcher) 將上⾯的並⾏計劃分發到每個 segment 上執⾏。這個例⼦中⼀共有2個segments。
查詢計劃包含2個slices,所以每個 segment 會啟動 2 個 QE(Query Executor),⼀個QE 負責執⾏⼀個 slice 對應的任務。
同⼀個 slice 在每個 segment 的 QE形成⼀個 Gang,它們在不同的segment上執⾏相同的任務。
HashJoin需要相同關聯鍵的所有數據都在⼀個 segment上,因⽽如果關聯鍵不是分佈鍵, 則需要數據移動。在這個例⼦中classes的分佈鍵(id)和關聯鍵(student_id) 不同,所以需要數據重分佈。
數據重分佈由 Motion 操作符節點處理,它分成2個部分,⼀部分負責發送數據,⼀部分負責接收數據。發送數據者可以根據不同的策略將數據發送給接收⽅,現在⽀持的策略有1)重分佈(redistribution);2)⼴播(broadcast)。
最後每個segment執⾏結束後,將結果發送給 Master。Master對最終的數據整合(Gather Motion),返回給客戶端。
4 調試Greenplum MPP 數據庫
4.1 調試 Master節點Backend進程
調試 Master 的Backend進程(也稱為 QD)和調試單節點的PostgreSQL ⾮常類似。通常遇到解析、優化、調度相關問題時,需要調試QD。
下⾯以⼀個例⼦介紹如何調試 GreenplumQD進程。啟動兩個窗⼝,⼀個運⾏psql,⼀個運⾏ lldb
使⽤ lldb 的 gui 命令可以使⽤⼀個簡單的源代碼瀏覽器查看當前正在執⾏的代碼區域,以及執⾏函數的相關變量。
通過簡單的斷點和單步執⾏,可以快速瞭解SQL的執⾏過程。譬如上⾯例⼦中可以看到cdbdisp_dispatchToGang 在 ExecutorStart 之後、ExecutorRun 之前運⾏,⽤途是將 QD 優化好的計劃分發給 segments 執⾏。
4.2 調試 Segment節點Backend進程 (QE)
調試 segment 進程(通常是 QE)和調試master上的進程⼀樣,唯⼀的區別是如何獲得進程的id?
此時不能通過 pg_backend_pid() 獲得,因為該pid是 QD 的進程號。常⽤的⽅法是通過執⾏2次 SQL,獲得 QE 的進程號。
Greenplum為了提⾼效率, 降低創建 Gang/QEs的代價, 通常會重⽤已經創建的Gang/QEs。利⽤這⼀特性,可以⽅便的找到每個 segment上 QE 的pid。
先執⾏⼀次想要調試的 SQL。然後使⽤下⾯的命令找出感興趣的 QE 的pid。
這個例⼦中進程38965 是 QD進程, 41210是 segment0上的 QE進程, 41211是segment 1 上的 QE 進程。
<code>○ →ps
-ef
|grep
postgres
|grep
idle
503
38965
38387
0
9
:35PM
0
:00.46
postgres
:5432
,yydzero
test
::1(51161)
con9
cmd65
idle
503
41210
38354
0
10
:39PM
0
:00.10
postgres
:40000
,yydzero
test
**(51490
)con9
seg0
idle
503
41211
38355
0
10
:39PM
0
:00.11
postgres
:40001
,yydzero
test
**(51491
)con9
seg1
idle
/<code>
知道了 QE的進程號,使⽤ lldbattach到該進程,重新執⾏ SQL就可以進⾏調試了。Gang/QEs的重⽤時間由 GUCgp_vmem_idle_resource_timeout控制。
4.3 使⽤ IDE調試
常⽤的調試器gdb/lldb雖然簡單易⽤、 功能也很強⼤,但是不直觀。很多集成開發環境(IDE)提供了⾮常直觀、強⼤、易⽤的調試環境,包括 clion、eclipse、xcode 等。IDE 對於學習 Greenplum 代碼也⾮常有幫助,可以⼤⼤提⾼效率。
下⾯簡單介紹如何使⽤ clion 圖形化⽤戶界⾯調試 Greenplum 代碼。( Eclipse、VisualCode具有類似功能)
Greenplum進程都是 daemon進程,很難通過啟動⽅式進⼊調試器。因⽽通常使⽤的⽅法是 attach到已經運⾏的進程。
⾸先啟動 clion,導⼊ Greenplum源代碼項⽬。clion需要 CMakeLists.txt⽂件構建⼯程項⽬。將下⾯的 CMakeLists.txt放到 Greenplum源代碼⽬錄的頂層⽬錄中,再啟動 clion既可建⽴合適的⼯程項⽬。
<code>$ cat CMakeLists.txt cmake_minimum_required(VERSION3.8
) project(gpdb) set(CMAKE_CXX_STANDARD11
) include_directories(src/include
src/backend/gp_libpq_fe) file(GLOB_RECURSE SOURCE_FILES"src"
"*.c"
"*.h"
) add_executable(gpdb ${SOURCE_FILES})/<code>
然後選擇 Run → Attach to Local Process… 出現下面 “Attach with LLDB to” 窗口。選擇需要調試的進程id即可。(如果確定進程id請見前面小節)
如果 clion調試器console顯示類似 “Debugger attached to process 38965” 的消息,則表示進程attach成功,可以使⽤ clion進⾏調試了。
通過圖像化窗⼝定位到 “ExecProcNode” 函數,通過單擊下圖的⼩紅圈處,即可設置斷點在 ExecAgg() 調⽤處。
執⾏ SELECT count(*) FROM students 語句,可以使⽤各種調試命令(例如單步執⾏、斷點、跳出函數等)⽅便的調試代碼。
如上圖所示,可以通過 IDE很直觀的看到正在執⾏的代碼⽚段,以及函數中變量的值。對於學習和調試Greenplum⾮常有幫助。
來源:Greenplum中文社區
關鍵字: gpinitsystem 集群 segment