愛鋒貝

標題: 筆記-1.0版本 [打印本頁]

作者: ★小梁帶你玩手機★    時間: 2023-4-16 23:41
標題: 筆記-1.0版本
關于本篇文章

第一次書寫時間:2017/12/19/9:08

第二次書寫時間:2017/12/19/14:07

第三次書寫時間:2017/12/19:20

第四次書寫時間:2017/12/19/22:55

第五次書寫時間:2017/12/20/10:31

第六次書寫時間:2017/12/21/8:32架構(gòu)設計

整體工程

概略圖:

(, 下載次數(shù): 568)

頂部層:

( NETFLIX|OSS =>Spring Cloud )和 Spring Boot 以及 docker
NETFLIX|OSS =>Spring Cloud:

屬于aws那種以前的方式,Spring Cloud很大一部分都是基于NETFLIX |OSS,對于java開發(fā)者并且不在aws上部署服務來說可以幾乎等同于Spring Cloud,以下也是基于Spring Cloud來講述的

隨著項目工程的越來越龐大、開發(fā)語言的差異漸大、業(yè)務閉環(huán)組合敏捷開發(fā)帶來的指引,我們進入了多系統(tǒng)多部署[分布式]的時期,一個組合業(yè)務的系統(tǒng)劃分成多個單獨業(yè)務的系統(tǒng)并且每一個業(yè)務都可以通過部署在多臺服務器來大大增加或者增強后臺的響應速度、并發(fā)量、業(yè)務回環(huán)速度、系統(tǒng)穩(wěn)定性等等。

同時這些一些問題必須急切的被解決: 服務注冊及發(fā)現(xiàn)、負載均衡、調(diào)用鏈容錯、統(tǒng)一路由、配置及依賴管理、多語言并存而統(tǒng)一調(diào)用聲明、可視化運行狀態(tài)監(jiān)控。

服務注冊及發(fā)現(xiàn):運行在多臺服務器上的同一個業(yè)務各自的所在ip不同,對于調(diào)用者或者說是服務消費者來說服務提供者是透明的,''我''需要引用特定而不需要明確指定具體調(diào)用的的提供者的最終ip,因為很有可能在某些情況下,那臺服務提供者因為一些原因資源占用率過高而無法服務,因為沒有哪種實現(xiàn)思路可以明確知道前臺業(yè)務上使用者的資源消耗是多少,也有可能是某一臺服務提供者的所在真實物理機器宕機了,此時如果是依賴的具體Ip就會導致無法獲取服務,或許會說,就算這臺服務器掛了,我換一臺不就行了?確實是可以的,但是你如何得到下一個屬于可用狀態(tài)且不會再并發(fā)嚴重情況下獲取可用物理ip地址呢?此時就會先需要一個數(shù)據(jù)庫來記錄、修改、刪除、查詢這些可用的屬于你所依賴服務的服務器ip,Eureka Server 就是這么做的,一個較為完整的流程是:當服務提供者開啟的時候?qū)⒆陨韎p和所屬業(yè)務提交給eureka server,eureka server會將當前節(jié)點添加到它的內(nèi)置數(shù)據(jù)庫中,而且很完善的是eureka server會自動定時的去監(jiān)測注冊到它上面的服務提供者,同時也是需要服務器提供者配合,通過內(nèi)部心跳機制向eureka server證明自己還活著,否則在超過一定時間后,eureka server就會將這臺服務器提供者從數(shù)據(jù)庫中移除,移除之后,其他消費者就不能引用到它了,通過這樣的機制,服務提供者對于服務消費者來說是高可用的,任何一臺服務提供者下線之后對整個服務提供者是無影響的,消費者是無感知的,但是會提高負載。但是也是有一個問題,eureka server此時就成了瓶頸了,eureka server能否工作以及是否流暢影響著整個系統(tǒng)的可用以及性能,對于一個系統(tǒng)來說維持這樣一個其實還屬于可容范圍,但是如果宕機了就不能了所以其實eureka server有備份節(jié)點的,當其他節(jié)點發(fā)現(xiàn)當前工作節(jié)點已經(jīng)無響應了,就會取代原節(jié)點繼續(xù)工作,這里用分布式系統(tǒng)的組件來描述就是zookeeper分布式協(xié)調(diào)組件 和 redis 哨兵機制

負載均衡:一個系統(tǒng)能否流暢工作一個是取決于系統(tǒng)本身是否能容下業(yè)務所需資源,另一個是資源是否能分配合理,過多的資源壓力會導致機器過早疲憊甚至宕機,當有機器無法負載而無法提供服務時,整個服務就會的平均負載就會提高導致滾雪球版崩潰,或許有人會說,有幾臺機器宕機了,我就再加幾臺機器不就行了嗎?但是你要知道根本原因不解決好,再加進來的服務器一樣會再次奔潰,然后原來的機器由于較少壓力導致一直處于空閑狀態(tài),微服務集群中看起來有5份效率正常輸入服務其實有可能是3:7  / 2的關系,而且頻繁上線下線機器會導致服務管理者的效率下降從而是整個集群過早崩潰,常用的負載有隨機分配RandomRule、輪詢獲取RoundRobinRule(默認)、試探性獲取RetryRule、權(quán)重分析WeightedResponseTimeRule等等,在不考慮自身消耗且確實有可用的情況下,試探性獲取是最有效果的實現(xiàn),但是其實獲取其他機器的負載情況是需要消耗性能的,尤其是在多次獲取無果的情況下是非常浪費性能的,但是如果最終無果,那就該考慮實現(xiàn)自動擴容及自動收縮了,也就是說在集群變動情況較大情況下,是不太可取的,隨機分配在剛開始時是可用且消耗低的,但是隨著集群運行量及負載量達到一定程度時,隨機分配是萬萬不可取的,輪詢獲取,是消耗低較為中性的,但是考慮到最終客戶端的消耗可能大多不一樣,可能會導致在分配圈中總是分配某一臺或者某一些機器,此時就是不太好的,但是也可以通過非對距圈性關系來持續(xù)輪詢,那樣就不會導致持續(xù)磨損某一臺機器了,最后的權(quán)重分析是屬于統(tǒng)計的結(jié)果,server端每隔30秒統(tǒng)計一次給出權(quán)重,一個是多個業(yè)務情況下對server負載增加壓力而且當某一個時間激增的情況下,可能激增的時間小于30S秒,此時這個算法就是難以切合實際的

調(diào)用鏈容錯:從一開始的切分業(yè)務到最終組合業(yè)務可能會形長大距離的多分化的線路[鏈路],當某一個服務提供點出現(xiàn)問題并且依賴其服務的其他消費者存在調(diào)用鏈時,這條調(diào)用鏈就可能會造成失敗,并且是級聯(lián)失敗。我們以前的做法是拋出異常讓最終捕獲做出處理,但是呢?一個花費了很大資源的操作因為一些可能不是很重要且必須的操作而失敗,最后的結(jié)果為Null,其實有些操作我們可以實現(xiàn)一個后備數(shù)據(jù),有些操作即使沒有真實數(shù)據(jù)其實也是合理的,比如說我要買10個東西,結(jié)果第5個的時候出錯了,不能購買,以往的做法是直接報錯,整條鏈路返回,但是也是資源消耗極重的,spring cloud 模式的判斷規(guī)則是5秒鐘內(nèi)失敗20次表示此節(jié)點可以進入熔斷模式了,也稱為保護路模式。

統(tǒng)一路由:在一個十分龐大的分布式的業(yè)務系統(tǒng)中,其中對外暴露的功能是非常復雜以及繁瑣的,如果是每個子系統(tǒng)各有一套聲明規(guī)則,最終在組合成api文檔時,這個文檔的調(diào)用者肯定內(nèi)心幾乎是崩潰的,一會是REST風格,一會是帶參風格,況且每一個系統(tǒng)的著重點不同,**微服務最大的特點是架構(gòu)再怎么變對整個系統(tǒng)來說都是無感知的**,在互聯(lián)網(wǎng)的時代,項目整體架構(gòu)風格是不斷迭代的,就像樂高積木,在做好了這些基礎的方塊之后,后面組合的形狀取決于業(yè)務發(fā)展,也可以稱為業(yè)務驅(qū)動,典型代表為淘寶,使用路由的思想,由路由入口打開流量入口,對外來說整個項目完全像是一個系統(tǒng)一樣,接口文檔的風格完全統(tǒng)一,對于不同業(yè)務系統(tǒng)的負載均衡策略也不同也是很容易實現(xiàn)的,對于像swagger這種項目動態(tài)文檔肯定也是放在路由上的,對內(nèi)實現(xiàn)為zull根據(jù)負載均衡策略轉(zhuǎn)發(fā)請求到具體的實現(xiàn)者上.

