Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
者:胡呈清
愛可生 DBA 團隊成員,擅長故障分析、性能優化,個人博客:https://www.jianshu.com/u/a95ec11f67a8,歡迎討論。
本文來源:原創投稿
*愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯系小編并注明來源。
如果 SQL 在執行過程中讀到的數據無法直接得到結果,那么就需要額外的內存來保存中間結果,得出最終結果,這個額外的內存就是內部臨時表。比如 group by 執行時,就需要構建一個臨時表,需要額外的字段保存聚合函數的結果,當然為了防止內存使用過大,一般超出某個限制后就會放到磁盤上。關于哪些操作會產生內部臨時表,可以查看官方文檔:https://dev.mysql.com/doc/refman/8.0/en/internal-temporary-tables.html,下面主要介紹 MySQL8.0 內部臨時表存放方式的變化。
MySQL 5.6 中,內部臨時表大小超過內存限制后是在臨時目錄中的單個表文件表空間中創建的,如果禁用了 innodb_file_per_table ,則在數據目錄中的 InnoDB 共享表空間(ibdata1)中創建,很容易造成 ibdata1 過大,并且無法釋放,只能邏輯導出數據遷移到新實例解決。
MySQL 5.7 在臨時表空間上做了改進,已經實現將臨時表空間從 InnoDB 共享表空間或者獨立表空間中分離,現在叫共享臨時表空間。好處有二:
其表現是 MySQL 啟動時 datadir 下會創建一個 ibtmp1 文件,默認值下會無限擴展。例如,如果某個 SQL 執行時創建了一個大小為 20MB 的內部磁盤臨時表,則創建時默認大小為 12MB 的臨時表空間文件會擴展到 20MB 以適應該表。當 SQL 執行完刪除臨時表時,釋放的空間可以重新用于新的臨時表,但 ibtmp1 文件保持擴展大小,只有重啟 MySQL 時才會真正回收共享臨時表空間變成初始大小 12MB。
相關參數:
缺點:SQL 執行完產生的內部臨時表可能很大,必須要重啟才能釋放。這點曾一度讓我很困惑,為什么不能做的更好一點執行完就釋放呢?所幸 MySQL8.0 優化了這個問題。
MySQL 8.0又有較大變化,新增了一些參數:
也就是說,默認情況下執行 SQL 產生內部臨時表,使用的存儲引擎從 MEMORY 變成了 TempTable,當然 TempTable 依然是一種內存表,可以使用的最大內存是1G(默認)。當大小超過1G,會使用內存映射臨時文件作為內部臨時表的溢出機制,大白話就是防止內存使用太大,把內存中的數據放在臨時文件中。
但是你想想,關系型數據庫設計了存儲引擎這么好的東西來存放數據,這時候用文件來存是不是過分了點?估計官方是這么想的:哎呀內部臨時表很小的,我就臨時放放,你忍忍。后來發現有些內部臨時表太大了忍不了,為了防止內存映射臨時文件過大,8.0.23版本引入一個新參數 temptable_max_mmap 來限制其大小,如果超過其大小(默認1G),則轉化為磁盤臨時表(這點和 MySQL 5.7一致)。值得注意的是 temptable_use_mmap 參數 8.0.26 標記被棄用了,官方文檔也提示建議設置為0將其關閉,所以個人理解使用內存映射臨時文件作為內部臨時表的溢出機制是一個糟糕的方案。
為什么要把內部臨時表默認引擎換成 TempTable ?它與 MEMORY 最大的不同是:
那么真的那么好用嗎?目前最新版本是8.0.26,還是存在一些問題的,例如: https://bugs.mysql.com/bug.php?id=98782 https://bugs.mysql.com/bug.php?id=98739 https://bugs.mysql.com/bug.php?id=99593 https://bugs.mysql.com/bug.php?id=99100
前3個都是性能問題,后面一個則可能會導致 SQL 執行時報錯:The table '/tmp/#sql639b7_13_4' is full,所以在這些問題解決前,建議設置internal_tmp_mem_storage_engine=MEMORY。
MySQL 8.0 臨時表空間也發生了變化,分為了會話臨時表空間和全局臨時表空間內,全局臨時表空間內和 MySQL 5.7 時沒什么兩樣,不過 SQL 產生的內部臨時表將存儲在會話臨時表空間中。
新參數:
shell> ls datadir/#innodb_temp
temp_10.ibt temp_2.ibt temp_4.ibt temp_6.ibt temp_8.ibt
temp_1.ibt temp_3.ibt temp_5.ibt temp_7.ibt temp_9.ibt
會話臨時表空間其實是個包含10個臨時表空間的池,會話臨時表空間在第一次請求創建磁盤臨時表時從臨時表空間池中分配給會話。一個會話最多分配兩個表空間,一個用于用戶創建的臨時表,另一個用于優化器創建的內部臨時表。當會話斷開連接時,其臨時表空間被清除并釋放回池中。
temptable_use_mmap=ON 時,如果內部臨時表超過了 temptable_max_ram 大小,使用內存映射的臨時文件用作內部臨時表的溢出機制,臨時文件放在 tmpdir 目錄下:
可以看到臨時文件數量+1,磁盤臨時表數量不變:
temptable_use_mmap=OFF 時,如果內部臨時表超過了temptable_max_ram 大小,使用 InnoDB 磁盤內部臨時表用作內部臨時表的溢出機制,存放在 innodb 會話臨時表空間中,與 MySQL 5.7 的區別是,session 斷開后就會釋放空間,不需要重啟 MySQL :
可以看到臨時文件數量不變,磁盤臨時表數量+1:
者:小不點啊
來源:www.cnblogs.com/leeSmall/p/9356535.html
一、Nginx Rewrite 規則
Rewrite規則含義就是某個URL重寫成特定的URL(類似于Redirect),從某種意義上說為了美觀或者對搜索引擎友好,提高收錄量及排名等。
語法:
rewrite <regex> <replacement> [flag]
關鍵字 || 正則 || 替代內容 || flag標記
Rewrite規則的flag標記主要有以下幾種:
last和break用來實現URL重寫,瀏覽器地址欄URL地址不變
a) 例如用戶訪問www.dbspread.com,想直接跳轉到網站下面的某個頁面,www.dbspread.com/new.index.html如何來實現呢?我們可以使用Nginx Rewrite 來實現這個需求,具體如下:在server中加入如下語句即可:
效果圖如下:
rewrite ^/$ http://www.dbspread.com/new.index.html permanent;
對應如下語法:
rewrite <regex> <replacement> [flag];
關鍵字 正則 替代內容 flag標記
正則表達式說明:
*代表前面0或更多個字符 +代表前面1或更多個字符
?代表前面0或1個字符 ^代表字符串的開始位置
$代表字符串結束的位置 。為通配符,代表任何字符
b)例如多個域名跳轉到同一個域名,nginx rewrite規則寫法如下:
格式:
rewrite <regex> <replacement> [flag];
關鍵字 || 正則 || 替代內容 || flag標記
說明:
比如http://www.dbspread.com/download/av123.rmvb 這個視頻下載地址被其他網站引用,比如在www.test.com的index.html引用download/av123.rmvb就叫盜鏈,我們要禁止這種引用就叫做防盜鏈
在nginx的nginx.conf的server里面配置如下代碼
三、Nginx 動靜分離
Nginx動靜分離是讓動態網站里的動態網頁根據一定規則把不變的資源和經常變的資源區分開來,動靜資源做好了拆分以后,我們就可以根據靜態資源的特點將其做緩存操作,這就是網站靜態化處理的核心思路。
1). WEB項目開發時要注意,將靜態資源盡量放在一個static文件夾2). 將static靜態資源文件夾放到Nginx可以取到的位置3). 頁面要建立全局變量路徑,方便修改路徑4). 修改nginx.conf的location, 匹配靜態資源請求
body {
margin: 10px 20px;
text-align: center;
font-family: Arial, sans-serif;
background-color: red;
}
4.4 在nginx的nginx.conf中server節點新增靜態資源分離的配置
對于Nginx基礎配置,推薦之前的:后端實踐:Nginx日志配置(超詳細)
4.5 訪問頁面查看效果
Keepalived軟件起初是專為LVS負載均衡軟件設計的,用來管理并監控LVS集群系統中各個服務節點的狀態,后來又加入了可以實現高可用的VRRP (Virtual Router Redundancy Protocol ,虛擬路由器冗余協議)功能。因此,Keepalived除了能夠管理LVS軟件外,還可以作為其他服務(例如:Nginx、Haproxy、MySQL等)的高可用解決方案軟件
管理LVS負載均衡軟件實現LVS集群節點的健康檢查作為系統網絡服務的高可用性(failover)
Keepalived高可用服務之間的故障切換轉移,是通過 VRRP 來實現的。在 Keepalived服務正常工作時,主 Master節點會不斷地向備節點發送(多播的方式)心跳消息,用以告訴備Backup節點自己還活著,當主 Master節點發生故障時,就無法發送心跳消息,備節點也就因此無法繼續檢測到來自主 Master節點的心跳了,于是調用自身的接管程序,接管主Master節點的 IP資源及服務。而當主 Master節點恢復時,備Backup節點又會釋放主節點故障時自身接管的IP資源及服務,恢復到原來的備用角色。
說明:keepalived的主從切換和redis的主從切換是不一樣的,keepalived的主節點掛了以后,從節點變為主節點,之前的主節點恢復以后繼續做主節點。redis的主節點掛了以后,重新恢復以后變為從節點
說明:
虛擬ip(VIP):192.168.152.200,對外提供服務的ip,也可稱作浮動ip192.168.152.130:nginx + keepalived master 主192.168.152.129:nginx + keepalived backup 從192.168.152.129:tomcat-8080192.168.152.129:tomcat-8081
環境準備:
centos6、jdk
虛擬ip(VIP):192.168.152.200,對外提供服務的ip,也可稱作浮動ip
192.168.152.130:nginx + keepalived master 主
192.168.152.129:nginx + keepalived backup 從
192.168.152.129:tomcat-8080
192.168.152.129:tomcat-8081
nginx和tomcat的環境準備請查看我的前一篇關于nginx的文章
注:192.168.152.129(keepalived從節點) 與 192.168.152.130(keepalived主節點)先安裝好nginx + keepalived
下載壓縮包:
wget www.keepalived.org/software/keepalived-1.3.5.tar.gz
解壓縮:
tar -zxvf keepalived-1.3.5.tar.gz
進入解壓縮以后的文件目錄:
cd keepalived-1.3.5
編譯安裝:./configure --prefix=/usr/local/keepalived系統提示警告 *** WARNING - this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.yum -y install libnl libnl-devel再次執行./configure --prefix=/usr/local/keepalived系統提示錯誤 configure: error: libnfnetlink headers missingyum install -y libnfnetlink-devel再次執行./configure --prefix=/usr/local/keepalived
make && make install
到此keepalived安裝完成,但是接下來還有最關鍵的一步,如果這一步沒有做后面啟動keepalived的時候會報找不到配置文件的錯誤
Configuration file '/etc/keepalived/keepalived.conf' is not a regular non-executable file
安裝完成后,進入安裝目錄的etc目錄下,將keepalived相應的配置文件拷貝到系統相應的目錄當中。keepalived啟動時會從/etc/keepalived目錄下查找keepalived.conf配置文件
mkdir /etc/keepalived
cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived
5.3 修改keepalived從節點192.168.152.129的/etc/keepalived/keepalived.conf配置文件
5.4 檢查nginx是否啟動的shell腳本
/usr/local/src/check_nginx_pid.sh
#!/bin/bash
#檢測nginx是否啟動了
A=`ps -C nginx --no-header |wc -l`
if [ $A -eq 0 ];then #如果nginx沒有啟動就啟動nginx
/usr/local/nginx/sbin/nginx #重啟nginx
if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then #nginx重啟失敗,則停掉keepalived服務,進行VIP轉移
killall keepalived
fi
fi
5.5 192.168.152.130(keepalived主節點)和 192.168.152.129(keepalived從節點)的nginx的配置文件nginx.conf
user root root; #使用什么用戶啟動NGINX 在運行時使用哪個用戶哪個組
worker_processes 4; #啟動進程數,一般是1或8個,根據你的電腦CPU數,一般8個
worker_cpu_affinity 00000001 00000010 00000100 00001000; #CPU邏輯數——把每個進程分別綁在CPU上面,為每個進程分配一個CPU
#pid /usr/local/nginx/logs/nginx.pid
worker_rlimit_nofile 102400; #一個進程打開的最大文件數目,與NGINX并發連接有關系
#工作模式及連接數上限
events
{
use epoll; #多路復用IO 基于LINUX2.6以上內核,可以大大提高NGINX的性能 uname -a查看內核版本號
worker_connections 102400; #單個worker process最大連接數,其中NGINX最大連接數=連接數*進程數,一般1GB內存的機器上可以打開的最大數大約是10萬左右
multi_accept on; #盡可能多的接受請求,默認是關閉狀態
}
#處理http請求的一個應用配置段
http
{
#引用mime.types,這個類型定義了很多,當web服務器收到靜態的資源文件請求時,依據請求文件的后綴名在服務器的MIME配置文件中找到對應的MIME #Type,根據MIMETYPE設置并response響應類型(Content-type)
include mime.types;
default_type application/octet-stream; #定義的數據流,有的時候默認類型可以指定為text,這跟我們的網頁發布還是資源下載是有關系的
fastcgi_intercept_errors on; #表示接收fastcgi輸出的http 1.0 response code
charset utf-8;
server_names_hash_bucket_size 128; #保存服務器名字的hash表
#用來緩存請求頭信息的,容量4K,如果header頭信息請求超過了,nginx會直接返回400錯誤,先根據client_header_buffer_size配置的值分配一個buffer,如果##分配的buffer無法容納request_line/request_header,那么就會##再次根據large_client_header_buffers配置的參數分配large_buffer,如果large_buffer還是無#法容納,那么就會返回414(處理request_line)/400(處理request_header)錯誤。
client_header_buffer_size 4k;
large_client_header_buffers 4 32k;
client_max_body_size 300m; #允許客戶端請求的最大單文件字節數 上傳文件時根據需求設置這個參數
#指定NGINX是否調用這個函數來輸出文件,對于普通的文件我們必須設置為ON,如果NGINX專門做為一個下載端的話可以關掉,好處是降低磁盤與網絡的IO處理數及#系統的UPTIME
sendfile on;
#autoindex on;開啟目錄列表訪問,適合下載服務器
tcp_nopush on; #防止網絡阻塞
#非常重要,根據實際情況設置值,超時時間,客戶端到服務端的連接持續有效時間,60秒內可避免重新建立連接,時間也不能設太長,太長的話,若請求數10000##,都占用連接會把服務托死
keepalive_timeout 60;
tcp_nodelay on; #提高數據的實時響應性
client_body_buffer_size 512k; #緩沖區代理緩沖用戶端請求的最大字節數(請求多)
proxy_connect_timeout 5; #nginx跟后端服務器連接超時時間(代理連接超時)
proxy_read_timeout 60; #連接成功后,后端服務器響應時間(代理接收超時)
proxy_send_timeout 5; #后端服務器數據回傳時間(代理發送超時)
proxy_buffer_size 16k; #設置代理服務器(nginx)保存用戶頭信息的緩沖區大小
proxy_buffers 4 64k; #proxy_buffers緩沖區,網頁平均在32k以下的話,這樣設置
proxy_busy_buffers_size 128k; #高負荷下緩沖大小
proxy_temp_file_write_size 128k; #設定緩存文件夾大小,大于這個值,將從upstream服務器傳
gzip on; #NGINX可以壓縮靜態資源,比如我的靜態資源有10M,壓縮后只有2M,那么瀏覽器下載的就少了
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2; #壓縮級別大小,最小1,最大9.值越小,壓縮后比例越小,CPU處理更快,為1時,原10M壓縮完后8M,但設為9時,壓縮完可能只有2M了。一般設置為2
gzip_types text/plain application/x-javascript text/css application/xml; #壓縮類型:text,js css xml 都會被壓縮
gzip_vary on; #作用是在http響應中增加一行目的是改變反向代理服務器的緩存策略
#日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' #ip 遠程用戶 當地時間 請求URL
'$status $body_bytes_sent "$http_referer" ' #狀態 發送的大小 響應的頭
'"$http_user_agent" $request_time'; #客戶端使用的瀏覽器 頁面響應的時間
#動態轉發
upstream web1 {
#每個請求按訪問ip的hash結果分配,這樣每個訪客固定訪問一個后端服務器,可以解決session的問題。配置了ip_hash就沒有負載均衡的效果了,每次訪問的都是同一個tomcat
#ip_hash;
#轉發的后端的tomcat服務器,weight表示轉發的權重,越大轉發的次數越多,機器性能不一樣配置的weight值不一樣
server 192.168.152.129:8080 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.152.129:8081 weight=1 max_fails=2 fail_timeout=30s;
}
upstream web2 {
server 192.168.152.129:8090 weight=1 max_fails=2 fail_timeout=30s;
server 192.168.152.129:8091 weight=1 max_fails=2 fail_timeout=30s;
}
server {
listen 80; #監聽80端口
server_name www.dbspread.com; #域名
#rewrite規則
index index.jsp index.html index.htm;
root /usr/local/nginx/html; #定義服務器的默認網站根目錄位置
#重定向
if ($host != 'www.dbspread.com' ){
rewrite ^/(.*)$ http://www.dbspread.com/$1 permanent;
}
#防盜鏈
location ~* \.(rmvb|jpg|png|swf|flv)$ { #rmvb|jpg|png|swf|flv表示對rmvb|jpg|png|swf|flv后綴的文件實行防盜鏈
valid_referers none blocked www.dbspread.com; #表示對www.dbspread.com此域名開通白名單,比如在www.test.com的index.html引用download/av123.rmvb,無效
root html/b;
if ($invalid_referer) { #如果請求不是從www.dbspread.com白名單發出來的請求,直接重定向到403.html這個頁面或者返回403
#rewrite ^/ http://www.dbspread.com/403.html;
return 403;
}
}
#監聽完成以后通過斜桿(/)攔截請求轉發到后端的tomcat服務器
location /
{
#如果后端的服務器返回502、504、執行超時等錯誤,自動將請求轉發到upstream負載均衡池中的另一臺服務器,實現故障轉移。
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_set_header Host $host; #獲取客戶端的主機名存到變量Host里面,從而讓tomcat取到客戶端機器的信息
proxy_set_header X-Real-IP $remote_addr; #獲取客戶端的主機名存到變量X-Real-IP里面,從而讓tomcat取到客戶端機器的信息
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#rewrite ^/$ http://www.dbspread.com/new.index.html permanent;#用戶訪問www.dbspread.com,想直接跳轉到網站下面的某個頁面:www.dbspread.com/new.index.html
proxy_pass http://web1; #跳轉到對應的應用web1
}
# location ~ .*\.(php|jsp|cgi|shtml)?$ #動態分離 ~匹配 以.*結尾(以PHP JSP結尾走這段)
# {
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_pass http://jvm_web2;
# }
#靜態分離 ~匹配 以.*結尾(以html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css結尾走這段),當然不是越久越好,如果有10000個用戶在線,都保存幾個月,系統托跨
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
{
root /var/local/static; #靜態資源存放在nginx的安裝機器上
#proxy_pass http://www.static.com; #靜態資源也可存放在遠程服務器上
expires 30d;
}
#日志級別有[debug|info|notice|warn|error|crit] error_log 級別分為 debug, info, notice, warn, error, crit 默認為crit, 生產環境用error
#crit 記錄的日志最少,而debug記錄的日志最多
access_log /usr/local/logs/web2/access.log main;
error_log /usr/local/logs/web2/error.log crit;
}
}
到這一步環境準備已完成,相關的配置也修改完成,下面我們來查看效果
5.6 配置hosts域名映射
192.168.152.200 www.dbspread.com
注意:這里192.168.152.200 是keepalived里面virtual_ipaddress配置的虛擬ip
virtual_ipaddress {
192.168.152.200 # 定義虛擬ip(VIP),可多設,每行一個
}
到這一步環境準備已完成,相關的配置也修改完成,下面我們來查看效果
5.7 分別啟動192.168.152.129的兩個tomcat
5.8 分別啟動192.168.152.130(keepalived主節點)和
192.168.152.129(keepalived從節點)的keepalived的
啟動命令:
/usr/local/keepalived/sbin/keepalived
可以看到keepalived和nginx都啟動了
在瀏覽器輸入www.dpspread.com域名訪問
可以看到從節點變為主節點了
在瀏覽器輸入地址www.dpspread.com訪問,可以看到訪問正常
可以看到主節點重新啟動以后變為主節點了
之前變為主節點的從節點又變回從節點了
CSDN 編者按】MySQL之父Monty有著四十多年的編程經驗,從兒時的興趣到長大后的深耕,他在編程領域不斷鉆研,最終成為編程大師。《新程序員004》帶你走進Monty的程序人生,談談他在編程方面的最新感悟以及對未來的預測。
作者 | 郭露 責編 | 徐威龍
出品 | 《新程序員》編輯部
如今,我們正處于數據爆炸的時代,軟件崛起的背后是數據的支持。而隨著開源技術的發展,越來越多的數據庫選擇創建開源社區,讓更多的開發者參與到數據庫的建設中來。
在開源數據庫領域中,Michael "Monty" Widenius(通常稱為Monty)絕對是不得不提的代表人物。有著四十多年編程經驗的Monty是MySQL和MariaDB的作者,也是開源軟件運動的著名倡導者,即便是現在他也在堅持寫代碼。作為影響了幾代技術人的數據庫,MySQL所取得的成就無需多言。而最初作為MySQL分支立項的MariaDB也在迅速成長,同樣在數據庫中贏得了一席之地。
Monty近照(圖源自Wiki)
作為在技術屆游歷半生的資深“程序員”,Monty對編程的理解也有許多獨到之處,他認為只有學習編程20年以上,才能像讀懂音樂一樣,看出編程之美。除此之外,他還表示:“寫代碼時要盡量將代碼一次性寫成,而不是寫完后再沒完沒了地修改。”只有做到這一點,才能稱得上是一名優秀的程序員。而這也是他長久以來所遵循的“編程法則”。
近期,《新程序員》有機會邀請Monty分享他的程序人生,談談他對于技術的感悟,以及對于數據庫發展的看法與心得。
1962年,Monty出生在芬蘭首都赫爾辛基,小時候的他便對計算機有著濃厚的興趣。1978年,年僅16歲的Monty用他一整個暑假打工攢的錢買了人生中的第一臺電腦,并且用BASIC語言寫下了第一行代碼REM,從此以后他便與編程結下了不解之緣。三年后,Monty被北歐著名高校赫爾辛基理工大學錄取,但由于自己的學習理念與學校不同,他感到在學校學不到什么東西,因此沒過多久就輟學了。1981年。離開了校園的Monty開始在荷蘭的一家叫做Tapio Laakso Oy的公司當程序員。在近十年之后,34歲的Monty開發出了歷史上最流行的開源數據庫之一——MySQL。
Monty能開發出MySQL并非偶然,他在編程上投入了大量的時間。根據早期的資料顯示,就連別人去參加聚會時,他也在家里寫代碼。在他看來,好的代碼不需要一次又一次地重寫,而是在開始寫之前,就抱有一次寫成的心態。正因為如此,直到多年后的今天,Monty仍然直言“自己在編程方面具有一定的天賦”。
除了Monty,MySQL的誕生還離不開David Axmark和Allan Larsson。早在1980年,17歲的Monty打算將自己的計算機內存從8KB提高到16KB。機緣巧合之下,他去往瑞典Allan Larsson的電腦店尋求幫助,在那里認識了同樣也是寫代碼的David Axmark,之后三人就成為了親密的合作伙伴,經常一起寫代碼,解決編程過程中遇到的問題。1995年,三人創立了MySQL AB,MySQL AB就是MySQL的雛形。這其中Monty負責了大部分的開發工作。最終,在1996年10月,MySQL首個版本發布,從此掀開了數據庫歷史的重要一章。
到了1999年,MySQL的迅速發展已經引起了許多人的注意, Oracle表示要以5000萬美元的價格收購MySQL。然而Monty三人并不想止步于此,也不想失去對MySQL的控制,因此拒絕了這次收購。
隨著時間的推移,MySQL迅速發展, 但同時市場上也出現了包括PostgreSQL在內的競爭對手數據庫。為了在競爭中脫穎而出,MySQL開始接受融資,以獲得更大的發展機會。到了2003年,MySQL實現了高達400萬的安裝次數,較兩年前翻了一番,成為了當時全世界最受歡迎的開源數據庫。
2008年1月16日,Sun Microsystems以高達10億美元的價格收購MySQL(然而次年Sun又被Oracle收購)。當時Monty擔心MySQL可能會受到Oracle的控制而變得商業化,并且如果Oracle一家獨大的話,可能會引發數據庫領域的不良競爭。于是他發起了一場拯救MySQL的請愿活動,并在MySQL閉源前將其分化,以其小女兒Maria的名字命名創建了MariaDB。
設計MariaDB的初衷(圖源自MariaDB官網)
MariaDB開源數據庫可以看做是MySQL的一個分支,主要由開源社區維護,目的是要完全兼容MySQL,甚至包括API和命令行。MariDB推出后,不少MySQL的員工都轉而投向MariaDB,甚至是原先使用MySQL的各大公司也將數據庫遷移到MariaDB上,其中就包括谷歌和維基百科。Monty表示:“與MySQL相比,MariaDB更加成熟,擁有更大的研發優勢,并且在安全性修復方面也更加出色。”直到現在,Monty依舊親自參與MariaDB的開發維護,可以說他的工作重心都在MariaDB上。
Monty的小女兒Maria(圖源自MariaDB官網)
鄒欣:你在創建MariaDB時,曾提到要把它打造成第二個MySQL,并且確保它是開源的。那么對于數據庫而言,為什么開源這么重要呢?
Monty:對于任何大型項目來說,開源都是非常重要的。既然要和巨頭競爭,你就要有和他們一樣的工具。在我看來,開源很適合用于軟件開發,尤其是當公司規模還不大的時候。這個時候你很難兼顧公司和用戶的需求,因此需要聽取別人的想法。而開源就意味著可以獲得社區的幫助,能夠了解其他人的觀點。有了開源,你可以開發出更好的產品,同時產品也能夠獲得更大的影響力。
鄒欣:不過開源的一大弊端就是聲音太多,需求不一,這種情況下該如何保證數據庫能滿足大多數人的需求呢?
Monty:要解決這個問題,就需要確保數據庫足夠靈活,這樣才能滿足大多數人的需求。在這一點上,MySQL和MariaDB的做法是建立各種性能不一的存儲引擎,人們可以針對具體需求開發自己的存儲引擎 。
事實上,對于那些有需求的人來說,MariaDB依舊是一個優秀的工具。而對于要求數據庫體量較小且運行較快的人來說,MariaDB同樣是一個不錯的選擇。在開發MariaDB時,我們考慮到了各種可能性,使它能夠保持良好的性能。
鄒欣:AI技術的發展讓人們對數據庫的期待發生了轉變,今天數據庫是否能夠與AI技術結合,從而擁有數據決策能力?
Monty:對于數據庫來說,最重要的是要處理AI需要的不同結構。因此我們添加了對JSON的支持,用于在MariaDB中支持動態列。這樣人們就可以儲存并檢索數據,同時保留自己想要的格式。通常AI并不是要創造內容,更多的是實現文件自動化,這就是我們對于MariaDB所抱的期望。因此這兩者完全是不同的工具集。
除此之外,我們還需要一個良好的環境,其中每一個部分都是可替代的,要確保自己不被束縛。一旦有了束縛的存在,那么你的應用程序就需要與靜態系統相結合,這會大大降低靈活性。我認為對于數據庫來說,要注意的一點就是,要確保數據庫容易上手,而這恰恰意味著更多的AI技術能夠整合到數據庫中。
鄒欣:在中國IT行業有這樣一種現象,認為程序員過了35歲就要轉型,進入管理層或是其他領域。對此你怎么看?
Monty:這在很多地方都很常見。這個現象的主要原因在于程序員在管理崗位上的工資要比單純做編程高。因為很少有公司會重視優秀的程序員,這就導致了收入的差異。我認為,如今程序員沒有晉升的空間。與其讓他們被迫轉型,不如建立一個能提升他們收入的新環境。要想做到這一點,公司就得讓他們承擔更多的責任。要程序員擔任管理崗位也行,但前提是仍然要保證他們每天寫代碼的時間。畢竟好的經理人到處都是,好的程序員卻千里挑一。
鄒欣:據我所知,你仍然每天在堅持寫代碼,但同時也要負責MariaDB的運營和管理。那么,你如何平衡這兩個身份呢?
Monty:我認為在寫代碼這方面,我還是有一點天分的,所以我想堅持下去。我會雇用經理人為我工作,這樣我就可以做我最擅長的事情。我會參與代碼審查、社區運營以及MariaDB的相關決策。但同時我也會花很多時間維系客戶,與不同國家的開發者交流,其中有許多中國的開發者。我認為,除了寫代碼之外,這是我做的最重要的事。總而言之,我會雇傭經理人來做一部分管理,讓我有足夠的時間在真正重要的事情上。
鄒欣:聽聞你從20世紀80年代就開始在家辦公,如今這一辦公方式也開始流行起來,對于遠程辦公你有什么看法?
Monty:事實上我認為遠程辦公是非常靈活的工作方式,自1981年開始我就在家辦公(MySQL和MariaDB團隊都是在家辦公)。我們招人之前可能從來沒見過他們,甚至都不知道對面是個人還是團隊。但是我們的效率一直都在線。能做到這一點的前提,是要對跟自己聯系密切的同事有足夠的了解。至少熟悉他們的樣貌。
我認為對于八成的開發者而言,在家辦公是一個不錯的選擇。可能有一小部分開發者,他們的工作負擔比較重,在家提不起精神來。這就需要他們出去走走,見見朋友或是接觸新事物。我剛開始在家辦公的時候,也會擔心這樣是不是會被孤立。所以后來我會定期在家里舉行派對,我也會親自下廚。我們團隊每年也會在一起待上一段時間。
鄒欣:對于你來說,在過去幾年數據庫領域發生了哪些大的變化?
Monty:在過去的五年或七年間,學習SQL(結構化查詢語言)開始成為一種趨勢。但是人們發現SQL過于復雜,因此還需要學習其他語言。于是許多公司開始創新,采用NoSQL(非關系型數據庫) 進行開發。但在過去的幾年里,人們逐漸意識到NoSQL并不是萬金油。但選擇關系型數據庫是否能夠涵蓋NoSQL提供的功能?很明顯,有的可以 ,有的不行。因此我認為,在當下的環境中,對于數據庫的要求在于要保證云端以及本地部署。
我們不能被一個數據庫束縛。云端提供的是靈活性,你能在數據庫中運行軟件,即使是有成百上千個軟件,而且本地部署的價格更低,控制權限更高,這一點是云端無法提供的。但我依然認為云端有它的優勢,我們要在兩者之間找到平衡。
鄒欣:30年前我從大學畢業時,人們提到數據庫一般是指去銀行辦業務。現在看來,人們有了更多的選擇,我們能夠借助數據庫實現許多功能。但提到數據庫開發時,人們往往指的是“后端”。那么,對于一個開發者或是畢業生想要進入數據庫領域的人來說,你會給他們怎樣的職業建議?
Monty:在我看來,從開源數據庫開始入門更簡單。現在開源數據庫很多,如果你的確想成為專家級別的人,想要得到一份很好的工作,你可以找一個合適的數據庫,并學習如何進行優化。但同時你也需要了解人們的需求,你可以和從事這一行的同學交流,并且學習解決數據庫中的實際問題。
鄒欣:除了多參與開源項目之外,對于中國開發者你還有哪些想說的?
Monty:我和來自中國的開發者有過非常多的互動,他們非常棒,在編程上表現得非常優秀。不過我在感到驚喜的同時,也感到非常惋惜,因為他們都想轉型做管理。我認為這是最大的錯誤。他們需要讓老板給自己派更多的任務,當然也可以做管理,但前提是能讓自己寫代碼。還是那句話:找到一個好經理很容易,但找到一個好的程序員很難。一個非常出色的程序員可以抵五個一般的程序員,關鍵是你想當一個好的程序員還是一個平庸的經理。對于所有中國開發者,我只想說,請堅持你的工作,你已經做得非常好了,一定不要停止寫代碼。
【參考資料】
https://zh.wikipedia.org/wiki/%E7%B1%B3%E5%8D%A1%E5%9F%83%E7%88%BE%C2%B7%E7%B6%AD%E5%BE%B7%E7%B4%90%E6%96%AF
https://blog.openocean.vc/founder-stories-a-hackers-hacker-6d5054c90564
https://huskyintelligence.com/leverage-open-source-code/
http://monty-says.blogspot.com/2009/12/help-saving-mysql.html
https://www.geeksforgeeks.org/introduction-of-mariadb/
http://www.josetteorama.com/from-mysql-to-mariadb-michael-%e2%80%9cmonty%e2%80%9d-widenius-talks-about-databases-and-his-projects/
https://dri.es/the-history-of-mysql-ab
https://mariadb.org/wp-content/uploads/2019/11/MySQL-MariaDB-story.pdf
*請認真填寫需求信息,我們會在24小時內與您取得聯系。