初入公司,從CRUD到運維支持java
一年以前,我仍是一個只會CRUD的普通程序員,常年與業務打交道,一套花式SSM框架三板斧從頭玩到底。linux
我入職了一個初創型的互聯網項目團隊,在迅速融入工做環境之後,我就開始上手寫起了CRUD代碼。雖然不知道底層原理, 可是SSM模版代碼已經爛熟於心,再加上有一些在之前工做時學習到的基礎和避坑的經驗,好比空值驗證,防止重複提交等, 讓我可以比較快地完成業務代碼。nginx
領導看到了這一點,把我安排到了運維支持部,開始讓我幹一些運維的活(公司在初創期用人是有這個特色)。 那個時候,開始逐個上線一個一個的服務。這是我從零開始瞭解公司技術現狀的開端,也是一個加班到死的開端。其實加班的緣由我是很是理解的,這個和公司的技術現狀是離不開的,且聽我慢慢道來。程序員
艱難的系統部署:瞭解技術全貌redis
在一個晚上,領導拿了一份文檔,列了一系列要上線的服務和服務要部署在的服務器,而後咱們就逐漸開幹了。算法
新服務器都是極爲純淨的,連一些基礎命令都沒有,只好慢慢學,慢慢裝。yum install xxxx,run xxx , ps aux|grep,telnet ....,一天過去了,什麼jdk,tomcat,全都裝好了。數據庫
(ps. 作運維這段時間最大的收穫就是linux命令玩得很熟練。)apache
把服務部署後,啓動時就趕上了難題:之前的服務是打war包放到tomcat的,可是如今的服務,須要java -jar 來啓動。 嘗試了能夠後臺啓動的nohup java -jar , 直接翻車。 無奈去詢問以前的開發,人家說得用screen 命令後臺啓動程序。我是一個刨根問底的人,後來發現,開發在爲了保持進程不退出,錯誤的使用了監聽控制檯事件的方式,致使了nohup啓動異常。編程
那個時候,正在搞核心業務開發的人由於一直忙於開發和調試,和咱們的溝通少之又少;而負責部署的咱們,又不瞭解業務,有些問題當時的開發也懶得詳細解釋,因而咱們只能靠猜,來部署程序。json
混亂的程度可見一斑, 但這不是幾個程序員所能左右的。
我在那個時候學習到的第一件事就是:在信息不足和溝通受限的時候,你要嘗試學會必要的自行推理,根據已有信息的上下文來補全缺乏的信息。
上線要緊,暫時就screen啓動程序吧。可是程序啓動之後,又遇到了更加尷尬的事情。
當時服務之間的調用方式,所有都是經過HttpClient直接調用目標服務。假如,我先啓動A服務,A服務依賴B服務,B服務沒啓動,A服務初始化時會報錯。那麼,到底先啓動誰後啓動誰成了一個棘手的問題。
我查看了每個服務的工程配置示例,發現每個服務的config.properties,都有一個配置爲root的選項,標識該服務的發佈路徑,例如,用戶服務,他的config.properties 會配置 root=/userservice/ ,我就知道了,調用該服務確定是這樣的http路徑:http://ip:port/userservice/xxxx。config.properties中,也會有一些帶有以下特徵的配置 reference_user=http://ip:port/userservice/xxxx。我很天然的明白了,這確定是配置了該服務依賴的其餘服務的調用地址。所以,我就想到,我能夠根據每個服務的配置文件理順服務之間的調用關係。
爲了確保個人猜測是正確的,我用網上的工具反編譯了一個工程,發現,果真原來服務之間都是經過HttpClient調用的。
而後我就畫了工程依賴圖,仔細抽絲剝繭的梳理出來了程序的具體的依賴關係。最後,我終於對服務的部署順序和方式有了思路,而有些程序員,私下已經有人開始說幹不下去了要離職。
怎麼部署終於明白了,但是緊接着的一個尷尬的問題就是,程序都啓動了,也調通了,可是領導要求負載均衡,集羣化,一個服務裏直接調用另一個服務使用了HttpClient直連的方式,怎麼搞負載均衡?怎麼搞?怎麼集羣?
當時離DeadLine不遠了,上線重要,因而忍痛購買了阿里雲的SLB實現每個服務的負載均衡,當時最痛苦的事情就是要理順這種蜘蛛網式的服務調用關係,好在我以前已經畫了工程依賴圖,這個也就好辦了。
每天加班折騰到凌晨兩點,一個半月之後,終於把所有的Service部署成功,不可思議的是,我一個徹底不懂業務的人,徹底根據日誌信息和配置關係,搭建成功的服務,竟然有80%的功能正常可用,這給了我這個苦哈哈加班的程序員不小的成就感,雖然搞不定的20%的功能後來由負責這塊的開發親自去搞了(領導出面,不能敷衍了)。雖然,後面還有一些小的插曲,雖然這個應用剛開始可能全是窟窿,但好在也終於如期上線。
這一個半月,我掌握了公司的技術架構,在一些程序員以不會爲理由拒絕部署kafka,nginx,zookeeper,activemq等基礎設施的時候,我出手去部署,其實我也不會,可是從學怎麼用,到部署完,時間也是夠的,我還學習了這些技術是幹什麼的,不虧。
最終,我整理了公司當時的技術全貌,一些網絡轉發和機房架構因爲保密緣由不予描述(雖然我也已經掌握了),我只單純說一下代碼層面的:
一,服務與服務之間,經過RESTful風格的HTTP調用,使用了HttpClient,須要本身維護蜘蛛網同樣的服務調用關係。
二,配置文件有在本地的,有在數據庫的,代碼裏每次獲取配置每次都要load本地,select數據庫。(影響性能)。
三,無用的配置文件和無用代碼散落在各處,給運維形成了干擾,代碼有歷史遺留的味道。
四,技術棧不規範,有的人外置tomcat,有的人內置tomcat,有的人用了Netty,簡直就是羣魔亂舞。
五,命名不規範不統一,詞不達意,公司用了elastic-job做爲分佈式任務調度平臺,elastic-job要求每個job啓動時須要指定job-name,可是,運維常常在控制檯上沒法根據job-name來定位究竟是哪一個job,好比,工程job爲payServiceAllJob,在控制檯上卻註冊爲AllJob,讓人摸不着頭腦。
痛點一:缺少服務的自動發現
服務上線之後,因爲自己項目就是在沒有規範,沒有制度的狀況下放肆生長出來的,所以服務上線之後仍是會瘋狂的加班,來彌補一個又一個補不完的窟窿。那個時候我尚未接觸業務,可是也要和開發一塊兒加班,人工值班監控。
已經一個月沒有寫增刪改查了,我就有機會開始搞一些事情了。那個時候,我請個人領導去說動技術部使用Dubbo,由於它能作服務自動發現,免配置擴容服務,是一個挺流行的RPC框架。可是因爲當時咱們沒有技術權限,這個事情是很難推進的,一切以穩定爲主。
我使用過Dubbo,可是我一直不理解的是,爲何Dubbo使用了ZooKeeper就能自動擴容?就能服務自動發現?這個確定和ZooKeeper有關係。因爲我是刨根問底型的開發,所以我開始在週末時間和晚上和上下班路上本身學習ZooKeeper,什麼順序節點,永久節點,臨時節點,什麼樹形存儲,動態監聽和通知。
終於,我就在沒有看Dubbo源碼的狀況下忽然恍然大悟:Dubbo的服務提供者和服務消費者都配置了服務name,若是我在ZooKeeper的一個name節點下存儲服務路徑集合,那麼每次新增服務或者下線服務都會通知到任何監聽這個name的客戶端?(後來知道這叫作namespace命名服務),Dubbo確定是使用了Zookeeper的命名服務來實現服務的動態發現的!
大部分程序員使用HttpClient都是使用的一個叫HttpHelper的工具類,個人改造就開始從HttpHelper這個工具類開始吧,讓程序員傳遞本身的服務的ip,port,se rviceName,destinctName,zookeeperUrl,而後我在工具類裏封裝了獲取調用路徑列表,並封裝了兩個負載均衡算法:ip_hash,隨機數。(其實我只會寫這兩種)。
在公司的四次迭代裏,他們在一邊飛速業務開發,一邊逐漸把本身的HttpHelper工具類替換給我寫的這個,終於能夠卸下slb,實現簡單的HTTP服務動態發現了。
當時的反對聲音其實仍是挺大的,不過運維的需求呼聲更高,配置URL太麻煩了!
那個時候,公司架構重組,得領導賞識,我被從新劃分到了技術部,作了基礎平臺研發部門的Team Leader,管理幾個程序員。
痛點二:缺少配置中心
解決了第一個痛點之後,我一邊寫增刪改查,一邊又想解決第二個痛點:配置問題。
以前每次部署程序到線上時,每次都要一個服務器一個服務器的改配置,我就想,我把個人時間浪費在這種一個服務器一個服務器改配置的事情上,真的是不甘心。
並且這麼改配置,還容易出錯。雖然公司沒有主動要求寫什麼。(公司的主要眼睛仍是放在了實現功能和業務上)那個時候加班沒有那麼狠了,程序員寫完增刪改查就回家了,我還在想配置中心怎麼實現。那個時候微服務的概念火熱,我瞭解到了Spring-cloud-config。知道有叫作配置中心的這種東東,對,咱們也須要配置中心,把配置集中抽出來管理。因爲我已經掌握了ZooKeeper,天然知道了作配置中心的思路。
半個月時間我就寫完了,時間主要浪費在了寫頁面上。(汗,做爲一個後臺程序員我認可個人頁面能力比較差)固然,這期間也通過了一些改版。我居然不知道ZooKeeper有Curator這麼好用的客戶端,以前一直使用的原生的org.apache.zookeeper這個原生客戶端操做,監聽消費之後還要從新監聽。
配置中心寫完之後,我也在一個週末發到了羣裏,並推廣了出去。此次,因爲公司的人員團結力已經大有改觀,並且我也已是組內Team Leader,先在組內普及了。
並且我此次組外的遊說和推廣也沒有那麼困難了,最終也都一個服務一個服務的落地了配置中心,並實現了一處改動,到處生效,也實現了傳說中的配置熱更新。這些,並無什麼高深的技術,僅僅就是依賴了一個ZooKeeper。
弄完這些,我已經感覺到了作技術的樂趣,同時,個人領導也以爲好像讓我寫增刪改查有點浪費,要求我把我手頭的任務所有分給組員,本身則是去解決別人的問題......我贏得了更多的時間去自我驅動,改善公司的基礎設置。
痛點三:缺少緩存框架
接下來我本覺得本身要沒事作了,可是,得益於左耳聽風的一個專欄,他說,描述一個業務(DSL),要比編寫一個業務更具備維護性,公司不少的人都在使用Redis緩存,可是,用的庫各不同,還常常出各類奇怪的問題,調試起來及其繁瑣。
固然,最終讓我受不了開始決定寫緩存框架的是由於我看到了個人組員寫的代碼與業務嚴重耦合,一會操做Redis,一會操做數據庫。我發現了這個痛點,研究了一下Spring的AOP和他的@Transtional 註解如何實現之後,終於決定手寫一個微型的緩存框架。基礎思路就是經過可插拔的@CacheEnable(key=xxxx,timeout=xxx......)實現Redis緩存,徹底不侵入業務代碼。若是不用了,把註解在方法上移除了就行了。
手寫這個Redis緩存框架使用了半個月,畢竟本身的技術能力仍是有限,如何實現AOP和Spring集成,怎麼抽象等等,都會讓我天天都思考半天才下筆,甚至有時候一天寫不了一行代碼。
期間看了一本叫作《面向對象編程》的書籍,裏面說,面向接口編程,依賴抽象,而不是依賴具體的實現......我忽然就像打通了任督二脈。我在CacheHandler裏面依賴了CacheStorage接口,而把RedisCacheStorage做爲一個實現類注入了進去,所以,後來我這個框架能夠同時支持redis,memcache,local。
寫完這個框架之後,我總結了三個可抽象的點:
1. 序列化方式(jdk,protobuf,thift,json)
2. 腳本解析器方式(就是解析key的方式:好比,可使用spel或者ognl:"userId"+#user.id )
3. 緩存實現方式(redis,memcache)。
後來我從劉大的碼農翻身公衆號的一篇將日誌系統的設計裏知道了正交一詞,大概這就是正交吧。最尷尬的是,原來Spring早就實現了,叫作SpringCache。汗。
(碼農翻身注:那篇文章叫作《一個著名的日誌系統是怎麼設計的》)
後來的事情,我也不詳細的講了,大概就是從私有框架,換成了公共成熟的庫,咱們也終於用上了Dubbo框架。
而對我本身自己,我只是更加理解了一些以前沒法理解的事情:Dubbo爲何能改一個組件的配置那個組件就換了一種實現。(面向接口編程)看Mybatis的源碼也沒那麼困難了,兩年前徹底下不去手。固然,我也變得更加熱愛技術了。
個人心得體會
那就給你們分享一下我近兩年來的心得體會。
1. 做爲一個程序員,必定要懂得自我挖掘,而不是僅僅實現業務功能就行了,也不能幹等着領導分配任務。
功能耦合了,寫代碼慢了,運維麻煩了,這些,都是潛在的需求,咱們如今的加班,是爲了之後不加班,是爲了提升本身的效率,是爲了避免能原地踏步。
2. 必定要真正地學會一個技術,我在實際工做中,發現有的同窗使用了一年的Git,居然不知道如何把GitHub的項目拉取到本地,可是他會把GitLib的項目拉取到本地。
程序啓動異常,有同窗從網上找了一個jar包導入到了工程裏,可是問他爲何把jar包導入到工程裏代碼就啓動正常了,居然不知道。
有的同窗使用了一年的Maven,不知道mvn compile 是什麼含義,只知道mvn package是打包。
這些,就是沒有真正的學會了一個技術,僅僅是工做時機械式的使用了,僅僅是複製粘貼了,下一個項目再複製粘貼過來就好了,模仿着別人的代碼寫邏輯,這是學不到東西的。
我以爲,你必定會有時間去學習這些東西,網上大把大包的資料和教程。必定要知其然而知其因此然,必定不要如出一轍的配置換了一種配置方式你就看不懂了。
3. 要掌握公司的技術棧,要刨根問底,公司用的什麼rpc框架?怎麼使用?原理是什麼?公司用的nginx,nginx怎麼配置的。公司用了配置中心,配置中心是什麼?公司的負載均衡框架用什麼作的,存在什麼問題?
我寫了一個緩存框架,你有沒有衝動研究一下究竟是怎麼實現的?保持技術好奇心是十分重要的。我認識的一個同窗,來咱們公司之後,簡歷上寫的,會SSM。後來經歷了個人配置中心演進之路,還學會用了。後來他離職了,簡歷上寫的仍是會SSM,沒別的了。原本,若是他把配置中心講一講會是一個很大的亮點。工做了一年,最怕的就是揮一揮衣袖,不帶走一片雲彩。
4. 要善於發掘,總有一些東西是亮點,是金子,只是你發現不了。
我在咱們公司學到的一個安全方面的設計就是token機制,這改變了個人觀念,之前一直覺得作單點登錄只能session共享,如今才知道,還能使用時間換空間的方式,使用token簽名代替sessionId,使登陸這個過程變得成爲無狀態的計算......這是我發現的,不少人程序員根本不能意識到這些技術亮點,並融化到本身腦海裏成爲本身的東西。
5. 使用碎片化時間去學習,不要總抱怨沒有時間。
學習是枯燥的,可是,當你收到了學習帶來的巨大紅利,你會愈來愈想學習。我親身的體驗就是,當我寫的配置中心和緩存框架投放到了生產中,並獲得了我想要的效果後,我如今更加喜歡學習,更加癡迷於技術了,個人技術能力並不強,不少的東西,都是由於個人興趣逐漸被激發,由於個人熱愛,才發生了質變。
6. 多思考,正確地實現業務。
有沒有觀察過,一樣的業務,有的人寫出來的實現就很是的豐滿和穩定,而有的人寫出來的接口可能直接調用一下就拋出了錯誤。不少程序員寫代碼只關心正常分支的邏輯,歷來不考慮異常邏輯的處理。在寫業務代碼的時候多去分析用戶場景,也會規避不少問題。
舉個例子,接口的參數的驗證,你能夠根據使用場景來編寫額外的適配和容錯。好比,接口中有一個字段A,這個字段大小寫敏感嗎?這個字段萬一用戶多輸入了一個空格怎麼辦?若是你能根據業務分析到,字段大小寫不敏感,我要所有轉成小寫來比較,空格不是正常參數的一部分,我要進行去空格來簡單的容錯。那麼,你可能會避免有一天某個業務人員跑過來跟你說,我明明寫的正確爲何你告訴我參數不存在。
不要小看業務代碼,沒必要掌握多麼高深的技術原理,只要能把業務邏輯實現的健壯,也已經很考驗能力了,說明了你是一個喜歡思考和注重細節的人。
結束語
如今的我,愈來愈喜歡研究源碼,研究底層,並伴隨着的是,我之前的一些疑惑都迎刃而解,這固然是由於我獲得了正向的反饋,付出會有收穫。如今被公司內部的部分程序員誤認爲是大神,固然,我還差得很遠。
如今公司技術,代碼逐漸在變好,工程規範逐漸在行程和標準化,統一化。這是值得欣慰的,我最近在研究API網關,公司的業務併發量在上升,我以爲須要一個入口統一管理API,負責鑑權,認證,限流,熔斷等一系列的功能。(這些詞都是在微服務課堂上學習的)。我已經開發了一部分了。使用Netty接收請求,使用HttpClientPool轉發請求,中間使用責任鏈模式作Handler中轉攔截處理,不知道什麼時候能竣工。