配置及依賴管理:微服務雖說是各自系統(tǒng)維護各自功能,但是很多配置文件還是需要統(tǒng)一的,并且伴隨中整體系統(tǒng)的升級,這樣的全局配置變量如果是各自固定日寫死的話,后面的改動就那么容易了.畢竟一個幾十個系統(tǒng)能夠非常迅速的改動同一個配置常量也是非常困難的,在eureka server中實現(xiàn)可以使用spring cloud configure,而在consul中是內(nèi)部已經(jīng)實現(xiàn)了,其實這樣的配置中心只不過是一個微型的k-v數(shù)據(jù)庫而已,當項目子服務系統(tǒng)中配置了配置中心時,在配置文件中引用變量會導致加載配置文件時動態(tài)從配置中心拉去數(shù)據(jù)并填充.與maven的思想有點類似.依賴管理使用的是maven來做到的,其實spring cloud 的實現(xiàn)一般都是maven項目,同時spring cloud官方推薦的是spring boot的基礎項目構(gòu)造.maven可以理解為一個特殊的能為你的功能導入jar庫文件的軟件,這個軟件是apche下的一個優(yōu)秀項目,項目受到開發(fā)人員的贊賞至今.這些具體的jar庫文件會默認在你本地的c:/用戶/用戶名/.m2/repository下,以導入org.springframework.boot包的spring-boot舉例,在repository下會有一個org的文件夾,其實就是以.分隔,每一個分隔的值都是一層目錄,這里為org/springframework/boot/spring-boot文件夾,在之之下為各種版本號名稱的文件夾,例如1.5.8.RELEASE/2.0.0.M3/...,在這之下為具體依賴的庫文件了,例如:spring-boot-1.5.8.RELEASE.jar/spring-boot-1.5.8.RELEASE.pom/spring-boot-1.5.8.RELEASE-sources.jar/...,在項目的pom.xml文件依賴庫文件的時候需要指定依賴的組織名和工程名和版本號,版本號會和這里的文件夾的版本號名一致,默認會導入運行依賴jar而不是source源碼jar.同時在定義導入規(guī)則時可能不止3個,可能會有依賴環(huán)境,例如編譯期compiler/測試期test/...,還有可能會到項目本地文件夾中依賴jar包,那么就需要使用systemPath標簽填入${project.basedir}/lib/xxx名稱-版本號.jar,這些jar庫文件一般都是來自于maven的外部庫,例如maven的中心庫或者是其他公司的私有庫,當然我們也可以搭建私有庫,使用nexus搭建,一般在linux搭建服務的流程為下載文件,解壓,配置配置文件,加入系統(tǒng)自啟之類的環(huán)境變量文件中,使用給定的啟動文件和參數(shù)啟動服務.至于nexus的水平擴容,我暫時還沒有做過.

多語言并存而統(tǒng)一調(diào)用聲明:使用注解方式標注網(wǎng)絡請求url來標注當前類為服務接口調(diào)用類,與以前使用的dubbo很相似,只不過dubbo是需要配置文件指明接口類對應的url,沒有擴容功能,開發(fā)也并非簡介,與spring boot的基于注解特點相違背,以前像這種都是將接口文件安裝到nexus中,服務調(diào)用者需要先依賴該接口文件然后配置再調(diào)用即可,由于是基于http網(wǎng)絡接口的,所以擁有跨語言的強大功能,調(diào)用遠程服務就像調(diào)用本地功能一般,當然也有一些屬于正常范圍的限制,比如說超時機制,比如說序列化效率低、效率不如dubbo/protocol buff/thrift.

在spring cloud中,這些問題的實現(xiàn)者為:服務注冊及發(fā)現(xiàn)(Eueka Server/Consul+Eureka Client)、負載均衡(Ribbon)、調(diào)用鏈容錯(hystrix)、統(tǒng)一路由(Zuul)、配置及依賴管理(Configure Server)、多語言并存而統(tǒng)一調(diào)用聲明(Feign)、可視化運行狀態(tài)監(jiān)控(Metrix)。

值得一提的幾個問題:

    1、微服務與單體架構(gòu)?最初項目由面向過程編程的c語言轉(zhuǎn)向面向?qū)ο蟮膉ava/c#編程,java以其一處編譯處處運行,伴隨著世界上最主流的服務器系統(tǒng)linux打敗了其他語言,人們以為這是以后的趨勢了,其實不然其實這才是開始,java工程通常對應小型企業(yè)來說是運行在tomcat上,中間或者會使用nginx做代理服務器來達到水平擴容,但是算一個數(shù)字,tomcat的并發(fā)量為300,不過新版本的tomcat的實現(xiàn)使用netty線程模型,可容并發(fā)量大大提升,但也是差不多,在通常情況下tomcat要實現(xiàn)業(yè)務的水平擴容必須實現(xiàn)session 共享,眾所周知session 節(jié)點不能超過8臺,否則此集群光是同步session所消耗的資源就已經(jīng)將所有帶寬都給占滿了.這時候前面的nginx反向代理服務器難道就可以了嗎?其實nginx并發(fā)量也是有限制的,畢竟nginx是無法反向代理的,理論上nginx的并發(fā)量為50000+,而實際并發(fā)量為30000+,一個系統(tǒng)難道十年前3W并發(fā)夠了,今天還是3W并發(fā)量就夠了嗎?每一年的并發(fā)量都在指數(shù)級的增長,所以**單體工程的容載量很難增長**, 而微服務架構(gòu)下的容載量就很容易提升了,以為服務之間的依賴是通過依賴服務實例名稱的,而對外接口是網(wǎng)關分配可用實例的,微服務下不會直接使用session,所以對外來說使用哪一個正在運行中的實例都是沒有很多區(qū)別的,而對于像是登錄這種特殊操作,通常服務器都是會保存登錄的客戶端狀態(tài)的,對此,我們往往使用SSO(single sign on)或者oauth2.0協(xié)議下的uaa系統(tǒng).對于很早之前的互聯(lián)網(wǎng)時代,需求都是來自分析的積累,剛開始的的項目都是幾乎新生的,項目開始者需要面對于市場的風險、同類產(chǎn)品的競爭危機、工程技術的回避風險,在反復推打過程中就最終確定了項目的原型了,由于當時的IT項目的體驗還是比較新鮮的,在新項目剛開始的一段時間,用戶也是出于摸索階段,項目的推廣使用也是非常緩慢的,系統(tǒng)的維護時間還是非常充足的,找一個深更半夜停了再發(fā)布也是無足緊要的,但是,現(xiàn)在就不太一樣了,用戶量的海量增長,需求的迅速開發(fā)發(fā)布,如果是按照以往的方式,可能需要每幾個小時整個系統(tǒng)都是需要重啟的,而對于越來越龐大的代碼量,越來越大的遺留問題,部署時間和開發(fā)時間越來越長,這樣的系統(tǒng)最終會倒下,甚至會總是在忙于解決以往問題而無法解決新問題的。很慶幸,如果你使用微服務架構(gòu),你的系統(tǒng)的功能架構(gòu)依舊不變,但是代碼會拆分成多個子系統(tǒng),子系統(tǒng)可以隨意水平擴容,在有新需求的時候,如果是已有系統(tǒng)的功能增長,那么會在已有系統(tǒng)的基礎上繼續(xù)開發(fā)新功能,如果這個功能達到一定程度,這個時候子系統(tǒng)是可以繼續(xù)切分的,此時開發(fā)人員是可以由內(nèi)調(diào)或者外招的,各個系統(tǒng)的交互使用HTTP協(xié)議進行通訊,無論是java/c#/go開發(fā)的系統(tǒng),整個系統(tǒng)都是高度兼容的.**單體架構(gòu)的push周期或者業(yè)務回環(huán)周期過長而由于微服務各部分是實現(xiàn)上的互不影響的,每次修改都是添加功能,不會影響其他模塊,所以可以調(diào)高效率** .

    2、微服務與分布式? 分布式是微服務的前生,分布式達到了一個大型項目的規(guī)模、兼容性和效率,但是其管理開發(fā)過程過于重量化,過于依賴運維沒有統(tǒng)一實現(xiàn)、很多都是零零碎碎的拼接起來的,在服務注冊與發(fā)現(xiàn)中使用的是RPC框架,比如說Dubbo和Zookeeper注冊中心,在負載均衡上依賴Zookeeper或者nginx的實現(xiàn),對于開發(fā)人員來說可用功能過于簡單,在調(diào)用上過于依賴語言特點,例如: Java服務如果使用Dubbo的話就只能被java服務調(diào)用,配置文件過于零碎,難以管理,因為就算是依賴管理使用了maven以及私有庫,但是配置文件的部分值也是很難實現(xiàn)的,而且分布式一致性在分布式項目中的實現(xiàn)并非是直接實現(xiàn)的,而在微服務spring cloud中確實很容易實現(xiàn)的,常見的實現(xiàn)者為consul.RPC框架一般都是基于二進制流(自定義序列化),所以在跨RPC框架的實現(xiàn)上也是比較難的,而微服務是基于HTTP協(xié)議的,兼容性更高,但是實際運行效率是更低的.在功能的劃分上,分布式的粒度更大,因為他是重量級的,粒度過小對整個系統(tǒng)來說是災難性的,而微服務粒度更小,因為各自服務是自治的并且有網(wǎng)關在流量入口把握.Spring Boot:

