相伴Java許多年,我也曾在SSM之時迷茫很久


在我當初接觸編程的時候,因為喜歡玩手機游戲,在諾基亞制衡市場的時代,大部分精良的手機游戲都由Java語言進行編寫的,那些游戲傻傻的都帶著那杯咖啡的圖標,我也順理成章以Java作為編程的母語進行學習。
那時候?qū)W習Java從JavaSE開始學起,if判斷/for循環(huán)/面向?qū)ο?多態(tài)/多線程/TCP/UDP,雖然多態(tài)難為了我很長時間,但不妨礙我沉迷進了編程這個奇妙的世界。學習Java GUI界面編程的時候終于脫離了黑窗口和命令行,終于可以把自己制作的東西交給父母看一看,讓他們知道自己兒子在學什么東西,似乎還學的很不錯一樣!到學習JavaEE的Servlet/JDBC/HTML/CSS/JS/JSP/MySQL至此可以做出來一些小型的網(wǎng)頁和博客。那時候特別高興,感覺終于能夠通過自己的技術(shù)制作出來一些符合自己想法的東西了,感覺自己就是造物主,自己可以創(chuàng)造一整個世界!
初期工作開始接觸使用Hibernate代替JDBC,以Struts2代替Servlet的形式進行編程,逐漸接受各種框架的洗禮,密密麻麻的框架需要學習,排不完的加班和數(shù)不清的復雜查詢,到現(xiàn)在我仍然想吐槽曾經(jīng)十幾個表聯(lián)查還覺得理所應當?shù)母鱾€架構(gòu)師!處理著各種冗余數(shù)據(jù)與歷史代碼,每天都掉許多頭發(fā),但是當時勸自己,既然剛?cè)胄?,賺的就是這個錢,我能堅持下去!
后續(xù)工作時使用SpringMVC代替Struts2,使用MyBatis代替Hibernate,使用Jedis整合Redis增加緩存,使用POI生成Excel表格,使用dom4j解析XML文件,使用SOAP協(xié)議的WebService接口代替HTTP協(xié)議進行服務器之間的數(shù)據(jù)傳輸,最后使用Spring管理所有的引入框架。讓整體項目越來越完善,似乎越來越接近所有人所說的那種企業(yè)級開發(fā)的程度了。但這段時間的旅程給人的感受并不美好,此時雖然每天晚上我都保持最少2個小時的長久學習狀態(tài),但始終沒有我在JavaSE與JavaEE時感受到的那種“接受新鮮事物的感覺”。誠然,我的技術(shù)不斷在完善,我所了解的框架越來越多,我也勝任了市場上要求三年開發(fā)經(jīng)驗的面試門檻和工作基礎。但于我個人而言,通過JDBC/Hibernate/MyBatis去讀取MySQL中的數(shù)據(jù)有什么區(qū)別?Servlet/Struts2/SpringMVC換來換去有什么意義么?只不過換了個框架換了個寫法而已,得到的結(jié)果并無不同啊。那我此時此刻浪費的時間來干嘛?我很焦慮,在擅長SSM之后,我技術(shù)的增長停滯了很長一段時間。那時候可能每天想的最多的就是通過考研來提高自己工資。畢竟單純從技術(shù)上我似乎已經(jīng)沒有什么辦法提高工資了。要么考研,要么等待自己的工作年齡生長到一定程度才行。
但后來發(fā)現(xiàn)35歲開始,似乎各個公司又不喜歡用你了,這就很尷尬了。我當時已經(jīng)工作三年左右,二十五六歲了,考研連考試帶學習兩三年的時間,我還能再干幾年?可是不考研的話,等待工齡漲工資我能漲幾年?那時候我迷茫的不得了。
后來發(fā)現(xiàn)大牛不外乎本公司內(nèi)自研框架和引擎的高齡程序員們,可是當我與他們一起開發(fā)銀行管理系統(tǒng)的時候發(fā)現(xiàn)他們?nèi)匀辉谟肑DK1.4版本,我對整個職業(yè)生涯都很絕望,是啊,我們的項目要求的是穩(wěn)定,哪來那么多潮流技術(shù)新技術(shù)去給你替換嘗試?而且所謂各種大牛研制的引擎或框架來說,始終離不開讀取數(shù)據(jù)庫/生成web頁面一系列功能,我都不需要回頭看就知道其中肯定包括了單點登錄/AES對稱加密/RSA非對稱加密/HTTPS協(xié)議/Freemaker生成HTML頁面/賬號對應權(quán)限/審批功能/跑批功能,來來去去做的這些就是我人生的意義么?他們只是工作早了一些,這樣的框架換我我也能做啊!我們每天干的都是這些事!等我年紀大了只能和他們一樣么?我還年輕我不服啊,我不能只漲年齡不漲技術(shù),但是那時候的Java除了不常用的框架之外的的確確沒有什么所謂的“技術(shù)”再可以讓我學習的了。
但是自那之后雖然Java技術(shù)停滯增長了,我便把重心放到了運維工程師的相關技術(shù)上,想往我夢想中的“架構(gòu)”層次再進一步。那時我學會了Nginx + Tomcat + SSM負載均衡的形式,又學會了Keepalived + Nginx + Tomcat + SSM多層負載均衡的形式,學習了WebSocket那種客戶端主動推送的協(xié)議,學習了Zabbix監(jiān)控自己的項目,學習了MongoDB這種除了Reids之外的緩存技術(shù),認知了ElasticSearch搜索引擎,認知Git與SVN之間的管理區(qū)別。開始不斷閱讀各種框架的底層源碼,例如在Spring代碼中設置斷點不斷的Debug,開始在MyBatis框架中增加代碼,定制更適合我自己的MyBatis攔截器(我在原有MyBatis之上增加了攔截器與自定義日志之類的功能)。在這段時間里,對于框架的理解越來越深,對于運維工程師所需的技術(shù)了解的越來越多??墒窃诒韭毠ぷ髦校胰匀桓杏X,以我當時三四年的工作經(jīng)驗來講,與那種剛畢業(yè)且學習好的學生來說,區(qū)別并不大,尤其類似POI/Jedis/MongoDB這一類工具與框架的學習成本很低,快的兩天一個,慢的兩周也能搞定,學習速度很快,在未來我的優(yōu)勢能在哪里?難道我的優(yōu)勢只能是我能兼職干運維工程師和研發(fā)工程師兩種工作么去和其他程序員硬卷么?這種優(yōu)勢與我能瘋狂加班有什么區(qū)別?這并不是我想要的!我并不想只是技術(shù)的“量”在增長,技術(shù)的“質(zhì)”仍然處于那個SSM的階段,我與畢業(yè)生寫的代碼仍然沒有任何不同之處!
在我工作五六年的時候,市面上Java研發(fā)常用的服務器軟件與Java框架已經(jīng)大部分了解,我開始接了不少私活,其中包括游戲服務器/IM軟件后臺/OA軟件后臺/電商后臺等等一系列項目,白天上一份班晚上熬夜接著干,得到了不少人的不少賞識,任何一套系統(tǒng)需求分分鐘能在腦內(nèi)形成拓撲圖的時候,我極其自大,覺得自己已經(jīng)無人能及了,對于新出的Spring Boot與Spring Cloud技術(shù)不屑一顧,幾周內(nèi)幾乎全部學下,其中包括Consul注冊中心/Kafka/FastDFS/Spring cloud Ribbon/Spring Data JDBC/緩存與持久化保持一致性/分布式通訊Feign/分布式斷路器Hystrix/分布式的任務調(diào)度Quartz等等吧。
很多人認為分布式不是新出的概念么?其實早好幾年前我在做SOAP的時候就已經(jīng)使用了這種分布式服務的形式,在我看來分布式微服務和我當初做的分布式服務沒任何區(qū)別。思想上都是一樣的,那時也通過注冊中心管理各個SOAP的WebService服務提供者,這種技術(shù)只是實現(xiàn)方式在變,可思想以前就有。只是現(xiàn)在實現(xiàn)的更加具體更加成熟了。剛好那時候有一個大項目拆分重做,整套項目大概區(qū)分六十多個微服務,那一年多我通過Spring Boot + Spring Cloud的架構(gòu)獨立連續(xù)制作了四十幾個微服務,聽起來數(shù)量很多,其實過程十分輕松,并且我還有閑暇時間去看書。那時候我在想,我的技術(shù)也就這樣了,最多重新學習一下HTML5/CSS3/VUE/Bootstrap/AngularJS回頭當個全棧就好了。
再后來有一段時間身體不好在家休養(yǎng),順手整理了下自己學習Spring Boot + Spring Cloud的過程,編纂成冊出版了《微服務分布式架構(gòu)基礎與實戰(zhàn)——基于Spring Boot + Spring Cloud》一書,寫書之余學習了Python擴展了下編程語言。

