題記:個人從事性能專項8年+,對項目的性能過程還算有一定的見解能力。最近一年有機會領導並主導性能測試的發展和建設工作,讓我很多想法可以逐步落地(之前受上面領導和KPI的限制,很多事情不能真正的按照自己的想法去做。)

先看下我的大盤規劃圖

(雙擊查看大圖)

針對以上規範,我先說明兩點:

1、後端的細節部分,要根據實際的項目需求調整。

如考覈和需求模板內容(筆者工作環境特殊,有一部分是外部負責壓測性能的,故需要針對他們的方案和報告進行評審卡關)

2、圖上各種平臺化的編號,就是我在實際項目中實現的順序(優先順序)

細心的讀者會發現我們把性能壓測平臺放在最後,為此我專門表達下我的觀點:

A、優先做可以花20%的時間完成能提升80%效率的事情!

性能平臺不是小事,做好一個可用、易用、實用性能平臺更不是一件容易的事情!筆者從華為、攜程、網易,都接觸過過也自行創建過性能壓測平臺,但真正做到好用的平臺,我可以負責的說目前沒有!缺點都十分明顯,限制也頗多。有的時候使用這些平臺,甚至還不如自己直接用JMeter方便(JMeter做了十幾年,你平臺才做了多久?)!

而性能平臺先做到可用、易用這水平(還得符合自己的壓測場景,比如在網易經常需要兩三百臺的壓測機發壓,那麼平臺對壓測機和報表的採集實時性要求就很高了),不是說隨隨便便的團隊都能在短時間內完成的!真的說做出一套符合公司場景使用的性能壓測平臺,2人左右的測試開發團隊,能在2年做到70分已經很不錯了!

顯然,這上面的花銷可是遠超20%的時間了,提升的效率嘛,繼續看下面。

B、「我們做個性能平臺,誰都可以壓測」--偽命題!!!

在我之前的性能培訓中,我多次強調過,性能測試是一項看重過程的測試

如果真的是那麼簡單,Apache出個壓測平臺應該不是什麼難事,所有的性能壓測人員就可以下崗了……顯然現實不是如此,是因為大部分性能測試過程,都會發現很多性能問題,那麼這個期間,

第一你要有察覺到性能問題發生的能力;

第二就是要能定位到性能問題的原因能力。