一個經(jīng)過整合過的輕量級的spring 框架,通篇項目中避免使用xml文件而是用注解來簡化項目,提高開發(fā)效率.基于spring 4.x實現(xiàn)了項目依賴動態(tài)掃描達到動態(tài)配置,項目可自帶運行容器環(huán)境,經(jīng)過maven打包成jar包后可直接啟動,在實際項目中啟動命令可為 nohup java -jar xxx.jar & ,同時基于spring boot的maven依賴文件一般為spring-boot-xxx-starter,spring boot官方已經(jīng)提供了很多starter依賴,例如:data-jpa/web/....同時非常適合作為spring cloud的 基礎架構(gòu),spring boot的web依賴默認為spring mvc作為控制層處理框架,使用thymeleaf作為前端模板框架,同時效率比傳統(tǒng)servlet工程的jsp的效率要高,在使用上接近于jsp和freemearker的面向?qū)ο?同時擁有jsp/freemarker的邏輯控制功能,作為固定填充數(shù)據(jù)非常容易.在spring boot工程中通常由標注了@SpringBootApplication的類的main啟動加載整個項目,初始化spring 容器,生成被標注了組件的類的bean,docker:

一個容器技術,容器技術并非近些年的新技術,而是很早之前已經(jīng)投入大規(guī)模實際生產(chǎn)的,早幾年前,有openstack等等商用容器化技術,而作為新技術docker與openstack的區(qū)別在于docker使用了中心鏡像倉庫,使得很多原本安裝在linux的服務可以通過從中心鏡像倉庫pull下來后直接運行而無需再次重復進項常規(guī)的linux運維操作,甚至在結(jié)合k8s或者swarm之后,可以迅速的大規(guī)模的水平擴容,這在過去無容器技術時是想都想不到的.同時docker是基于linux宿主機的內(nèi)核的,是基于進程的隔離,所以docker的啟動時秒級別的,但是openstack呢?分鐘級別,openstack也有鏡像的概念,但是這個鏡像與docker聯(lián)合鏡像文件有些不一樣,docker的aufs可以基于鏡像分層,使得很多鏡像可以共享鏡像基礎層,與openstack不同的是運行中的docker容器是基于覆蓋鏡像文件達到修改的操作的,所以不同容器的運行狀態(tài)可以不同卻共享基礎鏡像文件.再看oepnstack的使用,繁瑣的配置文件,復雜的運維,docker基于shell式的交互,提供了pull鏡像,運行鏡像,停止容器,重啟容器,刪除容器,通過-v參數(shù)指定數(shù)據(jù)卷的掛載位置實現(xiàn)持續(xù)的使用.同時作為容器常用功能可以映射端口或者隨機ip到宿主機中,通常一般都是使用-P指定固定端口,docker輕量級、高效率、眾多免費鏡像可用、支持大規(guī)模集群.同時docker的安裝也是非常簡單的幾乎不怎么需要修改配置文件,安裝時也只是一條yum指令就可以了,其實docker也是有一些不足之處的,比如說docker的安全性并不是特別高,集群間的網(wǎng)絡傳輸效率也不是很高,配置容器的一些環(huán)境變量時并非特別方便,記得很典型的一個問題,docker-mysql中,針對時區(qū)的配置,為何不默認直接掛載宿主機的時區(qū)配置文件呢?中間層:

使用spring cloud 作為微服務實現(xiàn)框架,所以首先需要確定服務注冊中心服務,對于spring cloud來說,實現(xiàn)可以為:consul或者eureka server,對于配置中心服務器,consul已經(jīng)內(nèi)置了,而eureka server需要另外搭配config server,對于這樣的注冊中心,默認端口為8761,同時eureka server和consul不能共存.而在正式系統(tǒng)中,為了保持一致性以及系統(tǒng)功能簡化,使用gateway網(wǎng)關系統(tǒng),通常實現(xiàn)為zull,以前我也不理解為什么需要一個多余的網(wǎng)關,但是后來才慢慢理解到,對于一個不斷復雜的微服務系統(tǒng),網(wǎng)關的作用是非常重要的,節(jié)點擴充后,外部不能直接訪問固定的ip而是需要訪問一個代理去獲取所有可用的可用ip然后調(diào)用具體的ip的功能,獲取可用ip列表是eureka server 或者consul可以做到的,但是這兩個卻無法直接調(diào)用ip的功能,所以需要一個能夠調(diào)用轉(zhuǎn)發(fā)的功能,這就是zull的一個特點,同時對于swagger這種動態(tài)接口文檔,我們也是將其放到網(wǎng)關上的.簡而言之就是瀏覽器直接訪問gateway,gateway轉(zhuǎn)發(fā)到具體微服務系統(tǒng)上去指定調(diào)用功能.但是也是有一些問題的,并非所有的轉(zhuǎn)發(fā)都是有意義的,比如說有權(quán)限認證的系統(tǒng),需要進行訪問控制'Access Control',具體使用基于oauth2.0標準的uaa系統(tǒng),而這個系統(tǒng)需要使用用戶權(quán)限規(guī)則的聲明,另外一個問題就是對于一次調(diào)用的負載均衡也是在網(wǎng)關上做到,所以眾所周知zull的starter依賴中默認都是有ribbon的.然后內(nèi)部子系統(tǒng)直接首先需要配置注冊中心所在ip位置然后直接依賴服務生產(chǎn)方的聲明的名稱在配置了ribbon的負載均衡之后會在每次消費服務接口時進行相應規(guī)則的負載均衡.底部層:

著名的日志收集分析框架-->ELK,分別是ElasticSearch、Logstash、Kibana的簡稱.elasticsearch簡稱es,是一個分布式的擁有獨立部署能力、多線程等特點的搜索引擎,與Luccen的區(qū)別?Luccen是一個文檔搜索的開發(fā)包,并沒有部署能力,同時在一個項目中如果繼承了搜索功能,那是絕對不會將搜索功能內(nèi)嵌到項目中的,因為搜索功能的負載也是非常大的,同時文檔庫的聲明、持續(xù)使用、備份等操作與傳統(tǒng)項目是相背道的.與Solr的區(qū)別?Solr是一個搜索引擎,實現(xiàn)也是使用luccen,其擁有部署能力,但是Solr的部署能力也是非常有限制的,Solr天生并不支持集群,在我以往開發(fā)過程中雖然也是搭建了Solr集群,但是借助apache的另一個項目:Zookeeper,雖然最終可以實現(xiàn)分布式,但是依然是有很多問題,一個是搭建復雜,依賴運維操作,一個是最終文件的一致性問題.而es不一樣,es天生支持分布式,在使用docker鏡像搭建es集群時,強烈建議配置內(nèi)存大小至少分配4G以上,不過或許這也是solr的一個優(yōu)點吧,占用資源更少一點.而logstash是日志的分析、kibana是將數(shù)據(jù)可視化了,使用了metrix技術技術總結(jié)

在實現(xiàn)具體子微服務系統(tǒng)中,使用以下技術:spring boot

作為每個子系統(tǒng)工程的承載者,以基于注解簡化開發(fā)出名.基于spring 4.x,而spring 是現(xiàn)今java 網(wǎng)站開發(fā)的趨勢框架.由原來的重量級的EJB框架到現(xiàn)在無人不認同的輕量級Spring框架.Spring并非強制規(guī)定了整個系統(tǒng)的開發(fā)流程,而是提供了輔助功能,在針對傳統(tǒng)網(wǎng)站的輸入->處理->輸出抽象成了MVC的架構(gòu)思想,控制數(shù)據(jù)輸入輸出->獲取數(shù)據(jù)->獨立界面層開發(fā),spring一直起著輔助整個作用,剛開始面對使用strux/strux2的使用者,spring 的整合是非常優(yōu)秀的,spring定義了項目的啟動,即必須先加載spring容器,在依賴的strux是會加載配置文件配置的action類,在依賴了hibernate時會加載配置文件中配置的dao類,等等諸如此類,spring提出了依賴注入(DI[Depency inject])的思想來做到松耦合的效果,然后上面的加載操作也就是new bean的操作,我們稱之為IOC控制反轉(zhuǎn),每一個模塊中只需要使用@Autowired之類的注解即可在調(diào)用階段獲取已經(jīng)實例化的bean,所以spring項目啟動時十分漫長的.而且在開發(fā)階段使用tomcat的時候還很可能造成啟動失敗的現(xiàn)象,那個時候需要將啟動超時時間設置更長一點即可.spring boot默認搭配的是maven,與傳統(tǒng)maven依賴不同的是spring boot的pom.xml中是肯定會依賴一個spring-boot-parent的parent的,而且就算當前parent不是spring-boot-parent,但是肯定也是有一層的parent是指定parent為springBoot特定的parent,在我寫這篇文章的時候,springboot官方推薦的版本為1.5.9,但是更大一點的里程碑版本2.x也快出來了,而且2.x是基于spring5.x的,其中spring5.x是可以使用spring webflux的,對于喜歡使用異步框架寫網(wǎng)絡相關代碼是非常好的,畢竟reactor是非常好的.在涉及到異步線程模型的時候傳統(tǒng)方式是阻塞式的非常不利于實現(xiàn)實際運行過程中由于延遲造成的一系列問題.springboot唯一的配置文件為application[-xxx].properties/yml,其中yml是基于對象屬性的書寫配置文件的一種新方式,在觀賞性和排列性上是非常高的,當然書寫也是比較麻煩的,還好我使用的是idea工具,有配置提示功能.在標注了@SpringBootApplication的類即為啟動類,這個啟動類起到加載springboot的作用,同時也可以配置通用參數(shù)或者bean,而取決了以往配置在配置xml文件的是@Configuration注解,在標注了該注解的類中書寫標注@Bean的方法返回特定的需要依賴的Bean對象,在這個方法里面一般都是自己手動的new的.Spring boot web