還有在藍橋杯的云課堂出了一個《Java多線程實戰(zhàn)基礎》的課程。又重新買了《算法之美》/《算法基礎》一系列算法書,從第一頁開始仔仔細細的學習,每一道題都回Eclipse中重新編寫代碼,當然后期陸陸續(xù)續(xù)的也都忘了。恕我直言,迄今為止我也背誦不出來快排的代碼。
那時開始不斷審視著我工作之中我遇到厲害的人物,思考他們技術(shù)上的優(yōu)點,當時想著我既然不知道如何去學習了,那就用他們的優(yōu)點填補自身,起碼勉強能夠進步。想想那其中包括通過自己手寫簡易多線程計算機系統(tǒng)的大佬!能夠背誦一點點Linux代碼的項目經(jīng)理!自己手寫協(xié)議的同事!從零到一實現(xiàn)MySQL!從零到一實現(xiàn)Tomcat的各種人才。雖然一個個都很厲害,但是好多學習的內(nèi)容純粹都是靠時間堆砌起來的!都沒法讓我再驚訝起來!因為雖然我沒寫過,但是我心里都有個大概,有些我學不會也不想學,因為工作上實在用不到!有些我也可以做到!至此我?guī)缀跻呀?jīng)放棄了Java方面的學習,再怎么學也不過如此了。
此后來到現(xiàn)任公司被現(xiàn)任領導面試的時候,領導問我:“你當初寫的Spring Boot項目最高承載并發(fā)(TPS)能達到多少?”
“當時的項目大概六千多吧,主要看數(shù)據(jù)查詢量大小與復不復雜。這也不光是程序的事,重在服務器,硬件性能配置的上跟不上,代碼再好也白費。而且當時業(yè)務邏輯也比較復雜,需要穿插數(shù)個系統(tǒng),所以這方面不太好直說。”
“讓你開發(fā)Redis,16核CPU,32G內(nèi)存的情況下,你單節(jié)點并發(fā)(TPS)能上6萬么?”
“這實在太恐怖了,這種機器Redis單節(jié)點并發(fā)應該也就10萬吧?我雖然可以完全實現(xiàn)Redis所有功能包括事務/鏈表/信息推送,但是確實性能不能和真正Redis進行比較。而且人家還是一個團隊在做的東西,一個人肯定完不成!”在我回答之時,別說讓我拿自己的產(chǎn)品和Redis進行比較,就算放在一起相提并論我都覺得臉上燒的慌。我一直工作也都是實現(xiàn)業(yè)務邏輯而已……
“那你和應屆生的區(qū)別是什么?這點業(yè)務邏輯哪個應屆生做不出來?Redis一共才幾萬行代碼,允許你兩年制作一個閹割版的Reids,不需要那么多的鏈表/隊列/事務,只是達到最基礎的set/get/消息通訊三個功能的情況下,代碼肯定更少,那你能不能做到Redis的并發(fā)?”
應該……做不到吧?不可能的,不現(xiàn)實的,怎么可能?。。?/p>
“你知道么?同樣都是Java語言,在不同人手里,完全不一樣!青龍偃月刀雖好,但是有些人只能拿它切了自己的腦袋!不是Java厲害,框架厲害,公司厲害,你就厲害!不會性能上的測試與優(yōu)化!你能仿照的,永遠都是只是實現(xiàn)了業(yè)務邏輯的殘次品!”
為了尋找這個面試官所言的真實性,我來到了當前這家公司,跟著面試我的這名領導優(yōu)化一套類似Redis的中間件。一開始多少以看笑話且隨時走人的心態(tài)來的,畢竟在我眼里,這幾乎是一件不可能完成的任務。
感謝現(xiàn)任領導,幾乎手把手教我各種性能測試的方式,雖然我曾經(jīng)了解一些,但是在這個項目中始終不夠看,改變原有編程觀念,不斷的優(yōu)化著接口里每一個小接口,關掉所有的日志輸出,盡可能減少循環(huán)減少遞歸次數(shù),幾乎全部的線程都為多線程異步使用,一個接口用了十數(shù)個隊列進行調(diào)用,優(yōu)化其中任何一絲GC可能不會清除掉的垃圾!高并發(fā)項目不存在任何Debug行為,線程全在大腦里轉(zhuǎn)。聽著似乎很簡單吧?但其實一個接口每天需要測幾十次,連續(xù)測試半年時間去優(yōu)化里面任何一點細節(jié)。
越制作現(xiàn)在手上的這款中間件越覺得自己當初如何可笑,面對曾經(jīng)不知天高地厚的自己恨不得回去好好抽自己幾個嘴巴子。當然,抽的時候一定要把現(xiàn)在學習路線告訴曾經(jīng)的自己,省的再走太多彎路了。
我是如何做到這樣的并發(fā)的?很簡單,秘密就在我編寫的《高性能Java架構(gòu):核心原理與案例實戰(zhàn)》這本書里。謝謝我的編輯安娜,是她給了我寫這本書的機會,也是她不斷的幫我修改其中的文字,讓這本書更好的呈現(xiàn)給大家。