顯然這兩點,纔是性能測試過程中,最難,最有技術含量的地方。而並不是在腳本的創建和點下按鈕的執行上!平臺在這兩點並不能提高多少效率,甚至平臺化就意味著限制化(JMeter的靈活度相信熟悉的人都知道,實際過程中二次開發的腳本、各種依賴或者插件的腳本,平臺的兼容性,我只能呵呵了……

C、性能壓測平臺的意義

那麼問題來了,性能壓測平臺的意義在哪裡?

從我個人的理解角度,平臺出現的目的就是要麼提升效率,要麼規範過程

I、腳本的統一管理;

II、測試過程的數據和歷史記錄保存;

III、規範的執行過程(避免有人少測或者沒測);

IV、針對高並發的業務需要,更好統一管理壓測機和壓測伺服器。

就我目前所負責的團隊而言,我們的歸檔要求很清晰,所以I、II、III,在沒有平臺的前提下,我們也做到了很有秩序和條例的管理。(你要什麼項目的腳本、數據、方案、報告,我可以在一兩分鐘內給你找到。)

而針對IV點,如果工作環境,真的經常需要少則三五臺,多則百十來臺的壓測機,那麼平臺化就變成了必需,畢竟你手動去用JMeter遠程一兩臺機器還可以,但三五臺以上,就並非那麼方便了,此外,壓測結果的聚合報表的實時展示能力,也存在考量!

但,單臺4C8G的window壓測機,JMeter支持1500-2000並發的壓力,所以我相信除了大部分的公司業務都是完全夠用的(畢竟我們大部分也都是在測試環境下壓測的。)所以,IV點對我而言,是完全不存在的。

恕我直言:很多性能壓測平臺出來後,實用和易用性並不高,這些平臺誕生的目的僅僅是為了KPI,為了給領導看罷了……

-------------------------------------------正文開始-------------------------------------------

清楚了上面的目的,那麼我們就來看看我這邊,怎麼將一個性能為0的傳統業的公司,快速走向規範化、高效化(不到1年的時間,我有信心說,我們現在的性能流程和專業度,不會比外面的任何互聯網公司差什麼,除了TPS不是一個量級外),讓遊擊隊逐漸擁有正規軍的戰鬥力!

性能組成員人數:>4人

性能水平:2-3年性能專項經驗(但性能水平一般,認知片面)

外圍環境:開發人員平均水平低下(很多都是畢業1-2年的新人,代碼質量可想而知),(性能方面薄弱)

負責業務:全集團業務,種類繁多,架構參差不齊且雜亂

面對的問題

1、公司運維能力薄弱,環境信息雜亂,監控不夠專業;

2、組內成員技術水平低下,性能短板太多!

3、項目流程隨意,性能隨意,毫無規範可言。

針對第3點,我花了半年的時間推行性能測試流程規範,定製了性能測試方案和性能報告的要求(同時約束完全應付且編造性能數據的供應商),這塊就不再此處詳述了,這完全和公司的環境和體制有關。

總之,第一步就是定規矩!

關於運維能力薄弱這點,我這人不習慣依靠別人,所以性能環境被我完全接了過來,運維給我平臺的虛機分配的許可權,剩下的完全由我自理!

第二步,抓環境!(性能測試必須對性能環境有100%幹預能力!)

關於第2點,組內成員性能能力的問題,只能靠我多次的培訓去提升他們的性能水平和意識了。我也從性能初級逐步走過來的,所以針對初級性能或者是僅僅停留在根據簡單使用的基礎上的組員,進行了快速高效的指導(在項目中成長!)

所以第三歩,就是循序漸進的促組員!(包括問題的分析思路、定位案例等等,實時給他們講解……費了我一個月的時間)

---------------------以下就是平臺建設的過程和思路【乾貨】--------------------------------

初級和資深的性能測試差別在什麼地方?

就是針對各項資源的敏感度認知!比如基本的資源監控、Jvm監控、DB的監控,如果是初級性能,這對對他們而言十分困難,所以最快的方法,就是先認圖,在學原理

那麼監控的重要性就出來了!有監控,可以先讓他們先意識到問題!

1、監控分為硬體監控和應用監控

監控工具主要是Grafana+telegraf+influxDB(儘可能用的一個平臺滿足大部分的監控需求)

值得一提的是:所有的監控報表,我親自做過定製,去除冗餘的,留下重要要的。(製作模板的人,對性能監控項也不太清楚,太多沒有用的監控只會給小白造成幹擾;有用的報表卻沒添加上去。)

A、硬體監控就是最基礎的cpu、內存、IO之類,如下圖

Linux資源監控

Window資源監控

B、應用監控,分為兩種,一種是全鏈路級監控,一種是應用自身資源監控

Java服務的全鏈路級監控:pinpoint

可以讓測試人員查看到具體的介面情況,是調優必備的利器

可以看到具體的耗時所在,及介面請求(包括慢的sql也可以瞬間抓出)

應用的自身的資源監控,就比較多了,我隨便貼幾張報表吧

下圖的都是telegraf支持的!

如:mongoDB監控

Redis監控

mysql監控

甚至,包括.net IIS 監控

有了監控利器,才能在第一時間去發現問題,進一步的定位問題!

舉個例子,你讓新人去了解Linux top 的各個參數是什麼,load是什麼,肯定沒有告訴他圖表在呈現什麼時候的曲線時,就意味的出問題了,簡單很多!

附上telegraf的配置:

mysql

# # Read metrics from one or many mysql servers

[[inputs.mysql]]

# ## specify servers via a url matching:

# ## [username[:password]@][protocol[(address)]]/[?tls=[true|false|skip-verify|custom]]

# ## see github.com/go-sql-drive

# ## e.g.

# ## servers = ["user:passwd@tcp(127.0.0.1:3306)/?tls=false"]

# ## servers = ["user@tcp(127.0.0.1:3306)/?tls=false"]

# #

# ## If no servers are specified, then localhost is used as the host.

# servers = ["tcp(127.0.0.1:3306)/"]

servers = ["root:ROOTqazwsx-123@tcp(localhost:3306)/?tls=false"]

MongoDB

# Read metrics from one or many MongoDB servers

[[inputs.mongodb]]

## An array of URLs of the form:

## "mongodb://" [user ":" pass "@"] host [ ":" port]

## For example:

## mongodb://user:[email protected]:27017,

## mongodb://10.10.3.33:18832,

servers = ["mongodb://127.0.0.1:27017"]

Redis

[[inputs.redis]]

# ## specify servers via a url matching:

# ## [protocol://][:password]@address[:port]

# ## e.g.

# ## tcp://localhost:6379

# ## tcp://:[email protected]

# ## unix:///var/run/redis.sock

# ##

# ## If no servers are specified, then localhost is used as the host.

# ## If no port is specified, 6379 is used

# servers = ["tcp://localhost:6379"]

servers = ["tcp://:qazwsxedc-123456@localhost:8888"]

SQLServer

[[inputs.sqlserver]]

## Specify instances to monitor with a list of connection strings.

## All connection parameters are optional.

## By default, the host is localhost, listening on default port, TCP 1433.

## for Windows, the user is the currently running AD user (SSO).

## See github.com/denisenkom/g for detailed connection

## parameters.

# servers = [

# "Server=192.168.1.10;Port=1433;User Id=<user>;Password=<pw>;app name=telegraf;log=1;",

# ]

servers = [

"Server=10.190.37.88;Port=1433;User Id=sa;Password=ouLjbnM63CZYS8D8;app name=telegraf;log=1;",

]

ASPnet IIS

[[inputs.win_perf_counters]] [[inputs.win_perf_counters.object]] # HTTP Service request queues in the Kernel before being handed over to User Mode. ObjectName = "HTTP Service Request Queues" Instances = ["*"] Counters = ["CurrentQueueSize","RejectedRequests"] Measurement = "win_http_queues" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). [[inputs.win_perf_counters.object]] # IIS, ASP.NET Applications ObjectName = "ASP.NET Applications" Counters = ["Cache Total Entries","Cache Total Hit Ratio","Cache Total Turnover Rate","Output Cache Entries","Output Cache Hits","Output Cache Hit Ratio","Output Cache Turnover Rate","Compilations Total","Errors Total/Sec","Pipeline Instance Count","Requests Executing","Requests in Application Queue","Requests/Sec"] Instances = ["*"] Measurement = "win_aspnet_app" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). [[inputs.win_perf_counters.object]] # IIS, ASP.NET ObjectName = "ASP.NET" Counters = ["Application Restarts","Request Wait Time","Requests Current","Requests Queued","Requests Rejected"] Instances = ["*"] Measurement = "win_aspnet" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). [[inputs.win_perf_counters.object]] # IIS, Web Service ObjectName = "Web Service" Counters = ["Get Requests/sec","Post Requests/sec","Connection Attempts/sec","Current Connections","ISAPI Extension Requests/sec"] Instances = ["*"] Measurement = "win_websvc" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). [[inputs.win_perf_counters.object]] # Web Service Cache / IIS ObjectName = "Web Service Cache" Counters = ["URI Cache Hits %","Kernel: URI Cache Hits %","File Cache Hits %"] Instances = ["*"] Measurement = "win_websvc_cache" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*).

.NET Monitoring

[[inputs.win_perf_counters]] [[inputs.win_perf_counters.object]] # .NET CLR Exceptions, in this case for IIS only ObjectName = ".NET CLR Exceptions" Counters = ["# of Exceps Thrown / sec"] Instances = ["*"] Measurement = "win_dotnet_exceptions" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*). [[inputs.win_perf_counters.object]] # .NET CLR Jit, in this case for IIS only ObjectName = ".NET CLR Jit" Counters = ["% Time in Jit","IL Bytes Jitted / sec"] Instances = ["*"] Measurement = "win_dotnet_jit" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*).

[[inputs.win_perf_counters.object]] # .NET CLR Loading, in this case for IIS only ObjectName = ".NET CLR Loading" Counters = ["% Time Loading"] Instances = ["*"] Measurement = "win_dotnet_loading" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*).

[[inputs.win_perf_counters.object]] # .NET CLR LocksAndThreads, in this case for IIS only ObjectName = ".NET CLR LocksAndThreads" Counters = ["# of current logical Threads","# of current physical Threads","# of current recognized threads","# of total recognized threads","Queue Length / sec","Total # of Contentions","Current Queue Length"] Instances = ["*"] Measurement = "win_dotnet_locks" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*).

[[inputs.win_perf_counters.object]] # .NET CLR Memory, in this case for IIS only ObjectName = ".NET CLR Memory" Counters = ["% Time in GC","# Bytes in all Heaps","# Gen 0 Collections","# Gen 1 Collections","# Gen 2 Collections","# Induced GC","Allocated Bytes/sec","Finalization Survivors","Gen 0 heap size","Gen 1 heap size","Gen 2 heap size","Large Object Heap size","# of Pinned Objects"] Instances = ["*"] Measurement = "win_dotnet_mem" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*).

[[inputs.win_perf_counters.object]] # .NET CLR Security, in this case for IIS only ObjectName = ".NET CLR Security" Counters = ["% Time in RT checks","Stack Walk Depth","Total Runtime Checks"] Instances = ["*"] Measurement = "win_dotnet_security" #IncludeTotal=false #Set to true to include _Total instance when querying for all (*).

---------

2、平臺的建設:

我走過很多家公司,鑒於我之前提到的他們更看重壓測平臺的建設,所以上面的這些針對內部管理的和過程的平臺,很多公司都不會看作重點!

但相信我,這些東西就是你的組員每天要做的繁瑣的東西,平臺化可以極大的提升他們做這些低級工作的效率!

這裡的平臺涉及隱私和機密,我就不在此介紹了!(和壓測平臺不一樣,什麼的平臺研發而言,比較簡單,用開源的框架搞搞,可能一兩周就是一個模塊。)

需要提醒各位的是,你們到項目過程中需要什麼元素欄位,一定要提前設計好,想清楚!

而平臺化後的過程數據,更便於後面的管理!

3、過程度量報表的出現!

有了上面平臺的數據,作為組長,上面的領導問及你們需求情況或者是季度考覈時,你再也不用去做重複、繁瑣、低效的手動統計了!

原理如下:我自己寫的JOB做數據聚合(實時性要求不高,一個小時執行一次),當然還是依賴強大的grafana!

性能需求和性能問題大盤--便於開發或上級領導,查看實時進展和結果

人員維度統計--便於考覈和彙報--各種維度,十分靈活

--------------------------------------------------------------

Grafana個人定製後的性能專項報表,不會免費公開,見諒!

相關技術詳貼,後面有時間了我再更新吧!

(未完,待後續更新………………)


推薦閱讀:
相關文章