通過這個starter從而可以獲取一系列的依賴,如spring mvc相關,structs2的框架是幾年前項目的標配了,而現(xiàn)在大部分項目都是使用spring mvc了,spring mvc使用@Controller規(guī)定了控制層的入口,類似的為@RestController(這個注解相當于組合@ResponseBody,但是ResponseEntity對象也是不需要@ResponseBody也是可以返回實際數(shù)據(jù)的),同時通過@RequestMapping,或者@GetMapping或者PostMapping等等,標注實際映射的url,這里有一個坑,以往的系統(tǒng)系統(tǒng)動不動就用特殊的請求參數(shù)來分別功能,這在實際使用中一個是不夠直觀,一個是是控制層平白無故多出代碼,另外一個偽靜態(tài)化操作,我們現(xiàn)在普遍使用的是REST風格的url,在返回前端界面時使用返回String類型的數(shù)據(jù),并且保證標注在類上的一定是@Controller而不是@RestController,該方法上一定沒有@ResponseBody注解,return 的數(shù)據(jù)為"[或有或無的文件夾名]模板名稱[或有或無的后綴]",當然這是forward轉(zhuǎn)發(fā)請求的寫法,當需要寫重定向的時候需要在前面加上"redirect:"字符串,其實默認是"forward:",這是省略的寫法.在控制層上我們一般做獲取請求參數(shù),這些參數(shù)有點隱藏的rest里面,使用@PathVariable獲取,隱藏在parameter里面使用@Parameter獲取,隱藏在body里面,使用@RequestBody獲取,還有點可能隱藏在cookie里面,這些參數(shù)的數(shù)據(jù)都是需要控制層去獲取能封裝盡量封裝到對象里面.同時也對于可以直接校驗的對象中的參數(shù)可以使用校驗框架,在形參簽名標注@Valid注解.在控制層一般都是注入業(yè)務層的接口,有些復雜操作通常需要組合多個業(yè)務的功能才能實現(xiàn),當然這是非常司空見慣的,在一個系統(tǒng)中,通常不管如何,控制層的異常是絕對不能向上拋出的,這里涉及到向上傳參的方法,業(yè)務層如何向控制層傳遞參數(shù)呢?一個是返回值、一個是傳入引用值對象、一個是ThreadLocal對象,一個是向上拋出業(yè)務層及其下層的業(yè)務異常,我們通常規(guī)定好業(yè)務層出現(xiàn)異常通常都是向上拋出的,不做任何捕獲,直到控制層的捕獲,通常如果有異常的話最后向調(diào)用者表達出異常的詳細原因,此時一般會單獨寫一個枚舉類、寫一個常量類,當然、如果項目文檔如果足夠強大,程序員足夠細心、開發(fā)周期非常短而沒有時間寫的話,一般我們都是會去寫的,這個常量類其實是一個接口類,因為本來僅僅是只需要放置一些屬性就可以了,而接口類中默認的訪問類型就是public,而且是static修飾的.最后有一個非常重要的概念:aop,面向切面編程,在spring boot中也是基于注解實現(xiàn)的,使用的是@Advice注解,組合@PointCut等注解Spring data jpa

在現(xiàn)如今的面向?qū)ο箝_發(fā)中,提起萬事萬物皆對象,在數(shù)據(jù)庫層開發(fā)中,通常會使用hibernate,而spring data jpa是hibernate的簡化升級版,其特點為標注一個為@Repository,并且這個類需要實現(xiàn)JpaRepository<實體類型,主鍵類型>,這里的實體類在Jpa中也并發(fā)由于是hibernate就要是配置,我們使用@Entity注解標注一個類為類與表映射,使用@Table映射數(shù)據(jù)庫服務器中實際表名,使用@Id標注當前字段為主鍵,同時對于可自增的字段使用@GenereteVlaue標注,而在一些特殊操作,需要標注當前實體類為@DynamicUpdate或者@DynamicCreate,這在使用Timestampt類型的參數(shù)是比較好用,然后我也理解到timestampt是存儲庫,localDateTime是工具類,同時我的項目中使用了Lombok,這個框架可以使用注解為實體類生成getter和setter以及constructor方法.在項目初始開發(fā)階段推薦使用,同時這個需要配置ide,由于我的是idea所以配置還是比較簡單的,安裝插件即可,在實體類上加上@Data注解,對于空參構(gòu)造使用@NoArgsConstructor和@AllConstructor注解.對于實體類中屬性名和數(shù)據(jù)庫中表中列名不一致的問題,一般使用@Columne注解即可.一般主鍵的類型為String或者Long,Long的承載量更小,運算速度更快,拓展性小,可自增,而String加上UUID這種全局唯一之后實現(xiàn)承載量更大,當然對于Long可承載量來說其實也是很大的,其實一般項目使用Long其實也是可以的.Spring Data Jpa默認已經(jīng)提供好了基于直接插入整個對象、修改指定id值的對象、刪除指定Id值的對象、查找所有對象、查找指定id值的對象,同時基于查詢提供了Pageable接口的傳入?yún)?shù),在業(yè)務層可自由組合size和page實現(xiàn)分頁操作,但是有一個bug就是分頁并非那么容易的時候spring data jpa定義的pageable就不是那么容易使用了,反而mysql的limit參數(shù)確實那么的好用,同時也可以指定sort規(guī)則,這些都是簡單的,更加復雜的在于根據(jù)指定條件查找/刪除/修改,然后有些查詢的優(yōu)化在于使用@Query注解實現(xiàn),一些自定義的修改規(guī)則在于使用@Update注解,總體來說spring data jpa的使用是非常簡單的.Spring data mybatis

mybatis作為以執(zhí)行效率為主要的框架,與spring data jpa不同的是,spring data mybatis是基于具體sql語句的.依賴于具體數(shù)據(jù)庫,多個系統(tǒng)之間的dao層代碼無法融合起來,在升級數(shù)據(jù)庫的時候整個系統(tǒng)會有短暫的疲憊期.同時也會出現(xiàn)由于切換數(shù)據(jù)庫導致的數(shù)據(jù)的兼容性問題,在大數(shù)據(jù)量遷移方面也是一個比較麻煩的問題.對于開發(fā)者來說,一部分掌握sql語言能非常流暢的優(yōu)化來自sql語句的執(zhí)行效率的人來說mybatis是極為好用的,但是另外一部分不那么流暢的人來說就為困難了,當然也可以請專門的寫sql語言的dba來寫或者優(yōu)化sql語句.但是比spring data jpa這種對象關系映射的ORM框架不同的是,mybatis的操作多表的效率是非常高的.而jpa的多表會有執(zhí)行的冗雜性,同時jpa的優(yōu)化執(zhí)行語句是非常困難的.雖然jpa的@Query可以直接強制執(zhí)行對象SQL語句.spring data mybatis與直接使用mybatis不同的是,其使用起來也是以注解使用較多,雖然都是使用接口類,但是其盡量使用@Mapper類對dao類進行標注,使用@Insert、@Delete@、@Update+@Param、@Selete+@Reuslts進行crud語句的操作,至于其他的與進行jdbc語句差不多,mybatis其實也只是做了那么兩件事情,結(jié)合書寫的sql語句將參數(shù)設置進去,對查詢結(jié)果數(shù)據(jù)屬性將數(shù)據(jù)取出.通常在對于效率要求很高的項目中都是使用mybatis的,因為對于一個項目來說在現(xiàn)如今每提升一點系統(tǒng)性能對于經(jīng)濟的獲取也是非常大的,另外其實項目中是可以使用兩套持久化技術的.前期使用spring data jpa實現(xiàn),后期切換成mybatis其實也是可以的.Thymeleaf

