者|鄒晟 去哪兒網基礎平臺技術專家
近幾年,云原生和容器技術非常火爆,且日趨成熟,眾多企業慢慢開始容器化建設,并在云原生技術方向上不斷的探索和實踐。基于這個大的趨勢, 2020 年底 Qunar 也向云原生邁出了第一步——容器化。
云原生是一系列可以為業務賦能的技術架構準則,遵循它可以使應用具有擴展性、伸縮性、移植性、韌性等特點。云原生也是下一代技術棧的必選項,它可以讓業務更敏捷。通過實踐 DevOps、微服務、容器化、可觀測性、反脆弱性(chaos engineering)、ServiceMesh、Serverless 等云原生技術棧,我們便可以享受到云原生帶來的技術紅利。
一項新技術要在企業內部落地從來都不是一蹴而就的,Qunar 的容器化落地也同樣如此。Qunar 的容器后落地主要經歷了 4 個時間節點:
2014 - 2015:
業務線同學開始嘗試通過 Docker、Docker-Compose 來解決聯調環境搭建困難的問題,不過由于 Docker-Compose 的編排能力有限、無法解決真實的環境問題,因此容器化最后也沒有推行起來。
2015 - 2017:
ops 團隊把為了提高 ELK 集群的運維效率,把 ES 集群遷移到了 Mesos 平臺上。后來隨著 K8s 生態的成熟,把 ES 集群從 Mesos 遷移到了 K8s 平臺,運維效率得到了進一步的提升。
2018 - 2019:
在業務需求不斷增加的過程中,業務對測試環境的交付速度和質量有了更高的要求,為了解決 MySQL 的交付效率問題( 并發量大時,網絡 IO 成為了瓶頸,導致單個實例交付時長在分鐘級),為了解這個問題,我們把 MySQL 容器化,通過 Docker on host 的模式可以在 10 秒之內就可以交付一個 MySQL 實例。
2020 - 2021:
云原生技術已經非常成熟了,Qunar 也決定通過擁抱云原生來為業務增加勢能。在各個團隊齊心協力的努力下,300+ 的 P1、P2 應用已經完成了容器化,并且計劃在 2021 年年底全部業務應用實現容器化。
Qunar 在做容器化過程中,各個系統 Portal 平臺、中間件、ops 基礎設施、監控等都做了相應的適配改造,改造后的架構矩陣如下圖所示。
Portal:Qunar 的 PaaS 平臺入口,提供 CI/CD 能力、資源管理、自助運維、應用畫像、應用授權(db 授權、支付授權、應用間授權)等功能。
運維工具:提供應用的可觀測性工具, 包括 watcher(監控和報警)、bistoury (Java 應用在線 Debug)、qtrace(tracing 系統)、loki/elk(提供實時日志/離線日志查看)。
中間件:應用用到的所有中間件,mq、配置中心、分布式調度系統 qschedule、dubbo 、mysql sdk 等。
虛擬化集群:底層的 K8s 和 OpenStack 集群。
Noah:測試環境管理平臺,支持應用 KVM/容器混合部署。
主要改造點:
應用畫像: 把應用相關的運行時配置、白名單配置、發布參數等收斂到一起,為容器發布提供統一的聲明式配置。
授權系統: 應用所有的授權操作都通過一個入口進行,并實現自動化的授權。
K8s 多集群方案: 通過調研對比,KubeSphere 對運維優化、壓測評估后也滿足我們對性能的要求,最終我們選取了 KubeSphere 作為多集群方案。
改造關注點:由于容器化后,IP 經常變化是常態,所以各個公共組件和中間件要適配和接受這種變化。
為了幫助業務快速平滑地遷移到容器,我們制定了一些規范和自動化測試驗證等操作來實現這個目標。
容器化的前置條件: 應用無狀態、不存在 post_offline hook(服務下線后執行的腳本)、check_url 中不存在預熱操作。
測試環境驗證: 自動升級 SDK、自動遷移。我們會在編譯階段幫助業務自動升級和更改 pom 文件來完成 SDK 的升級,并在測試環境部署和驗證,如果升級失敗會通知用戶并提示。
線上驗證: 第一步線上發布,但不接線上流量,然后通過自動化測試驗證,驗證通過后接入線上流量。
線上 KVM 與容器混部署:保險起見,線上的容器和 KVM 會同時在線一段時間,等驗證期過后再逐步下線 KVM。
線上全量發布: 確認服務沒問題后,下線 KVM。
觀察: 觀察一段時間,如果沒有問題則回收 KVM。
KVM 場景中 hook 腳本使用場景介紹:
preStart hook : 用戶在這個腳本中會自定義命令,比如環境準備。
preOnline hook:用戶會定義一些數據預熱操作等,這個動作需要在應用 checkurl 通過并且接入流量前執行。
問題點:
K8s 原生只提供了 preStop、postStart 2 種 hook, 它們的執行時機沒有滿足上述 2 個 KVM 場景下業務用到的 hook。
分析與解決過程:
preStart hook:在 entrypoint 中注入 preStart hook 階段,容器啟動過程中發現有自定義的 preStart 腳本則執行該腳本,至于這個腳本的位置目前規范是定義在代碼指定目錄下。
preOnline hook:由于 preOnline 腳本執行時機是在應用 checkurl 通過后,而應用容器是單進程,所以在應用容器中執行這個是行不通的。而 postStart hook 的設計就是異步的,與應用容器的啟動也是解耦的, 所以我們初步的方案選擇了 postStart hook 做這個事情。實施方案是 postStart hook 執行后會不斷輪詢應用的健康狀態,如果健康檢測 checkurl 通過了, 則執行 preOnline 腳本。腳本成功后則進行上線操作, 即在應用目錄下創建 healthcheck.html 文件,OpenResty 和中間件發現這個文件后就會把流量接入到這個實例中。
按照上面的方案,Pod 的組成設計如下:
場景介紹:
在容器發布過程中如果應用啟動失敗,我們通過 K8s API 是拿不到實時的標準輸入輸出流,只能等到發布設置的超時閾值,這個過程中發布人員心里是很焦急的,因為不確定發生了什么。如下圖所示,部署過程中應用的更新工作流中什么都看不到。
問題點:
K8s API 為什么拿不到標準輸入輸出?
分析與解決過程:
通過 kubectl logs 查看當時的 Pod 日志,什么都沒有拿到,超時時間過后才拿到。說明問題不在程序本身,而是在 K8s 的機制上;
查看 postStart Hook 的相關文檔,有一段介紹提到了 postHook 如果執行時間長或者 hang 住,容器的狀態也會 hang 住,不會進入 running 狀態, 看到這條信息,大概猜測到罪魁禍首就是這個 postStart hook 了。
基于上面的猜測,把 postStart hook 去掉后測試,應用容器的標準輸入可以實時拿到了。
找到問題后,解決方法也就簡單了,把 postStart hook 中實現的功能放到 Sidecar 中就可以解決。至于 Sidecar 如何在應用容器的目錄中創建 healthcheck.html 文件,就需要用到共享卷了。新的方案設計如下:
使用上述方案后,發布流程的標準輸入輸出、自定義 hook 腳本的輸出、Pod 事件等都是實時可見的了, 發布過程更透明了。
場景介紹:
我們的應用是多機房多集群部署的,當一個應用的新版本發布時,由于應用的實例數較多,有 50+ 個并發從 harbor 拉取鏡像時,其中一些任務收到了鏡像拉取超時的報錯信息,進而導致整個發布任務失敗。超時時間是 kubelet 默認設置的 1 分鐘。
分析與解決:
通過排查最終確認是 harbor 在并發拉取鏡像時存在性能問題,我們采取的優化方案是通用的 p2p 方案,DragonFly + Harbor。
場景介紹:
應用發布過程中調用授權接口失敗,K8s 的自愈機制會不斷重建容器并重新授權,并發量比較大,最終把授權服務拖垮。
我們的容器授權方案如下:
Pod init 容器啟動時進行調研授權接口進行授權操作,包括 ACL 和 mysql 的白名單。
容器銷毀時會執行 Sidecar 容器的 preStop hook 中執行權限回收操作。
問題點:
ACL 授權接口涉及到了防火墻,QPS 比較低,大量容器進行 ACL 授權時把服務拖垮 。
分析與解決:
為了解決上述的問題,限量和降低授權接口調用次數是有效的解決方式。我們采取了下面幾個措施:
init 容器中的重試次數限制為 1 次。
授權接口按應用和 IP 限流, 超過 3 次則直接返回失敗,不會再進行授權操作。
ACL 中涉及的一些通用的端口,我們統一做了白名單,應用無需再進行授權操作。
KVM 場景 Debug 介紹:
在開發 Java 應用的過程中,通過遠程 Debug 可以快速排查定位問題,因此是開發人員必不可少的一個功能。Debug 具體流程: 開發人員在 Noah 環境管理平臺的界面點擊開啟 Debug, Noah 會自動為該 Java 應用配置上 Debug 選項,-Xdebug -Xrunjdwp: transport=dt_socket, server=y, suspend=n, address=127.0.0.1:50005,并重啟該 Java 應用,之后開發人員就可以在 IDE 中配置遠程 Debug 并進入調試模式了。
容器場景的 Debug 方案:
測試環境的 Java 應用默認開啟 Debug 模式,這樣也避免了更改 Debug 重建 Pod 的過程,速度從 KVM 的分鐘級到現在的秒級。當用戶想開啟 Debug 時,Noah 會調用 K8s exec 接口執行 socat 相關命令進行端口映射轉發,讓開發人員可以通過 socat 開的代理連接到 Java 應用的 Debug 端口。
問題點:
容器場景下在用戶 Debug 過程中,當請求走到了設置的斷點后,Debug 功能失效。
分析與解決過程:
復現容器場景下 Debug,觀察該 Pod 的各項指標,發現 Debug 功能失效的時候系統收到了一個 liveness probe failed,kill pod 的事件。根據這個事件可以判斷出當時 liveness check 失敗,應用容器才被 kill 的,應用容器重啟代理進程也就隨之消失了,Debug 也就失效了。
關于 Debug 過程 checkurl 為什么失敗的問題,得到的答案是 Debug 時當請求走到斷點時,整個 JVM 是 hang 住的,這個時候任何請求過來也會被 hang 住,當然也包括 checkurl,于是我們也特地在 KVM 場景和容器場景分布做了測試,結果也確實是這樣的。
臨時解決方案是把斷點的阻斷級別改為線程級的,這樣就不會阻斷 checkurl 了, idea 中默認的選項是 Suspend All,改為 Suspend Thread 即可。不過這個也不是最優解,因為這個需要用戶手工配置阻斷級別,有認知學習成本。
回到最初的問題上,為什么容器場景下遇到這個問題,而 KVM 沒有,主要是因為容器場景 K8s 提供了自愈能力,K8s 會定時執行 liveness check, 當失敗次數達到指定的閾值時,K8s 會 kill 掉容器并重新拉起一個新的容器。
那我們只好從 K8s 的 liveness 探針上著手了,探針默認支持 exec、tcp 、httpGet 3 種模式,當前使用的是 httpGet,這種方式只支持一個 url, 無法滿足這個場景需求。經過組內討論, 最后大家決定用這個表達式 (checkurl == 200) || (socat process && java process alive) 在作為應用的 liveness 檢測方式,當 Debug 走到斷點的時候, 應用容器就不會阻斷了, 完美的解決了這個問題。
以上就是我們落地容器化過程中遇到的幾個問題與我們的解決思路。其中很重要的一點是從 KVM 遷移到容器時需要考慮用戶的使用習慣、歷史功能兼容等要點,要做好兼容和取舍,只有這樣容器化落地才會更順暢。
多集群穩定性治理
讓可觀測性數據更全面、覆蓋度更廣,進而完善我們的 APM 系統,提升排查問題效率。
通過實施混沌工程來驗證、發現和消除容器化場景的穩定性盲區。
提高資源利用率
根據業務指標實現彈性擴縮容。
根據應用的歷史數據智能的調整 requests。
ServiceMesh 方案落地
本文由博客一文多發平臺 OpenWrite 發布!
、Tomcat 的缺省端口是多少,怎么修改?
1)找到 Tomcat 目錄下的 conf 文件夾
2)進入 conf 文件夾里面找到 server.xml 文件
3)打開 server.xml 文件
4)在 server.xml 文件里面找到下列信息
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" uriEncoding="utf-8"/>
port="8080"改成你想要的端口
2、tomcat 有哪幾種 Connector 運行模式(優化)?
bio:傳統的 Java I/O 操作,同步且阻塞 IO。maxThreads=”150”//Tomcat 使用線程來處理接收的每個請求。這個值表示Tomcat 可創建的最大的線程數。默認值 200。可以根據機器的時期性能和內存大小調整,一般可以在 400-500。最大可以在 800 左右。minSpareThreads=”25”—Tomcat 初始化時創建的線程數。默認值 4。如果當前沒有空閑線程,且沒有超過 maxThreads,一次性創建的空閑線程數量。Tomcat 初始化時創建的線程數量也由此值設置。maxSpareThreads=”75”–一旦創建的線程超過這個值,Tomcat 就會關閉不再需要的 socket 線程。默認值 50。一旦創建的線程超過此數值,Tomcat 會關閉不再需要的線程。線程數可以大致上用 “同時在線人數每秒用戶操作次數系統平均操作時間” 來計算。acceptCount=”100”—-指定當所有可以使用的處理請求的線程數都被使用時,可以放到處理隊列中的請求數,超過這個數的請求將不予處理。默認值10。如果當前可用線程數為 0,則將請求放入處理隊列中。這個值限定了請求隊列的大小,超過這個數值的請求將不予處理。connectionTimeout=”20000” –網絡連接超時,默認值 20000,單位:毫秒。設置為 0 表示永不超時,這樣設置有隱患的。通常可設置為 30000 毫秒。
nio:JDK1.4 開始支持,同步阻塞或同步非阻塞 IO。指定使用 NIO 模型來接受 HTTP 請求 protocol=”org.apache.coyote.http11.Http11NioProtocol” 指定使用 NIO 模型來接受 HTTP 請求。默認是 BlockingIO,配置為 protocol=”HTTP/1.1” acceptorThreadCount=”2” 使用 NIO 模型時接收線程的數目aio(nio.2):JDK7 開始支持,異步非阻塞 IO。
apr:Tomcat 將于 JNI 的形式調用 Apache HTTP 服務器的核心動態鏈接庫來處理文件讀取或網絡傳輸操作,從而大大地 提高 Tomcat 對靜態文件的處理性能。
<!--
<Connector connectionTimeout="20000" port="8000"
protocol="HTTP/1.1" redirectPort="8443" uriEncoding="utf-8"/>
-->
<!-- protocol 啟用 nio 模式,(tomcat8 默認使用的是 nio)(apr 模式利用系統級異步 io) -->
<!-- minProcessors 最小空閑連接線程數-->
<!-- maxProcessors 最大連接線程數-->
<!-- acceptCount 允許的最大連接數,應大于等于 maxProcessors-->
<!-- enableLookups 如果為 true,requst.getRemoteHost 會執行 DNS 查找,反向解析 ip 對應域名或主機名-->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioPro
其他配置 maxHttpHeaderSize="8192" http 請求頭信息的最大程度,超過此長度的部分不予處理。一般 8K。URIEncoding="UTF-8" 指定 Tomcat 容器的 URL 編碼格式。disableUploadTimeout="true" 上傳時是否使用超時機制enableLookups="false"--是否反查域名,默認值為 true。為了提高處理能力,應設置為 false compression="on" 打開壓縮功能compressionMinSize="10240" 啟用壓縮的輸出內容大小,默認為 2KB noCompressionUserAgents="gozilla, traviata" 對于以下的瀏覽器,不啟用壓縮 compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"
3、Tomcat 有幾種部署方式?
1)直接把 Web 項目放在 webapps 下,Tomcat 會自動將其部署
2)在 server.xml 文件上配置節點,設置相關的屬性即可
3)通過 Catalina 來進行配置:進入到 conf\Catalina\localhost 文件下,創建一個xml 文件,該文件的名字就是站點的名字。編寫 XML 的方式來進行設置。
4、tomcat 容器是如何創建 servlet 類實例?用到了什么原理?
當容器啟動時,會讀取在 webapps 目錄下所有的 web 應用中的 web.xml 文件,然后對 xml 文件進行解析,并讀取 servlet 注冊信息。然后,將每個應用中注冊的 servlet 類都進行加載,并通過反射的方式實例化。(有時候也是在第一次請求時實例化)在 servlet 注冊時加上如果為正數,則在一開始就實例化,如果不寫或為負數,則第一次請求實例化。
5.tomcat 如何優化?
1、優化連接配置.這里以 tomcat7 的參數配置為例,需要修改 conf/server.xml文件,修改連接數,關閉客戶端 dns 查詢。參數解釋:URIEncoding=”UTF-8″ :使得 tomcat 可以解析含有中文名的文件的 url,真方便,不像 apache 里還有一個 mod_encoding,還要手工編譯maxSpareThreads : 如果空閑狀態的線程數多于設置的數目,則將這些線程中止,減少這個池中的線程總數。minSpareThreads : 最小備用線程數,tomcat 啟動時的初始化的線程數。enableLookups : 這個功效和 Apache 中的 HostnameLookups 一樣,設為關閉。connectionTimeout : connectionTimeout 為網絡連接超時時間毫秒數。maxThreads : maxThreads Tomcat 使用線程來處理接收的每個請求。這個值表示 Tomcat 可創建的最大的線程數,即最大并發數。acceptCount : acceptCount 是當線程數達到 maxThreads 后,后續請求會被放入一個等待隊列,這個 acceptCount 是這個隊列的大小,如果這個隊列也滿了,就直接 refuse connection maxProcessors 與 minProcessors : 在 Java 中線程是程序運行時的路徑,是在一個程序中與其它控制線程無關的、能夠獨立運行的代碼段。它們共享相同的地址空間。多線程幫助程序員寫出 CPU 最 大利用率的高效程序,使空閑時間保持最低,從而接受更多的請求。通常 Windows 是 1000 個左右,Linux 是 2000 個左右。useURIValidationHack:我們來看一下 tomcat 中的一段源碼:
【security】
if (connector.getUseURIValidationHack()) {
String uri = validate(request.getRequestURI());
if (uri == null) {
res.setStatus(400);
res.setMessage(“Invalid URI”);
throw new IOException(“Invalid URI”);
} else {
req.requestURI().setString(uri);
// Redoing the URI decoding
req.decodedURI().duplicate(req.requestURI());
req.getURLDecoder().convert(req.decodedURI(), true);
可以看到如果把 useURIValidationHack 設成”false”,可以減少它對一些 url的不必要的檢查從而減省開銷。enableLookups=”false” :為了消除 DNS 查詢對性能的影響我們可以關閉DNS 查詢,方式是修改 server.xml 文件中的 enableLookups 參數值。disableUploadTimeout :類似于 Apache 中的 keeyalive 一樣給 Tomcat 配置 gzip 壓縮(HTTP 壓縮)功能 compression=”on” compressionMinSize=”2048″ compressableMimeType=”text/html,text/xml,text/JavaScript,text/css,text/plain” HTTP 壓縮可以大大提高瀏覽網站的速度,它的原理是,在客戶端請求網頁后,從服務器端將網頁文件壓縮,再下載到客戶端,由客戶端的瀏覽器負責解 壓縮并瀏覽。相對于普通的瀏覽過程 HTML,CSS,javascript , Text ,它可以節省 40%左右的流量。更為重要的是,它可以對動態生成的,包括 CGI、PHP ,JSP , ASP , Servlet,SHTML 等輸出的網頁也能進行壓縮,壓縮效率驚人。
1)compression=”on” 打開壓縮功能
2)compressionMinSize=”2048″ 啟用壓縮的輸出內容大小,這里面默認為2KB
3)noCompressionUserAgents=”gozilla, traviata” 對于以下的瀏覽器,不啟用壓縮
4)compressableMimeType=”text/html,text/xml” 壓縮類型最后不要忘了把 8443 端口的地方也加上同樣的配置,因為如果我們走 https 協議的話,我們將會用到 8443 端口這個段的配置,對吧?
<!–enable tomcat ssl–>
<Connector port=”8443″ protocol=”HTTP/1.1″
URIEncoding=”UTF-8″ minSpareThreads=”25″ maxSpareThreads=”
75″
enableLookups=”false” disableUploadTimeout=”true”
connectionTimeout=”20000″
acceptCount=”300″ maxThreads=”300″ maxProcessors=”1000″
minProcessors=”5″
useURIValidationHack=”false”
compression=”on” compressionMinSize=”2048″
compressableMimeType=”text/html,text/xml,text/javascript,text/css,text/plain”
SSLEnabled=”true”
scheme=”https” secure=”true”
clientAuth=”false” sslProtocol=”TLS”
keystoreFile=”d:/tomcat2/conf/shnlap93.jks” keystorePass=”aaaaaa”
/>
好了,所有的 Tomcat 優化的地方都加上了。
6.內存調優
內存方式的設置是在 catalina.sh 中,調整一下 JAVA_OPTS 變量即可,因為后面的啟動參數會把 JAVA_OPTS 作為 JVM 的啟動參數來處理。具體設置如下:
JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -
XX:NewRatio=4 -XX:SurvivorRatio=4"
其各項參數如下:-Xmx3550m:設置 JVM 最大可用內存為 3550M。
-Xms3550m:設置 JVM 促使內存為 3550m。此值可以設置與-Xmx 相同,以避免每次垃圾回收完成后 JVM 重新分配內存。
-Xmn2g:設置年輕代大小為 2G。整個堆大小=年輕代大小 + 年老代大小 +持久帶大小。持久帶一般固定大小為 64m,所以增大年輕代后,將會減小年老 代大小。此值對系統性能影響較大,Sun 官方推薦配置為整個堆的 3/8。
-Xss128k:設置每個線程的堆棧大小。JDK5.0 以后每個線程堆棧大小為 1M,以前每個線程堆棧大小為 256K。根據應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在 3000~5000 左右。
-XX:NewRatio=4:設置年輕代(包括 Eden 和兩個 Survivor 區)與年老代的比值(除去持久代)。設置為 4,則年輕代與年老代所占比值為 1:4,年輕代占整個堆棧的 1/5
-XX:SurvivorRatio=4:設置年輕代中 Eden 區域 Survivor 區的大小比值。設置為 4,則兩個 Survivor 區域一個 Eden 區的比值為 2:4,一個Survivor 區占整個年輕代的 1/6 -XX:MaxPermSize=16m:設置持久代大小為 16m。
-XX:MaxTenuringThreshold=0:設置垃圾最大年齡。如果設置為 0 的話,則年輕代對象不經過 Survivor 區,直接進入年老代。對于年老代比較多的應用,可以提高效率。如果將此值設置為一個較大值,則年輕代對象會在 Survivor 區進行多次復制,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概論。
7.垃圾回收策略調優
垃圾回收的設置也是在 catalina.sh 中,調整 JAVA_OPTS 變量。具體設置如下:
JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -
XX:+UseParallelGC -XX:MaxGCPauseMillis=100"
具體的垃圾回收策略及相應策略的各項參數如下:串行收集器(JDK1.5 以前主要的回收方式) -XX:+UseSerialGC:設置串行收集器 并行收集器(吞吐量優先) 示例:
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
-XX:+UseParallelGC
- XX:MaxGCPauseMillis=100
-XX:+UseParallelGC:選擇垃圾收集器為并行收集器。此配置僅對年輕代有效。即上述配置下,年輕代使用并發收集,而年老代仍舊使用串行收集。
-XX:ParallelGCThreads=20:配置并行收集器的線程數,即:同時多少個線程一起進行垃圾回收。此值最好配置與處理器數目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式為并行收集。JDK6.0 支持對年老代并行收集
-XX:MaxGCPauseMillis=100:設置每次年輕代垃圾回收的最長時間,如果無法滿足此時間,JVM 會自動調整年輕代大小,以滿足此值。
-XX:+UseAdaptiveSizePolicy:設置此選項后,并行收集器會自動選擇年輕代區大小和相應的 Survivor 區比例,以達到目標系統規定的最低相應時間或者收集頻率等,此值建議使用并行收集器時,一直打開。并發收集器(響應時間優先) 示例:
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
- XX:+UseConcMarkSweepGC
-XX:+UseConcMarkSweepGC:設置年老代為并發收集。測試中配置這個以后,
-XX:NewRatio=4 的配置失效了,原因不明。所以,此時年輕代大小最好用-Xmn 設置。
-XX:+UseParNewGC: 設置年輕代為并行收集。可與 CMS 收集同時使用。JDK5.0 以上,JVM 會根據系統配置自行設置,所以無需再設置此值。
-XX:CMSFullGCsBeforeCompaction:由于并發收集器不對內存空間進行壓縮、整理,所以運行一段時間以后會產生“碎片”,使得運行效率降低。此值設置運行多少次 GC 以后對內存空間進行壓縮、整理。
-XX:+UseCMSCompactAtFullCollection:打開對年老代的壓縮。可能會影響性能,但是可以消除碎片
8.共享 session 處理
目前的處理方式有如下幾種:
1).使用 Tomcat 本身的 Session 復制功能 參考 http://ajita.iteye.com/blog/1715312(Session 復制的配置)方案的有點是配置簡單,缺點是當集群數量較多時,Session 復制的時間會比 較長,影響響應的效率
2).使用第三方來存放共享 Session 目前用的較多的是使用 memcached 來管理共享 Session,借助于memcached-sesson-manager 來進行 Tomcat 的 Session 管理參考 http://ajita.iteye.com/blog/1716320(使用 MSM 管理 Tomcat 集群session)
3).使用黏性 session 的策略 對于會話要求不太強(不涉及到計費,失敗了允許重新請求下等)的場合,同一個用戶的 session 可以由 nginx 或者 apache 交給同一個 Tomcat 來處理,這就是所謂的 session sticky 策略,目前應用也比較多 參考:http://ajita.iteye.com/blog/1848665(tomcat session sticky)nginx 默認不包含 session sticky 模塊,需要重新編譯才行 優點是處理效率高多了,缺點是強會話要求的場合不合適
8.添加 JMS 遠程監控
對于部署在局域網內其它機器上的 Tomcat,可以打開 JMX 監控端口,局域網其它機器就可以通過這個端口查看一些常用的參數(但一些比較復雜的功能不支持),同樣是在 JVM 啟動參數中配置即可,配置如下:-Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168.71.38 設置 JVM 的 JMS 監控監聽的 IP地址,主要是為了防止錯誤的監聽成 127.0.0.1 這個內網地址 -Dcom.sun.management.jmxremote.port=1090 設置 JVM 的 JMS 監控的端口 -Dcom.sun.management.jmxremote.ssl=false 設置 JVM 的 JMS 監控不實用SSL -Dcom.sun.management.jmxremote.authenticate=false 設置 JVM 的 JMS 監控不需要認證
9.專業點的分析工具有
IBM ISA,JProfiler、probe 等,具體監控及分析方式去網上搜索即可
10.關于 Tomcat 的 session 數目
這個可以直接從 Tomcat 的 web 管理界面去查看即可 ;或者借助于第三方工具 Lambda Probe 來查看,它相對于 Tomcat 自帶的管理稍微多了點功能,但也不多 ;
11.監視 Tomcat 的內存使用情況
使用 JDK 自帶的 jconsole 可以比較明了的看到內存的使用情況,線程的狀態,當前加載的類的總量等;JDK 自帶的 jvisualvm 可以下載插件(如 GC 等),可以查看更豐富的信息。如果是分析本地的 Tomcat 的話,還可以進行內存抽樣等,檢查每個類的使用情況
12.打印類的加載情況及對象的回收情況
這個可以通過配置 JVM 的啟動參數,打印這些信息(到屏幕(默認也會到 catalina.log 中)或者文件),具體參數如下:
-XX:+PrintGC:輸出形式:[GC 118250K->113543K(130112K), 0.0094143secs] [Full GC 121376K->10414K(130112K), 0.0650971 secs]
-XX:+PrintGCDetails:輸出形式:[GC [DefNew: 8614K->781K(9088K),0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K),0.0436268 secs]
-XX:+PrintGCTimeStamps
-XX:+PrintGC:PrintGCTimeStamps 可與上面兩個混合使用,輸出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960secs]
-XX:+PrintGCApplicationConcurrentTime:打印每次垃圾回收前,程序未中斷的執行時間。可與上面混合使用。輸出形式:Application time: 0.5291524seconds
-XX:+PrintGCApplicationStoppedTime:打印垃圾回收期間程序暫停的時間。可與上面混合使用。輸出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:PrintHeapAtGC: 打印 GC 前后的詳細堆棧信息
-Xloggc:filename:與上面幾個配合使用,把相關日志信息記錄到文件以便分析 -verbose:class 監視加載的類的情況 -verbose:gc 在虛擬機發生內存回收時在輸出設備顯示信息 -verbose:jni 輸出 native 方法調用的相關情況,一般用于診斷 jni 調用錯誤信息
13.Tomcat 一個請求的完整過程
Ng:(nginx)
upstream yy_001{
server 10.99.99.99:8080;
server 10.99.99.100:8080;
hash $**;
healthcheck_enabled;
healthcheck_delay 3000;
healthcheck_timeout 1000;
healthcheck_failcount 2;
healthcheck_send 'GET /healthcheck.html HTTP/1.0' 'Host: wo.com'
'Connection: close';
}
server {
include base.conf;
server_name wo.de.tian;
...
location /yy/ {
proxy_pass http://yy_001;
}
首先 dns 解析 wo.de.tian 機器,一般是 ng 服務器 ip 地址 然后 ng 根據 server 的配置,尋找路徑為 yy/的機器列表,ip 和端口 最后 選擇其中一臺機器進行訪問—->下面為詳細過程
1) 請求被發送到本機端口 8080,被在那里偵聽的 Coyote HTTP/1.1Connector 獲得
2) Connector 把該請求交給它所在的 Service 的 Engine 來處理,并等待來自Engine 的回應
3) Engine 獲得請求 localhost/yy/index.jsp,匹配它所擁有的所有虛擬主機 Host
4) Engine 匹配到名為 localhost 的 Host(即使匹配不到也把請求交給該 Host處理,因為該 Host 被定義為該 Engine 的默認主機)
5) localhost Host 獲得請求/yy/index.jsp,匹配它所擁有的所有 Context
6) Host 匹配到路徑為/yy 的 Context(如果匹配不到就把該請求交給路徑名為”“的 Context 去處理)
7) path=”/yy”的 Context 獲得請求/index.jsp,在它的 mapping table 中尋找對應的 servlet
8) Context 匹配到 URL PATTERN 為*.jsp 的 servlet,對應于 JspServlet 類
9) 構造 HttpServletRequest 對象和 HttpServletResponse 對象,作為參數調用JspServlet 的 doGet 或 doPost 方法
10)Context 把執行完了之后的 HttpServletResponse 對象返回給 Host
11)Host 把 HttpServletResponse 對象返回給 Engine
12)Engine 把 HttpServletResponse 對象返回給 Connector
13)Connector 把 HttpServletResponse 對象返回給客戶 browser
14.Tomcat 工作模式?
Tomcat 是一個 JSP/Servlet 容器。其作為 Servlet 容器,有三種工作模式:獨立的 Servlet 容器、進程內的 Servlet 容器和進程外的 Servlet 容器。
進入 Tomcat 的請求可以根據 Tomcat 的工作模式分為如下兩類:Tomcat 作為應用程序服務器:請求來自于前端的 web 服務器,這可能是Apache, IIS, Nginx 等;Tomcat 作為獨立服務器:請求來自于 web 瀏覽器;
15.你怎樣給 tomcat 去調優?
JVM 參數調優:-Xms 表示 JVM 初始化堆的大小,-Xmx表示 JVM 堆的最大值。這兩個值的大小一般根據需要進行設置。當應用程序需要的內存超出堆的最大值時虛擬機就會提示內存溢出,并且導致應用服務崩潰。因此一般建議堆的最大值設置為可用內存的最大值的 80%。在 catalina.bat 中,設置 JAVA_OPTS='-Xms256m -Xmx512m',表示初始化內存為 256MB,可以使用的最大內存為 512MB。
禁用 DNS 查詢 當 web 應用程序向要記錄客戶端的信息時,它也會記錄客戶端的 IP 地址或者通過域名服務器查找機器名轉換為 IP 地址。DNS 查詢需要占用網絡,并且包括可能從很多很遠的服務器或者不起作用的服務器上去獲取對應的 IP 的過程,這樣會消耗一定的時間。為了消除 DNS 查詢對性能的影響我們可以關閉 DNS 查詢,方式是修改 server.xml 文件中的 enableLookups 參數值:
Tomcat4 Tomcat5
調整線程數 通過應用程序的連接器(Connector)進行性能控制的的參數是創建的處理請求的線程數。Tomcat 使用線程池加速響應速度來處理請求。在 Java 中線程是程序運行時的路徑,是在一個程序中與其它控制線程無關的、能夠獨立運行的代碼段。它們共享相同的地址空間。多線程幫助程序員寫出 CPU 最大利用率的高效程序,使空閑時間保持最低,從而接受更多的請求。Tomcat4 中可以通過修改 minProcessors 和 maxProcessors 的值來控制線程數。這些值在安裝后就已經設定為默認值并且是足夠使用的,但是隨著站點的擴容而改大這些值。minProcessors 服務器啟動時創建的處理請求的線程數應該足夠處理一個小量的負載。也就是說,如果一天內每秒僅發生 5 次單擊事件,并且每個請求任務處理需要 1 秒鐘,那么預先設置線程數為 5 就足夠了。但在你的站點訪問量較大時就需要設置更大的線程數,指定為參數maxProcessors 的值。maxProcessors 的值也是有上限的,應防止流量不可控制(或者惡意的服務攻擊),從而導致超出了虛擬機使用內存的大小。如果要加大并發連接數,應同時加大這兩個參數。web server 允許的最大連接數還受制于操作系統的內核參數設置,通常Windows 是 2000 個左右,Linux 是 1000 個左右。在 Tomcat5 對這些參數進行了調整,請看下面屬性:maxThreads Tomcat 使用線程來處理接收的每個請求。這個值表示 Tomcat 可創建的最大的線程數。acceptCount 指定當所有可以使用的處理請求的線程數都被使用時,可以放到處理隊列中的請求數,超過這個數的請求將不予處理。connnectionTimeout 網絡連接超時,單位:毫秒。設置為 0 表示永不超時,這樣設置有隱患的。通常可設置為 30000 毫秒。minSpareThreads Tomcat 初始化時創建的線程數。maxSpareThreads 一旦創建的線程超過這個值,Tomcat 就會關閉不再需要的 socket 線程。最好的方式是多設置幾次并且進行測試,觀察響應時間和內存使用情況。在不同的機器、操作系統或虛擬機組合的情況下可能會不同,而且并不是所有人的 web 站點的流量都是一樣的,因此沒有一刀切的方案來確定線程數的值。
16.如何加大 tomcat 連接數
在 tomcat 配置文件 server.xml 中的配置中,和連接數相關的參數有:minProcessors:最小空閑連接線程數,用于提高系統處理性能,默認值為 10 maxProcessors:最大連接線程數,即:并發處理的最大請求數,默認值為 75 acceptCount:允許的最大連接數,應大于等于 maxProcessors,默認值為 100 enableLookups:是否反查域名,取值為:true 或 false。為了提高處理能力,應設置為 false connectionTimeout:網絡連接超時,單位:毫秒。設置為 0 表示永不超時,這樣設置有隱患的。通常可設置為 30000 毫秒。其中和最大連接數相關的參數為 maxProcessors 和 acceptCount。如果要加大并發連接數,應同時加大這兩個參數。web server 允許的最大連接數還受制于操作系統的內核參數設置,通常 Windows 是 2000 個左右,Linux 是 1000 個左右。tomcat5 中的配置示例:
<Connector port="8080"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true" />
對于其他端口的偵聽配置,以此類推。
3. tomcat 中如何禁止列目錄下的文件
在{tomcat_home}/conf/web.xml 中,把 listings 參數設置成 false 即可,如下:
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
17.怎樣加大 tomcat 的內存。
首先檢查程序有沒有陷入死循環 這個問題主要還是由這個問題 java.lang.OutOfMemoryError: Java heap space 引起的。第一次出現這樣的的問題以后,引發了其他的問題。在網上一查可能是 JAVA 的堆棧設置太小的原因。跟據網上的答案大致有這兩種解決方法:
1、設置環境變量 解決方法:手動設置 Heap size 修改 TOMCAT_HOME/bin/catalina.sh set JAVA_OPTS= -Xms32m -Xmx512m 可以根據自己機器的內存進行更改。
2、java -Xms32m -Xmx800m className 就是在執行 JAVA 類文件時加上這個參數,其中 className 是需要執行的確類名。(包括包名) 這個解決問題了。而且執行的速度比沒有設置的時候快很多。如果在測試的時候可能會用 Eclispe 這時候就需要在 Eclipse ->run -arguments 中的 VM arguments 中輸入-Xms32m -Xmx800m 這個參數就可以了。后來在 Eclilpse 中修改了啟動參數,在 VM arguments 加入了-Xms32m -Xmx800m,問題解決。一、java.lang.OutOfMemoryError: PermGen space PermGen space 的全稱是 Permanent Generation space,是指內存的永久保存區域,這塊內存主要是被 JVM 存放 Class 和 Meta 信息的,Class 在被 Loader 時就會被放到 PermGen space 中,它和存放類實例(Instance)的 Heap 區域不同,GC(Garbage Collection)不會在主程序運行期對PermGen space 進行清理,所以如果你的應用中有很多 CLASS 的話,就很可能出現 PermGen space 錯誤,這種錯誤常見在 web 服務器對 JSP 進行 pre compile 的時候。如果你的 WEB APP 下都用了大量的第三方 jar, 其大小超過了 jvm 默認的大小(4M)那么就會產生此錯誤信息了。解決方法:手動設置 MaxPermSize 大小 修改 TOMCAT_HOME/bin/catalina.sh在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:
JAVA_OPTS="-server -XX:PermSize=64M -XX:MaxPermSize=128m
建議:將相同的第三方 jar 文件移置到 tomcat/shared/lib 目錄下,這樣可以達到減少 jar 文檔重復占用內存的目的。二、java.lang.OutOfMemoryError: Java heap spaceHeap size 設置 JVM 堆的設置是指 java 程序運行過程中 JVM 可以調配使用的內存空間的設置.JVM 在啟動的時候會自動設置 Heap size 的值, 其初始空間(即-Xms)是物理內存的 1/64,最大空間(-Xmx)是物理內存的 1/4。可以利用 JVM 提供的-Xmn -Xms -Xmx 等選項可進行設置。Heap size 的大小是 Young Generation 和 Tenured Generaion 之和。提示:在 JVM 中如果 98%的時間是用于 GC 且可用的 Heap size 不足 2%的時候將拋出此異常信息。提示:Heap Size 最大不要超過可用物理內存的 80%,一般的要將-Xms 和-Xmx 選項設置為相同,而Xmn 為 1/4 的-Xmx 值。解決方法:手動設置 Heap size 修改 TOMCAT_HOME/bin/catalina.sh 在“echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:
JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"
三、實例,以下給出 1G 內存環境下 java jvm 的參數設置參考:JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m - XX:MaxPermSize=128m -Djava.awt.headless=true " 很大的 web 工程,用 tomcat 默認分配的內存空間無法啟動,如果不是在 myeclipse 中啟動 tomcat 可以對 tomcat 這樣設置:TOMCAT_HOME/bin/catalina.bat 中添加這樣一句話:set JAVA_OPTS=-server -Xms2048m -Xmx4096m -XX:PermSize=512M - XX:MaxPermSize=1024M -Duser.timezone=GMT+08 或者 set JAVA_OPTS= -Xmx1024M -Xms512M -XX:MaxPermSize=256m 如果要在 myeclipse 中啟動,上述的修改就不起作用了,可如下設置:Myeclipse->preferences->myeclipse->servers->tomcat->tomcat×.×->JDK 面板中的Optional Java VM arguments 中添加:-Xmx1024M -Xms512M -XX:MaxPermSize=256m 以上是轉貼,但本人遇見的問題是:在 myeclipse 中啟動 Tomcat 時,提示"ava.lang.OutOfMemoryError: Java heap space",解決辦法就是:Myeclipse->preferences->myeclipse->servers->tomcat->tomcat×.×->JDK 面板中的Optional Java VM arguments 中添加:-Xmx1024M -Xms512M -XX:MaxPermSize=256m
18.Tomcat 有幾種部署方式
tomcat 中四種部署項目的方法 第一種方法:在 tomcat 中的 conf 目錄中,在 server.xml 中的,節點中添加:
<Context path="/hello" docBase="D:/eclipse3.2.2/forwebtoolsworkspacehello/WebRoot" debug="0" privileged="true">
</Context>
至于 Context 節點屬性,可詳細見相關文檔。第二種方法:將 web 項目文件件拷貝到 webapps 目錄中。第三種方法:很靈活,在 conf 目錄中,新建 Catalina(注意大小寫)\localhost 目錄,在該目錄中新建一個 xml 文件,名字可以隨意取,只要和當前文件中的文件名不重復就行了,該 xml 文件的內容為:
<Context path="/hello" docBase="D:eclipse3.2.2forwebtoolsworkspacehelloWebRoot" debug="0" privileged="true">
</Context>
第 3 個方法有個優點,可以定義別名。服務器端運行的項目名稱為 path,外部訪問的 URL 則使用 XML 的文件名。這個方法很方便的隱藏了項目的名稱,對一些項目名稱被固定不能更換,但外部訪問時又想換個路徑,非常有效。第 2、3 還有優點,可以定義一些個性配置,如數據源的配置等。第四種辦法,: 可以用 tomcat 在線后臺管理器,一般 tomcat 都打開了,直接上傳 war 就可以
19.Tomcat 的優化經驗。
Tomcat 作為 Web 服務器,它的處理性能直接關系到用戶體驗,下面是幾種常見的優化措施:
? 去掉對 web.xml 的監視,把 jsp 提前編輯成 Servlet。有富余物理內存的情況,加大 tomcat 使用的 jvm 的內存。
? 服務器資源 服務器所能提供 CPU、內存、硬盤的性能對處理能力有決定性影響。o 對于高并發情況下會有大量的運算,那么 CPU 的速度會直接影響到處理速度。
o 內存在大量數據處理的情況下,將會有較大的內存容量需求,可以用 -Xmx -Xms -XX:MaxPermSize 等參數對內存不同功能塊進行劃分。我們之前就遇到過內存分配不足,導致虛擬機一直處于 full GC,從而導致處理能力嚴重下降。
o 硬盤主要問題就是讀寫性能,當大量文件進行讀寫時,磁盤極容易成為性能瓶頸。最好的辦法還是利用下面提到的緩存。
? 利用緩存和壓縮對于靜態頁面最好是能夠緩存起來,這樣就不必每次從磁盤上讀。這里我們采用了 Nginx 作為緩存服務器,將圖片、css、js 文件都進行了緩存,有效的減少了后端 tomcat 的訪問。另外,為了能加快網絡傳輸速度,開啟gzip 壓縮也是必不可少的。但考慮到 tomcat 已經需要處理很多東西了,所以把這個壓縮的工作就交給前端的 Nginx 來完成。除了文本可以用gzip 壓縮,其實很多圖片也可以用圖像處理工具預先進行壓縮,找到一個平衡點可以讓畫質損失很小而文件可以減小很多。曾經我就見過一個圖片從 300多 kb 壓縮到幾十 kb,自己幾乎看不出來區別。
? 采用集群 單個服務器性能總是有限的,最好的辦法自然是實現橫向擴展,那么組建tomcat 集群是有效提升性能的手段。我們還是采用了 Nginx 來作為請求分 流的服務器,后端多個 tomcat 共享 session 來協同工作。可以參考之前寫的《利用 nginx+tomcat+memcached 組建 web 服務器負載均衡》。
? 優化 tomcat 參數 這里以 tomcat7 的參數配置為例,需要修改 conf/server.xml 文件,主要是優化連接配置,關閉客戶端 dns 查詢。
此博客文章中,我想分享一個強大的工具Leadership Health Check。這將幫助您的管理團隊變得更強大,并為積極的服務型領導團隊揭示改進機會,從而更好地賦能您所支持的敏捷團隊。
首先,讓我們從頭開始。
在敏捷教練的工具箱中,我最喜歡的一項練習是在Spotify工作期間學到的 Squad Health Check (中文版:https://www.bobjiang.com/posts/blog/sqad_health_check_model.html) 。這是一種以回顧的形式進行自我評估的研討會。在會上,團隊表達自己在各種主題上的感受,例如協作,交付的價值,影響力,獲得組織的支持等。結果會生成對團隊和領導力的洞見及改進措施。我喜歡這個工具,因為它是加強自組織,組織文化和持續學習的非常棒的工具。
一年多以前, 我和Spotify 的一位同事Georgiana Laura Levinta為我們的tribe創建了領導力健康檢查(tribe是Spotify的半自治部門,由4-8個團隊組成,有一組專門的leader和經理)(更多有關tribe可以參考 https://www.bobjiang.com/posts/blog/scaling-agile-spotify-with-tribes-squads-chapters-guilds.html) 。
我和Geo受到了Squad Health Check的啟發,采用這種做法幫助tribe的管理者自我評估他們向tribe內的squad提供積極支持的領導能力,并討論他們如何作為一個團隊進行改進,以提供更好的支持。
從那時起,我和Casumo客戶一起基于他們的背景、文化和信仰采用了這一方法。我們已經在公司的領導團隊以及tribe級別(半自治部門)實踐了幾次,獲得了巨大的成功和價值。我相信 Team Health Check和 Leadership Health Check都非常強大;因此,我想將它們推薦到更廣泛的敏捷社區,希望更多的組織會發現它們的價值,或者至少受到他們的啟發,然后進行完全不同的嘗試。
如果您不想了解團隊和領導力健康檢查背后的起源和思考,而只是來這里下載研討會材料,請關注本公眾號回復"檢查表"獲取下載地址。
團隊健康度檢查表
(Spotify的 Suard Health Check)
Spotify的Suard Health Check的第一個版本看起來與今天的版本有很大不同。它提出了諸如"您有產品負責人PO嗎?","您有敏捷教練的支持嗎?"和"發布容易嗎?" 之類的問題。隨著這些組織上的痛點(例如,并非所有的團隊都有PO)逐漸消失,該調查逐漸發展為更加關注自組織,團隊合作,可持續流程和任務明確性(見右側示例)。
這種形式在Spotify內部迅速傳播開來,越來越多的團隊和tribe'使用這個。如今,這已成為許多組織中根深蒂固的習慣。團隊每年進行兩次到四次check。當每個tribe根據其背景和需求采用它并與其他tribe共享其版本時,該工具得到不斷發展。
The Team Health Check
我在這篇博客文章中分享的 Team Health Check的靈感來自Spotify的 Squad Health Check。通過與其他客戶的合作,我對其進行了改進,使其更加通用。
現在對各種主題和評論的闡述,試圖嵌入呈現一些著作的思考和研究:如 Christopher Avery的Teamwork is an Individual Skill , J. Richard Hackman的 Leading Teams ,Daniel H. Pink,的 Drive , Stanley McChrystal的 Team of Teams , Patrick Lencioni的 Google's Aristotle Project和The Five Dysfunctions of a Team ,還有甚多其他書籍和敏捷領袖的思想研究。
The Team Health Check 包含大約12個主題。對于每個主題,都有綠色和紅色的說明。綠色表示可觀察到的健康或積極的案例。紅色表示不健康或不良案例。這里有兩個例子:
1)團隊自組織
2)反饋
如果你要在你的組織中與團隊一起實踐" Team Health Check",我強烈建議你基于組織的文化和背景進行修改采用,并決定模板中哪些可以保留。我相信這是一次偉大的領導力實踐。定義主題和聲明所面臨的挑戰迫使你們作為領導者聚焦在你們渴望建立的文化,想要看到的行為以及預期的與領導力和組織期望達成共識的成員。
由于團隊可能每年進行幾次健康檢查,因此在某種程度上這可以作為您所追求的目標教育,并且在某種意義上成為團隊的權利清單。如果他們每次都收獲了問題,每次都感到有能力操縱和打造計劃和命運,他們便找到了應該的方式。如果被問及他們是否有時間提前思考和嘗試,則意味著應該允許他們有足夠的時間來這樣做。等等。
以我的經驗,每年與團隊進行兩次到四次 Team Health Check,你將收獲:
如果您作為團隊成員害怕或注意到,自我評估的結果已被管理層用來比較不同團隊有多"好"--那么不要在團隊之外分享您的結果!與其他任何回顧會形式一樣,將其用作產生見解(洞見),討論和行動的工具。分享行動,結果,而不是討論本身。
如果您是經理,想使用該工具評估團隊的"敏捷成熟度",效能或在團隊之間進行比較-請勿這么做!答案將非常主觀,去反映每個團隊的具體情況和挑戰。如果想評估的話,實踐的結果可以表明您在為團隊提供支持方面做得怎樣。這不是衡量團隊表現的如何,而是衡量您作為領導者的表現如何。
領導力健康檢查表
領導力健康檢查的目的與團隊健康檢查的目的相同,可以自我評估我們在各個領域的團隊感覺如何,并揭示我們如何改善協作和交付的價值。在這種情況下,團隊是一組敏捷團隊的經理和領導者。我們提供的價值是我們為團隊提供的支持,以及我們為幫助團隊為用戶和利益相關者提供價值所做的工作。
(領導健康檢查練習投票的結果)
正如我在本文開頭所提到的,領導力健康檢查的第一版是與Spotify的同事Georgiana Laura Levinta共同開發的。Georgiana還寫了一篇有關該工具創建的Spotify內部博客文章。希望有一天它將在Spotify的官方博客上發布。
我在這里共享的版本是我與當前客戶端Casumo一起運行的版本。它引發了有關敏捷環境中領導力的大量討論。它凝聚了領導團隊,激發了行動和變化,以進一步改善他們支持團隊的方式。
實踐證明,它對于公司的領導團隊(由CEO,CTO,CFO等組成)以及部門級領導均有效。研討會產生了見識,并指導領導團隊確定下一步的工作重點。
專為管理/領導團隊設計
該領導健康檢查承認領導者/管理者團隊不同于緊密結合起來,推出產品或者提供服務的團隊。他們可能不會為實現短期目標而協作,將他們團結在一起的是他們所提供的服務:提供支持,指導,指引和團隊可以在其中蓬勃發展和脫穎而出的環境。為了有效地做到這一點,他們需要將自己視為一個團隊,并與價值觀和長期戰略保持一致,就如何做出決定以及什么構成良好的領導達成共識。
其中一些主題與團隊健康檢查的主題相同,例如信任與安全,可靠性,持續改進和反饋。其他是領導力健康檢查特有的,例如文化與價值觀,愿景與方向,服務型領導力和透明度。
采用領導力健康檢查
我的建議與團隊健康檢查的建議相同,如果您要在部門或公司中運用"領導者健康檢查",我強烈建議基于文化和信任的基礎將其用在檢查領導力水平上。
在一組主題和聲明上達成一致是一項很棒的練習,并且很可能會引發大量艱難而健康的討論,迫使您調整并決定對您而言重要的事情。例如,您認為自己是一個團隊還是一個松散的一組人?您相信包容性的決策還是明確的決策?您對這些問題的立場應反映在健康檢查中。
實踐社區健康檢查
這是一個驚喜獎勵。當我與客戶一起工作時,我接觸了高端人才。人才在他們的組織是一組具備相同信仰和能力的人,有時也被稱為實踐社區。在Spotify這是分隊(Chapter)。我們開發了健康檢查,其主題針對實踐社區成員彼此之間的需求進行了調整。他們通常不像團隊那樣朝著一個共同的目標努力,但是他們確實共享其他需求,例如知識共享,幫助,與某些長期戰略保持一致等等。
主題和聲明未經過修飾,也沒有經過許多次改進(如果有的話)。但是,如果需要,可以關注本公眾號回復"檢查表"下載。也許您可以將其用作靈感來源。
引導
我以幾乎完全相同的方式引導團隊和領導力檢查。我通常計劃90分鐘的會議,并為研討會作如下安排:
1)歡迎-- 5分鐘
研討會的目的及其結構的說明。我強調自我評估的方式,是一種回顧的形式,而不是從任何客觀角度衡量我們作為一個團隊的好壞的方法。
2)自我評估-15分鐘
對于每個主題,我要求某人大聲朗讀主題,綠色和紅色聲明。然后每個人投票。如果您認為綠色最能說明事情的發展,請投綠色票。如果您認為紅色最能說明事情的發展,請選擇紅色。如果您同時看到綠色和紅色示例,或者認為事物既不是綠色也不是紅色,則將其投票為黃色。收集投票,然后進入下一個主題,請下一個人大聲朗讀,依此類推。
注意:在一起做這件事時,我要求人們用綠色,黃色或紅色的便利貼來投票。然后,我收集便簽紙并將其放在白板上。在與遠程成員一起為研討會提供便利時,我準備了一個Google Spreadsheet,然后請與會人員對文檔進行投票。在下面的屏幕快照中,您可以同時看到團隊成員的投票以及在第4步之后的討論中捕獲的評論。
3)反思-- 5分鐘
我要求大家簡短地評論并反思總體結果。- 5分鐘
4)探尋改進措施-- 45分鐘
找到并討論最有趣的結果。可能是投票最多的紅色話題,或者是投票范圍最廣的綠色,黃色,紅色話題,我們對該話題的看法截然不同。我試圖促進討論,以便提出建議和決定并采取行動。
5)摘要-- 5分鐘
重復商定的行動要點及責任人。
確保分配了某人來記錄并共享結果。
6)結束-- 5分鐘
結束環節。我通常請每個人簡短地評論"您認為對于我們團隊來說,最重要的討論或行動是什么?"
常見問題
*問:為了使答案更全面,此練習是否需要團隊成員之間的信任? *
是。但是我也相信做這樣的練習可以建立信任。隨著團隊成員認識到這不是評估他們的工具,而是幫助他們自己變得更強大的工具,答案將更加誠實。結果,隨后的討論產生了更深刻的見解以及更具影響力的行動和變化。
問:一個部門匯總幾個團隊的團隊健康檢查結果沒有價值嗎?
當然。如果您作為領導者想查看模式和趨勢,以了解應該將精力集中在哪里,那么這將非常有價值。上圖顯示了Spotify中的真實示例。例如,這有助于領導者和團隊確定工作的優先級,以使其易于發布。第4小隊是在兩周前成立的,所以他們的自我意識可能真的很低,因為一切看上去都很綠色。第2小隊似乎在掙扎很多。因此,這兩個小隊得到了額外的支持和照顧。
問:但是我真的很想用它來比較不同團隊的表現。我為什么不能?
不,你不能!有幾個原因。這是一種自我評估,因此結果會從團隊的個人角度揭示團隊的敬業精神。一個小隊可能會覺得他們的移動速度非常快,而另一個小隊卻非常緩慢,即使它們都以每周一次的節奏進行釋放。每個團隊的背景和挑戰差異很大。一個團隊可能將每日更新發布到網站,而另一個團隊則在許多外部依賴項下苦苦掙扎。一個團隊可能很大,另一個可能很小。等等。
如果您將其用于比較,甚至可能用于決定要獎勵的團隊,那么團隊會清楚這一點,并開始以不誠實的答案來計算結果,以"看起來不錯"。
問:結果應該共享嗎?
我堅信透明度,所以如果您問我-是的。不過,我的建議是僅分享結果并商定行動,而不是由誰對每個主題投票。透明并共享結果可以建立信任,實現跨團隊學習并培養責任感。
問:我覺得有些問題太含糊,太開放,將其劃分為更多的問題并縮小范圍會怎樣?
當然可以。如果這些問題不能引發良好的討論不能提供有用的見解,請嘗試其他問題。但是我的建議是提出的問題不要超過十二至十四個。如果添加一個,也許應該刪除另一個。問:為了節省時間,我是否應該在研討會之前發送問題并請人們投票?
也許這是一個很大的群體,例如大于10人。否則,我覺得在研討會中一起做起來會更加有樂趣和參與感。
關注本公眾號,查看圖片。 回復"檢查表"獲取下載地址。不要猶豫,復制并采用它們基于您的上下文,然后與您的團隊一起使用。
譯者:Fish
審校:姜信寶
原文:https://blog.crisp.se/2019/03/11/jimmyjanlen/health-checks-for-teams-and-leadership
本文首發于 Bob Jiang的博客 ,轉載請聯系 Bob Jiang
*請認真填寫需求信息,我們會在24小時內與您取得聯系。