如今這款中間件誠如當時所說在16核CPU,32G內(nèi)存的情況下每秒帶寬推送至少5個G,可承接6萬以上HTTP請求無任何壓力,無報錯無內(nèi)存溢出無丟失數(shù)據(jù),甚至CPU和內(nèi)存還有相當多的剩余量,在單機性能達到這個程度時,我又陸續(xù)為這個中間件編寫集群版本/主從復制版本。
《高性能Java架構(gòu):核心原理與案例實戰(zhàn)》這本書我在寫之前構(gòu)思過無數(shù)次,但開始的時候始終無法達到我所想要講的那種優(yōu)化程度。
SQL優(yōu)化怎么講?這一條SQL我教你優(yōu)化之后,下一條你仍然不知道怎么優(yōu)化!
邏輯優(yōu)化怎么講?業(yè)務就是那么要求的?難不成教怎么和產(chǎn)品經(jīng)理打架讓他改需求?
架構(gòu)優(yōu)化怎么講?我把我所有架構(gòu)過的程序交代出來讓讀者挨個朗讀并背誦?
在我不斷練習之后,與不少程序員進行溝通,溝通具有實際意義的問題后,我才逐漸形成這本書。
“你知道if判斷是否影響性能么?”
“你知道for循環(huán)與foreach循環(huán)性能是否相同么?”
“你知道JDK的Stream流是否影響性能么?”
“你知道lambda表達式是否影響性能么?”
“你知道工廠模式是否影響性能么?如果影響大概到什么程度?”
“你知道幾種緩存形式?哪種性能最好?為什么不能一味的用性能最好的那種緩存形式么?”
“假如讓你做一套小說網(wǎng),那每一個章節(jié)那么多字數(shù),你都從緩存中獲取數(shù)據(jù)么?緩存不會崩潰么?Redis承受的住么?”
“你知道一個Java應用程序,什么框架都不引用的情況下,只寫入main方法與for循環(huán)HelloWord輸出,那在8核CPU,16G內(nèi)存的情況下最多能輸出多少次么?”
“你知道MySQL單表達到一億條數(shù)據(jù),在8核CPU,16G內(nèi)存的情況下,總數(shù)據(jù)體積達到幾個G,使用limit10字段,那需要多長時間獲取出來?真如網(wǎng)絡上所說的,MySQL單表4000條之后讀取速度就降級了么?”
以上問題,在任何搜索引擎上都不可能找到相應答案,但答案就在《高性能Java架構(gòu):核心原理與案例實戰(zhàn)》這本書里,更重要的是,獲取答案的方式方法就在這本書里!
我將我所學的架構(gòu)思想與測試方式都置入其中,文章簡短可能并不齊全,可能在學習此書的過程中您的學習筆記會比這本書寫的更加厚重,更厚重幾倍,若非如此可能效果不佳。原本我還想補充些內(nèi)容,但想想無用之文可能幾十本都放不下,更重要的是將方式方法告訴大家,將擴展視野的方式告訴大家。日后工作到什么程度,再看個人造化。
此書行文粗糙暫且見諒。愿您在讀此書之時可以領略到我在后期成長所體會到的一個個驚喜,愿您讀此書之后可以自信的說出前言中的答案,愿您在技術(shù)成長的道路上不會像我一直在走彎路。
愿您幸福。
張方興
行文于2021年4月某夜