java網(wǎng)站開發(fā)從剛一開始的將頁面冗雜到servelt中到提出mvc思想后將視圖層單獨出去,其中獲取好處也是非常多的,由于將界面層作為三分之一,這樣的前端可以直接由前端人員進行開發(fā)維護,剛開始的時候使用的是jsp技術,那個的時候的開發(fā)人員并非很多,網(wǎng)站承載量并非特別大,網(wǎng)頁前端業(yè)務也并不復雜,所以導致對性能的要求不是很高,jsp的運行流程為轉(zhuǎn)譯編譯運行,其中消耗的時間內(nèi)在當初是并非很多的,但是對于現(xiàn)在來說這種消耗是很高的,這是導致我們棄用jsp的一個原因,還有一個非常重要的原因就是jsp非常依賴java servlet,這就使得jsp只能作為后端專屬語言了,后來隨著分布的口號,我們逐漸意識到前端渲染的重要性,那個時候我們使用的是Freeemarker網(wǎng)頁靜態(tài)化技術,這在當年還有一些類似的技術,例如:velocity,但是velocity的性能不如freemarker,后來網(wǎng)頁靜態(tài)化技術成了標準技術了,網(wǎng)頁靜態(tài)化技術為將傳入數(shù)據(jù)傳入模板中通過特點標簽將數(shù)據(jù)填充到指定位置最后生成html文件,在一些高并發(fā)訪問的網(wǎng)頁使用這種靜態(tài)化技術遠遠比動態(tài)化技術要好的多,典型代表為:淘寶,當年是什么支持了淘寶在那么用戶沖擊下服務器依然很流暢,一部分是cdn一部分就是靜態(tài)化技術,另外的化就是其獨特的架構(gòu)了,要知道當前國內(nèi)第一家開源RPC框架Dubbo就是阿里的.spring團隊對市場上有先進性的技術都很感興趣.比如struts2/hibernate,這些到現(xiàn)在逐漸變成了spring mvc以及最新基于reactor異步架構(gòu)的spring wbflux和spring data jpa及其系列,甚至可以說freemarker就是thymeleaf的前生,同時spring 自家的spring mvc框架對thymleaf非常支持.同時thmeleaf對于面向?qū)ο笏枷胫С值姆浅5轿?將原本需要冗雜的標簽改為屬性,使得將html文件改為thymeleaf模板文件非常方便.Spring data redis

redis是一個單線程基于內(nèi)存支持分布式部署的服務.通常我們項目中使用redis一個是為了使用其基于內(nèi)存的特點實現(xiàn)緩存,另一個是使用其單線程及其執(zhí)行指令強原子性的特點實現(xiàn)并發(fā)鎖機制.在項目中很多地方都會使用緩存,一個是用戶登錄信息token存入redis,而這在以往稱之為單點登錄.另外為業(yè)務數(shù)據(jù)緩存,如果是自己使用StringRedisTemplate實現(xiàn)緩存操作,那么這個業(yè)務的代碼量又會平白增加很多了,在spring boot2.x中,我們通常是使用@Cache注解實現(xiàn)對緩存的操作,這個注解包含了獲取緩存,清除緩存,修改緩存(當觸發(fā)某種條件時),這種注解需要標注在方法名上,對于不同的方法實現(xiàn)不同的操作.其實redis一個更加重要的作用是作為并發(fā)鎖,通常的秒殺操作都是能夠使用這種并發(fā)鎖達到單機程序鎖所達不到的效率,因為這種鎖是不會阻塞本地線程的.實現(xiàn)原理是因為一次向redis請求的指令為一組同時存取的原子操作,一次只能有一個操作成功,同時通常會在存數(shù)據(jù)的時候會設置過期時間,而取出數(shù)據(jù)時通常會使用時間戳做鎖,將本機時間作為鎖.而解鎖的過程為將指定key的value移除掉.Spring data ElasticSearch

在項目集成了搜索引擎之后,傳統(tǒng)操作索引庫是比較復雜的,但是功能最為完善,但是其實有些時候并不是需要那么完善的功能的,比如說高亮操作,這個時候我們通常是為了簡化操作而封裝一個通用方法,其實現(xiàn)在spring data 系列已經(jīng)對es有了這種操作的支持了,使用spring data elasticsearch 可以非常簡單的實現(xiàn)對索引庫的CRUD操作,但是首先你需要定義一個文檔類,使用@Document("文檔名稱,通常類名也行"), 寫一個接口類實現(xiàn)ElasticSearchRepository<文檔庫類,類中主鍵類型>.其使用方式與spring data jpa一致.Logback

對于一個項目來說,日志是非常重要的,日志常用來分析程序漏洞、性能瓶頸、實際調(diào)用頻率,同時對于自動化測試來說,沒有日志就幾乎是等于白測試了,因為有時候就算是自動化測試工具通過了,但是在實際運行過程中還是會遇到一些奇怪現(xiàn)象導致產(chǎn)生奇怪的數(shù)據(jù),比如說就算是AssertNotNull(data)通過了,但是不代表這個data就是合理的了.現(xiàn)在可用的日志框架很多,比如說Log4j、Log4j2等等,它們都實現(xiàn)了同樣的一些功能:以后臺方式將運行時期的由開發(fā)人調(diào)制的數(shù)據(jù)和上下文信息通過靈活簡便的配置(如日志輸出格式、日志輸出位置等等)實現(xiàn)非常高效的輸出.但是log4j2由于過于先進,一些框架都還未支持,所以我們選擇使用Logback框架,其實日志還有一個比較重要的作用是mybatis默認情況下不會輸出執(zhí)行語句,而是需要將mapper下的日志級別設置到dubug或者trace級別.Swagger2

對一個web項目來說,接口文檔是非常重要的.以前也有接口文檔,但是以前的文檔時有專門的維護人員或者開發(fā)人員去書寫的,只是作為有哪些對外接口的文字描述,測試的時候需要測試人員再次復制黏貼Url并填入復雜的請求參數(shù),同時這種測試是低效率的,對于多個復雜接口一起組合使用,是很實現(xiàn)的.多模塊或者多子系統(tǒng)并行開發(fā)時,這種文檔還影響著項目開發(fā)的進度,因為系統(tǒng)直接會有其他系統(tǒng)功能的依賴,swagger2打破了這一僵局,swagger2會掃描項目中所有加了@Controller或者@RestController的類,將這些類的映射路徑分別收集起來在請求swagger暴露的REST API界面時會將這些映射路徑分別隱藏在各自的Controller類中,同時可以手動指定Controller類的名稱和方法名稱以及請求參數(shù)聲明.如果點進去會進入一個具體的請求url中,swagger會展示URL調(diào)用時需要傳入哪些參數(shù),哪些是必須的,參數(shù)的基本類型,如果再點擊"Try it out",會直接調(diào)用這個rest 的url,同時由于這個界面都是折疊效果做的,所以不必擔心當前測試沒有做完就去做下面或者上面的其他而導致丟失參數(shù).總結(jié)來說:swagger的使用比較簡單、而且測試非常方便Apache ab

對于一個微服務的項目來說,如果你不測試它的并發(fā)量、容載量,那跟單體工程還有不同?Apache ab是一個命令行的可以測試并發(fā)效果的工具.至于使用是很簡單的.ActiveMQ/Kafka

對于一個中大型項目來說,任何的直接操作數(shù)據(jù)都有可能有未知原因?qū)е虏僮魇?對于一些模塊或者叫做系統(tǒng)來說,有些數(shù)據(jù)是不能丟失的,比如說訂單系統(tǒng),支付系統(tǒng).分布式的項目常遇到的數(shù)據(jù)一致性問題都可以使用消息隊列來解決.消息隊列有AMQP和JMS兩類,主流常見的消息隊列服務有  ActiveMQ/RabbitMQ/Kafka,其性能大致都差不多,但是ActiveMQ不支持集群,如果需要集群的話需要借助Zookeeper.RabbitMQ天生支持分布式,Kafka在大數(shù)據(jù)生產(chǎn)環(huán)境中經(jīng)常用到,所以在對于消息隊列的話,功能最強的是Kafka,使用最簡單的為ActiveMQ,同時由于spring整合的非常好,在使用Spring Kafka或者Spring Boot ActiveMQ,接受消息一般都是將一個方法上加上@XXXListener注解,在spring kafka中,傳入?yún)?shù)為具體需求,返回參數(shù)的類型為Void,而在@XXXListener上需要標明id,topic等信息.而在發(fā)送消息使用@SendTo注解,并在注解中聲明發(fā)送到的topic,topic中可以使用EL表達式從配置文件中獲取話題名稱.Spring boot websocket

socket意思為套接字,一般用來維持長連接,使用長連接一般可以用作在線聊天,在spring boot框架下,有jetty/tomcat/undertow三種,如果是使用tomcat的話,由于已經(jīng)內(nèi)置了spring-boot-starter-tomcat所以不需要再次依賴,但是如果是使用的是jetty,那還需要spring-boot-starter-jetty.在使用中需要依賴spring-boot-starter-websocket并且清除掉spring-boot-starter-tomcat,寫一個類繼承TextWebSocket.重寫handleTextMessage(處理消息)、afterConnectionEstablished(當消息處理之后)、afterConnectionClosed(連接關閉之后)、HandleTransportError(傳輸異常)方法,發(fā)送數(shù)據(jù)使用的是session的sendMessage方法,接受消息用的是TextMessage.Docker

容器技術,安裝一個mysql對于docker來說,僅僅只是查看一下文檔,在dockerhub.com中查找mysql相關鏡像,理解文檔之后,按照他的pull指令在已經(jīng)安裝了docker的服務器中運行即可得到鏡像,我一般都是用記事本將啟動鏡像需要的參數(shù)組織起來,在覺得OK之后再復制黏貼到SSH工具,如secureCRT軟件,在鏡像運行之后我一般會使用docker ps -a去查看容器運行情況,有點時候即使是當時啟動成功了,后面也不一定能啟動起來,當發(fā)現(xiàn)描述為EXIT時我都會查看一下啟動參數(shù)和配置,而當運行一段時間之后為UP之后,這樣的容器才有可能是認為是啟動成功了.對于如何查看容器的基礎信息,使用docker inspect.然后就是停止容器運行:docker stop 容器id,刪除容器:docker rm 容器id,刪除鏡像而為本地文件系統(tǒng)騰出空間:docker rmi 鏡像id,而對于如何查看容器id使用docker ps -a ,查看鏡像id使用docker images.一個常見問題是容器內(nèi)部時區(qū)問題,通??梢允褂?e參數(shù)指定時區(qū).另一個常見問題是docker中心庫拉去鏡像速度過慢問題,通常是需要配置加速器的,一般的加速器都很貴,但是阿里云有一個加速器速度非??於颐赓M.進入容器中使用docker exec -it 容器id /bin/bash.功能

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6fDgKvyY-1577344034026)(C:\Users\tanSh\Desktop\需求驅(qū)動響應的商城平臺\資源\代優(yōu)匯商城功能設計圖4.png)]
賣家能夠增加商品,修改商品(包括商品下架),刪除商品,查找指定商品,搜索商品,查找所有商品并分頁顯示

買家能夠根據(jù)商品的特征進行搜索商品,比如說紅色手機,特征為紅色和手機.

買家能夠進行活動中的秒殺商品操作

平臺會根據(jù)商品實際分類將商品進行分類顯示給賣家,分類是一種多層次關系,比如說智能家電、床上用品

買家能夠查看商品詳情并且能夠?qū)⒃撋唐芳尤?amp;amp;#34;收藏"/"到貨通知"/"購物車"/"訂單"

買家能夠?qū)ξ粗Ц队唵沃Ц?或者在下訂單的時候進行付款,買家能夠使用支付寶或者微信支付,在App中用戶能夠提示打開微信或者支付寶進行支付,而在網(wǎng)頁中,會跳轉(zhuǎn)到支付寶或者非微信的支付界面,支付成功即為下單成功

賣家會能夠及時的得到買家下的訂單,這里我們使用websocket長連接,并及時進行發(fā)貨等操作,并且能夠選擇物流的公司,并且在物流公司確認發(fā)貨之后會告訴賣家開始發(fā)貨,買家會通知買家已經(jīng)開始發(fā)貨了

買家能夠支付關注到物流情況,這里我們集成了物流公司的實現(xiàn)查詢接口API

有反饋系統(tǒng),買家和賣家都可以直接向系統(tǒng)提出意見和建議

**------------------------>如果只有上面的功能,那么這個項目將是毫無意義的--------------->下面的才是開始:**

    隨著社會的高速發(fā)展,生產(chǎn)力已經(jīng)超過了過去十年的總和,IT時代的到來,我們漸漸意識到經(jīng)濟發(fā)展的規(guī)律,不管是淘寶還是京東,其核心功能為為生產(chǎn)力分配價值、加速流通,十年前淘寶是如此,今天還是如此,十年前人們覺得淘寶是多余的,覺得線下商店就夠了,但是從第一座城市建立開始到現(xiàn)在,沒有哪一家商店能夠站在城市的角度思考生產(chǎn)力的分配,淘寶做到了,哪怕是十座城市的人口流量還是一百座都是同一個入口,同一家商城,淘寶利用其分層的思想將適合的商品送到合適的人手中,對外部看來淘寶就像是一個巨型的商店,甚至比線下商店更加專業(yè),因為他的數(shù)據(jù)是統(tǒng)一的,用戶需要看到商品、用戶需要拿到商品、用戶需要付款、用戶需要退貨等等.淘寶真的很牛逼,如果管理一個市中心的商店是有難度的話,中國那么多的線上商店的管理那將是指數(shù)級別難度的增長.十多年前淘寶以商家進入線上出售商品、物流公司將商品發(fā)送為驅(qū)動,利用互聯(lián)網(wǎng)流通快、消耗小、入口統(tǒng)一的特點在中國消費者市場站穩(wěn),淘寶的盈利模式為商家管理費用,至于費用細節(jié)這里就不細談了.

    漸漸的,買家覺得購買的東西不夠好,淘寶推出了已購買者的評價功能,淘寶平臺以為這樣就可以有效抑制差貨現(xiàn)象,其實不然,在推出這個功能之后沒過多久,大規(guī)模的刷單浪潮掀起,一單刷單,評論的質(zhì)量就無法保障,一單這個的質(zhì)量無法保障,買家在購買東西的時候?qū)⑹菦]有任何的可信性,刷單的流程一般為互聯(lián)網(wǎng)中隨意的一名買家在購買這件商品之后發(fā)布好評,商家不發(fā)貨或者接受退貨,刷手不收貨或者退貨,這樣的虛假交易帶來的好評對其他消費者是一種誤導甚至是坑騙,至于刷手的利益是什么?是來自商家額外的獎勵,在退還本金之后額外一些小費,由于網(wǎng)絡交易幾乎不存在阻塞性,刷手很可能就是靠這種方便一天為幾百家商店刷單.其實這不能怪刷手,這是平臺的漏洞導致的.再看用戶購買的操作,我相信很多剛開始用淘寶的買家可能會有同一種情況,由于新鮮感會抑制不住想買點新鮮東西,其實實際并非實用的東西,在經(jīng)濟繁榮時期這是正常的,后來才開始后悔,特別是結(jié)合花唄之后導致的迅速購買帶來的償還期,對于平臺來說這并沒有什么,甚至是越多購買記錄越好,但是這也是我為了改進這種而想做這個項目的一個原因.

    有人說,淘寶上的二手商店是不是太多了?確實是很多,因為平臺對于這種二手并不感覺有什么疑問,因為對于他來說,越多的商家越好,但是對于整個交易過程中來說,每多一個二手商店,買家的付出價值越加沉重,每多一個二手商店,在買家的付出價值不變的情況下,質(zhì)量更加低下,其實我曾經(jīng)一度在想如何消滅二手商店,在我想到答案之后,我又陷入了如何去驗證這個答案的艱難境地,直到共享單車的出現(xiàn),經(jīng)過這樣的驗證我明白了我的答案是對的.

    在商品繁雜的今天,如何在一個已知的已經(jīng)是很詳細的列表里面找到最適合自己的.在過去,淘寶是沒有這件事情,僅僅是展示一個商品列表又是有什么用呢?后來淘寶推出了個性推薦、同類歷史記錄推薦,當然這是在結(jié)合大數(shù)據(jù)和人工智能分析之后的成果,其中如何去獲取數(shù)據(jù),一個是歷史記錄數(shù)據(jù),如果你瀏覽了或者搜索了某一跨商品,我堅信在能夠推薦的地方,淘寶都會推薦相關商品給你,一個相同行為軌跡的推薦,如果你購買了手機,恨與可能推薦其他眾多用戶在購買手機之后再次購買的充電寶給你,其實很多都有數(shù)據(jù),只不多淘寶僅僅是一個交易平臺,甚至是如果我想買一個東西我都無法找到相關功能去與我交流,交流的意思為買家不斷輸出數(shù)據(jù),平臺捕獲數(shù)據(jù)并分析得到商品特征,而淘寶有的僅僅是一個搜索功能,當買家知道要買個什么東西的時候需要搜索干嘛?不知道要買個什么東西的時候如何搜索?搜索得到的眾多商品怎么去選擇最適合自己的.

    關于假貨問題,也就是商品描述與實際商品不符合.甚至是很多東西都是買了很長時間之后才知道這個商品是否有質(zhì)量問題.如何去區(qū)分呢?靠買家評價,完全靠不住的.靠平臺打分?那也只是個數(shù)據(jù),其實就我來說,最靠得住的是生產(chǎn)鏈,這是我前面畫那張圖中明確強調(diào)的部分.只有完全真實透明的生產(chǎn)鏈才能保證商品的質(zhì)量.對于工程來說質(zhì)量=測試,但是在實際實際中,很多東西都沒有那么簡單.只有靠消滅二手,公開生產(chǎn)鏈.然后我發(fā)現(xiàn)淘寶和實際生產(chǎn)廠家是分開的.所以要連接起來其中必定要多加上一個二手.所以我們的平臺必須要講生產(chǎn)廠家搬到線上,但是真實情況是很多廠家都是只是生產(chǎn)一個部分的商品,難道對于一個買家來說就是只買一個部件嗎?例如我要買手機,難道只是買一個高通的處理器嗎?所以針對這一點,里面還有一個轉(zhuǎn)折點,部件也是商品,但是不是給普遍的消費者買的,而是給需要這種部件的買家買的,我們將所有的買家抽象成需求者,需求者有不用的身份,需求者在需求商品的時候可以指明自己的身份,也可以使用存留在平臺的身份.過去的ERP只是作為企業(yè)內(nèi)部的管理,企業(yè)外部即企業(yè)與企業(yè)之間的聯(lián)系幾乎還是原來的模式,企業(yè)的選擇依然是人工的,不過有些大企業(yè)會有依賴資源分析系統(tǒng),對,這也是我們要做的,這一點與普通消費者的購買心理一致,所以抽象起來,幾乎所有的需求者都是同一種的需求心理,當然普通人的需求心理我們可以分析出來,因為有足夠多的數(shù)據(jù),企業(yè)就不一定了,對此也只是將數(shù)據(jù)排行展示而已.企業(yè)在生產(chǎn)過程中有內(nèi)部依賴需求即自己a部門生產(chǎn)的東西會被b部門依賴,也有外部依賴需求即a公司會依賴b公司的技術、商品等等,在我感覺的理想狀態(tài)是,同一種企業(yè)應該將下層生產(chǎn)力融合起來,對于技術應該在充分實踐之后讓落后公司學習更加先進公司的技術,這就存在著一個肯學、一個肯教的問題了,至于下層生產(chǎn)力融合起來可以理解為公司將自己的處于生產(chǎn)層員工向這樣的處于同一生產(chǎn)類型的人力資源池填充,當需要多少資源時向資源池中獲取多少資源,當多了就填充,少了就向其他公司平臺管理或者各公司聯(lián)合管理申請,如果這樣做了,整個行業(yè)就容易把握了,員工不再有公司限制,有的只是屬于自己實際經(jīng)驗的充分發(fā)揮.更容易的對社會進行管理.在這樣的模型下生產(chǎn)力將大幅度提升.

    其實交易從古至今一直由三部分構(gòu)成,需求者,響應者,價值,平臺其實也是只需要根據(jù)這三個抽象對象展開業(yè)務即可,傳統(tǒng)的有囤貨開店直銷、現(xiàn)代的有基于商家管理然后由商家自己管理顧客.對于需求者來說,獲取自身相關的需要的商品,平臺能更加理解需求者想要的東西,能向需求者推薦意想不到的商品,需求者能夠花更少的錢而獲取更好的貨,需求者收到的貨物有更好的質(zhì)量,而對于響應者來說,能夠?qū)⒆约旱呢浳锼偷较胍降男枨笳呤种?,當市場更好的時候能夠更容易擴大自己的生產(chǎn)力,能夠簡化生產(chǎn)模型并和互聯(lián)網(wǎng)融合,能向經(jīng)營或者技術更好的同類響應者學習,能夠免費使用商用ERP并隨著時代前進而前進即有人能夠?qū)⒎腔ヂ?lián)網(wǎng)的響應者持續(xù)的帶入互聯(lián)網(wǎng)并不需要錢.而對于價值來說,能夠有永久的記錄保存(就像區(qū)塊鏈)、能夠迅速的流通并發(fā)揮到需要的地方(小額貸),能夠不受社會的動蕩抑制而是由商品的消耗價值決定,所有的需求都能直接用某一種價值進行衡量而不受限.

    如何認為是需響成功?需求者從瀏覽商品然后下單、平臺分析推送,當需求者付出響應價值、平臺保存價值、響應價值分發(fā)響應者、響應者發(fā)出商品,需求者確認響應成功,對于剩余價值,響應者回購已售商品殘余價值,需求者出售已購商品殘余價值。

    需求者在當前平臺與其他平臺的區(qū)別?需求者直接發(fā)布+需求者對話提煉,需求者行為軌跡,在響應庫中主流需求與需求者吻合,其他需求者推薦.需求者直接發(fā)布可以理解為搜索功能或者向需求庫中添加一條需求,響應者會在收到來自平臺與之匹配的需求記錄,需求者對話提煉,會使用人工智能中的人機對象,然后從對話中提取出所需商品的特征,然后當需求者認為描述清楚之后向需求者展示匹配的商品列表.需求者行為軌跡可以理解為根據(jù)用戶歷史購買物品推斷出還將會購買的東西,這是屬于大數(shù)據(jù)分析或者人工智能分析的實現(xiàn)技術,當需求者符合某一系列特征后會將屬于這一特征的一些更加符合需求者實際情況的東西推薦給需求者.朋友的直接推薦.

    響應者在當前平臺與其他平臺的區(qū)別?響應者可以直接發(fā)布商品,能夠免費使用統(tǒng)一的ERP系統(tǒng),能夠從友站鏈入,響應者可以作為一個成熟商品的一部分部件進行發(fā)布商品,這樣的部件可以理解為商品,而且當前公司很有可能會依賴其他公司的部件的商品.之所以只用統(tǒng)一的ERP系統(tǒng),一個是為了將這些企業(yè)聯(lián)合起來,一個是為了整合數(shù)據(jù)時更容易.還有很多功能以后再補充.實現(xiàn)

在這個項目初期分為3個系統(tǒng)1個輔助服務進行開發(fā),分別是了需求者系統(tǒng)、響應者系統(tǒng)、服務網(wǎng)關、注冊中心,在需求者系統(tǒng)上實現(xiàn)了買家系統(tǒng)、需求分析系統(tǒng),買家系統(tǒng)中能夠進行常規(guī)的用戶登錄、注冊、修改密碼、忘記密碼、修改用戶信息、人臉識別登錄功能,需求分析系統(tǒng)中有人機對話功能、需求記錄、支付寶和微信支付功能、關于文件管理使用了阿里云的OSS服務.響應者系統(tǒng)中有響應者登錄、注冊、修改密碼、忘記密碼、修改用戶信息、還有商品管理模塊,關于商品模塊支持響應者進行div操作,實際上也是字符串替換而已,訂單管理系統(tǒng),物流管理系統(tǒng)、支持從淘寶或者京東直接導入商品,能夠加入生產(chǎn)鏈作為完整商品中的一個模塊,能夠發(fā)起生產(chǎn)鏈,支持免費使用統(tǒng)一抽象的ERP(企業(yè)資源管理)+OA(辦公自動化)+EMS(制造執(zhí)行)系統(tǒng).針對發(fā)布商品或者生產(chǎn)鏈有智能檢測模塊保證平臺合法經(jīng)營.

對于項目中的注冊用戶功能,我們使用了阿里云的短信接口服務,當用戶注冊時需要先請求專門的發(fā)送短信的接口,此接口內(nèi)實現(xiàn)較為簡單,無dao層操作,無需涉及到數(shù)據(jù)庫的操作,但是需要集成阿里云短信java版的maven依賴(官網(wǎng)提示沒有依賴而是需要自己在自己的私有庫上去安裝),在封裝了簡單的發(fā)送短信的工具類后,使用發(fā)送短信是非常簡單的,在開始集成阿里云短信接口服務時,需要申請短信模塊和短信簽名,這兩個申請還是很簡單的.將參數(shù)配置進去后,將固定參數(shù)配置到application.yml中,當然也可以使用application.properties,對于這兩者的區(qū)別在于yml更加面向?qū)ο?在ide工具中,如idea中修改時很簡單的,但是在記事本或者notepad++中就不容易了.其實影響也不大.還是推薦使用application.yml.在需要使用的方式使用@Value("${xxx}")注解進行注入.如果用戶是使用了正確的手機號碼進行注冊,當然我們后臺也會進行基于正則表達式的檢查傳入的手機號碼.用戶手機會在1-2分鐘內(nèi)受到短信通知,而對于短信丟失率,官網(wǎng)給出的數(shù)據(jù)是99%.再調(diào)用短信接口時,我會先生成0-9的6位數(shù)字的隨機值,然后將此值放入redis中,因為項目中使用的是spring boot框架,所以集成一個spring data reids還會很簡單的.而通過在業(yè)務層使用@Autowired StringRedisTemplate stringRedisTemplate; 注入redis操作對象,而通過這個對象可以將手機號碼和0-9的6為隨機數(shù)字放入redis中。當然在實際項目中是這樣做的,聲明一個業(yè)務常量接口類,在里面聲明一個常量,因為interface類里面所以的屬性都是public static final 修飾的,所以可以使得更加貼合實際.我會聲明一個redis中直接存放的string的key的前綴,例如為'requester_regist_';然后后面再直接拼接上手機號碼,這樣就是直接是'requester_regist_123456',通過添加到redis并設置過期時間,過期時間默認為30分鐘.當用戶來注冊的時候回攜帶手機號碼,這個時候需要校驗是否有效,還是需要注冊redis操作對象并調(diào)用取數(shù)據(jù)的方法,從常量類中取出注冊前綴以及傳入的手機號碼,如果取出的值不為空并且與傳入的verificationCode一致,則給與注冊.同時對于賬號名是否有效會進行校驗,比如說是否與正則表達式符合,同時還會校驗用戶名是否已經(jīng)存在,如果存在則不給予注冊.在返回數(shù)據(jù)對象會封裝一個抽象響應對象.需要封裝一些必須的屬性,例如:響應嗎、數(shù)據(jù)(類型為泛型T,以為不管是返回單個pojo對象還是page對象還是list對象都是可行的)、消息內(nèi)容,通常還會聲明一個用戶注冊的枚舉類,該類中必須設置int code和stirng msg,對于這樣封裝,雖然是增加了代碼量,但是很好維護,代碼格式很優(yōu)美.就此客戶端,不管是pc的html還是手機app都是可以通過判斷code表示是否注冊成功.對于數(shù)據(jù)校驗成功之后就可以開始寫入數(shù)據(jù)庫了,本項目中使用的是mysql,并且將mysql是通過docker進項安裝了,在啟動時固定了映射端口為3306,其實個人感覺最好不要隨機映射端口或者ip,原因也是很簡單的,因為下次啟動的時候服務的訪問地址都改變了,對于項目來說就是災難性的了,同時在啟動容器時指定數(shù)據(jù)卷,以便數(shù)據(jù)備份導出以及持續(xù)使用.同時對于mysql鏡像一個bug就是時區(qū)問題,這是我在使用timestamp類型的列才發(fā)現(xiàn)的,通過查資料才發(fā)現(xiàn)是容器內(nèi)部時區(qū)問題,我隨即登錄宿主機使用date指令查看了宿主機時間及時區(qū),同時通過docker exec -it 容器id /bin/bash 指令進入了容器內(nèi)部,在同樣使用了date指定之后發(fā)現(xiàn)時區(qū)果然不對,相差8個小時,隨機我再次查閱官方文檔,解決方法有兩種,一種是掛載宿主機時區(qū)文件,一個是同時-e攜帶參數(shù)指定容器時區(qū).至此最終解決問題.在項目中使用的是spring data jpa,spring data系列框架都是很容易被開發(fā)人員接受的,spring data jpa 是基于hibernate 實現(xiàn)的,在拋棄了hibernte冗雜的配置文件.并基于接口類實現(xiàn)基于的crud,同時提供了高級查詢對象,在spring data jpa中,表與類的映射關系只是幾個注解接口解決.@Entity,@Table@Column@Id@GenerateValue,在接口層,異常都是需要寫一堆代碼,同時對于分頁操作也是不夠簡潔,jpa 中只是需要聲明一個接口類繼承JpaRepository<實體類類型,主鍵類型>,在實際的多條數(shù)據(jù)查詢中使用pageable對象,封住了size和page和sort對象,分頁查詢時同時指定page第幾頁,size一頁多少條,sort:以哪些字段排序以什么屬性排序.通常注冊只需要返回id即可.同時既然是注冊,密碼的安全性也是非常高的.使用3倍md5并且加鹽實現(xiàn)了加密明文操作,同時將加密方法封裝起來,因為當用戶使用明文密碼登錄是還是需要使用該加密類實現(xiàn)加密再比對才能校驗是否密碼正確.

對于項目中最基礎的登錄功能,我們實現(xiàn)的是SSO,英文名為single sign on,稱為單點登錄.當用戶首次完整登錄成功,業(yè)務層會生成全局唯一的字符串,而這個操作使用uuid即可完成,在java中生成一個UUID值是非常簡單的,使用UUID類調(diào)用randomUUID即可返回一個32+4位的字符串,同時將該字符串中所有的'-'替換為''即可.將此字符串即token(令牌)存入redis中,至于key,還是可以像前面一樣在接口類中聲明前綴,例如"requester_login_",然后再加上用戶的id,因為登錄方式可以有多種,但是id確實唯一的.同時在業(yè)務層注入redis操作類,同時調(diào)用設置值的方法將key和token存入redis中并設置默認過期時間為2個小時.因為spring data redis的stringRedsiTemplate.opsForValue的存值方法支持指定時間單位,所以可以不需要講毫秒值換算為2小時,而是2,TimeUnit.Hour即可。對于pc的html/html5可以直接通過session對象操作cookie對象即可,而對于像手機app這種,可以將token直接作為返回參數(shù)返回,html5的本地存儲,安卓的sqlite這些都是可行的存儲方案.在下一次請求登錄時,如果對于該賬號的token有效不為空,并且與傳入的token一致,即可認為是sso登錄,在多平臺的時代,sso登錄有著重要意義.

對于項目中的修改密碼,首先要確保用戶現(xiàn)在是登錄狀態(tài),然后與注冊用戶差不多,但是在使用spring data jpa進行修改操作時需要使用@Update注解標注修改,同時在@Query("sql語句")使用ddl語句進行修改指定密碼類的值.

對于項目中的忘記密碼,實現(xiàn)與注冊有公共之處,即為忘記密碼需要驗證手機驗證碼.然后與修改密碼類似

修改用戶信息與修改密碼類似

關于項目中的人臉識別功能的實現(xiàn),由于大數(shù)據(jù)耗費資源較重,所以對于一些市場上已經(jīng)有的第三方云服務,這里就直接集成了,比如說人臉識別,在剛開始集成的時候這個東西應該很難,實際上很容易,因為我在阿里云上有長時間的時間經(jīng)歷,所以我剛開始的時候是選擇阿里云的人臉識別服務,阿里云的人臉識別是基于兩個圖片的比對的,對于像當前這樣的系統(tǒng)來說,我直接拋棄了,因為上傳兩張圖片文件的代價是比較大的,雖然也可以改進為一張從客戶端上傳,其他的從OSS對象文件存儲中使用內(nèi)網(wǎng)進行傳輸,但是由于實現(xiàn)起來確實很麻煩,后來我找了一些的服務商,都沒有符合我的業(yè)務,直到碰到百度云的人臉識別,百度云的人臉識別從一開始就是瞄準的團體型,幾個核心的接口分別為:上傳用戶圖片到用戶組中,從用戶組中比對傳入圖片,從圖片組中刪除指定用戶圖片,所以事情就簡單了,在用戶開啟人臉識別并至少上傳了一張圖片,登錄時只需要打開攝像頭,拍攝一張圖片并調(diào)用接口到服務器,然后調(diào)用從用戶組中比對用戶的接口將圖片.返回結(jié)果為一系列的比對結(jié)果數(shù)組,同時可以指定返回的結(jié)果數(shù)組的大小,但是也有默認值,返回的第一條數(shù)據(jù)為相似度最高的,可以獲取之前上傳用戶圖片時額外指定的用戶id字符串,判斷相似度是否高于85,如果高于85數(shù)據(jù)即為合理,重新刷新token,實現(xiàn)與用戶登錄類似.

關于項目中的需求記錄,當用戶搜索時將搜索值提取分析保存到需求記錄表中,平臺會使用hadoop平臺定時每一天8點到9點分析所有的搜索記錄表,將數(shù)據(jù)提取到hdfs文件系統(tǒng)中,通過對標簽的匹配,將一部分需求記錄發(fā)送給響應者的查詢接口.因為這個對實時性和效率并不是要求特別高,所以是hadoop是極好的,因為在云服務器中硬盤的性價比比內(nèi)存的性價比低的多.
關于項目中的文件管理使用了阿里云的OSS服務,因為普通文件系統(tǒng)有著帶寬抑制、性價比更低、影響服務器性能、擴容復雜,在思考之后決定使用OSS 對象存儲服務,OSS還支持CDN加速,影音文件讀取加速等特點,但是這也有一個缺點,文件刪除策略過于死板,文件刪除標準應該為文件與項目無關聯(lián),實現(xiàn)這個并不復雜,甚至是很簡單,但是涉及到安全問題其實阿里云OSS也是不容易做的,所以我們可以自己做,寫一個數(shù)據(jù)庫文件列的管理模塊,能夠在輸入連接數(shù)據(jù)庫的參數(shù):Url、數(shù)據(jù)庫類型、用戶名、密碼后連接實際數(shù)據(jù)庫得到所有表,管理人員在通過驗證后展開表,勾選字段,在勾選了所有的有文件名稱引用的表的字段后,將這些數(shù)據(jù)上傳,這樣我們就可以得到所有需要提取數(shù)據(jù)的位置了,這里我并不是使用的spring data jpa而是jdbc,因為這個屬于過于靈活的操作,jpa做不到,在得到這些表及其字段名后,將這些數(shù)據(jù)存入記錄表中,方便管理,使用quat    Z實現(xiàn)定時服務,當開始調(diào)用分析功能時,我一個是需要將所有的數(shù)據(jù)從哪些列中查出,一個是要講oss文件中當前項目的bucket中的所有的文件名稱獲取出來,這里的數(shù)據(jù)量的級別已經(jīng)達到了大數(shù)據(jù)的范疇了,獲取數(shù)據(jù)之后的處理很簡單就是將sso文件庫中的文件名逐個與數(shù)據(jù)庫中的列中的文件名進行比較,如果發(fā)現(xiàn)sso文件庫中的文件名不存在于mysql數(shù)據(jù)庫中的指定列名中,那么這個文件就是可以刪除掉的,但是具體實現(xiàn)我才發(fā)現(xiàn)并不是那么理想,在上傳數(shù)據(jù)時會有干擾因素,因此,我想出了將上傳數(shù)據(jù)庫中的文件名的操作分為3個操作,一個聲明開始上傳,一個多次上傳數(shù)據(jù),最后聲明確認上傳接受、甚至需要管理員輸入手機驗證碼.當然在刪除操作進行前會進行備份操作.這個功能的系統(tǒng)容載量可以很容易擴容。
-----------------------------




歡迎光臨 愛鋒貝 (http://m.7gfy2te7.cn/) Powered by Discuz! X3.4