Go語言在掃碼支付系統中的成功實踐

今天的內容主要分四個方面。第一,金融支付系統的一些特點;第二,我們的掃碼支付系統技術選型;第三,系統迭代過程中的架構演進;第四,與Go相關的一些坑。

金融支付系統的一些特點

Go語言在掃碼支付系統中的成功實踐
圖 1

首先從業務流程入手,其實非常簡單。一位消費者結賬時,假如選擇掃碼支付的方式付款 100 元,產生一筆交易信息。如圖 1 所示,我們看上面藍色的線條,通過商家的收款產品,把這 100 元的交易信息送到我們的掃碼支付系統,然后傳遞到后面的微信、支付寶或者其他支持掃碼支付的相應錢包,完成這筆交易信息的傳遞,完成這筆交易處理。

在行業內,通常稱藍色的線條為信息流。信息流是什么意思?就是傳遞這筆交易的信息。接下來, 完成 信息傳遞還沒有結束,看圖中灰色的線條,通常在第二天的時候,即 T+1 時,我們會通過商家的清算銀行把這 100 元清到商戶的清算賬戶,這樣才算完成了這筆資金的清算,因此我們稱下面的灰色線條為資金流。很簡單,我們今天更關注的是上面信息流相關的處理。

接下來,我們看一下信息流相關處理。除了我剛剛提到的,實時交易處理 100 元的信息傳遞外,還會涉及到哪些方面呢?一個是實時交易的服務,另外一個是商戶對賬的服務。剛剛提到資金流的傳遞是商家收到 100 元,那么收到的金額對不對,和前一天交易行為是不是匹配呢?商家需要一些對賬報表,來核對相應交易行為、到賬資金,這就是對賬服務。

另外,其他的一些商戶服務,包括一些商戶信息的維護,商戶交易行為的查詢,交易記錄的查詢方面,最基本來說是這三類的服務。另外,可能會有更多附加的服務,包括風控,以及其他的一些增值營銷服務等。

今天,我們聚焦在這三類基本服務,看看三類基本服務對應的后臺系統的類型是什么樣子。

首先是實時交易服務:API Gateway。回到剛剛 100 元的處理,從商家收款產品,到我們掃碼交易的處理系統,接口過來以后,在系統中進行一些相應的業務邏輯處理,交易信息落地,之后把交易信息分發到后面相應的接口。整個流程,實際上無非就是接口的轉換,中間攙雜一些相應的業務處理。跟我們微服務架構上的 API Gateway 的定位其實非常類似,可以理解為它就是一個加入了一些業務邏輯的 API Gateway 系統。從商家對賬服務來說,通常是在交易發生的第二天進行資金流的流轉,與之同步的會有相應的對賬報表要給到商家,為商家提供對賬服務。通常來說,對賬服務會涉及到批處理相應系統。商戶服務剛才提到的查詢、信息維護等,這些可能是相應的 web portal 提供相應的商戶服務。

從業務角度出發 , 對我們的系統有什么基本的要求?

第一,既然是支付系統,安全性肯定是再怎么強調也不為過的;

第二,穩定性也是一個必不可少要考慮的關鍵點。包括我們的商家可能會有各種類型的客戶,包括餐館可能白天營業,夜店可能半夜也會有交易發生。整個系統 7*24 小時的穩定性,也是需要考慮的重點;

第三,我們系統的吞吐量,這個就很好理解了,當前面的客戶、商家交易量上來的時候,整個系統包括并發處理能力,請求的響應時間等,都是業務上非常關注的重點。

回到最開始提到的問題,我們用 Golang 來搭建支付處理系統,靠不靠譜。 在我理解就是這三方面的考量:安全性有沒有保證,穩定性是不是足夠穩定,吞吐量是不是能夠達到業務的要求。接下來看看到底能還是不能,進入技術選型話題。

技術選型

從技術選型來說,剛才提到的三個方面,主要是業務需求方面的考量。業務需求方面,在 2015 年, 我們 搭建這套系統的時候,還有另一點非常重要的考量。因為 2015 年正好是掃碼支付方式快速發展的階段,當時,業務方面對于系統的快速迭代要求是非常高的。技術選型方面,除了業務需求,還有技術需求和團隊需求。技術需求是什么意思?我們知道在軟件開發領域,有一句話 叫 “沒有銀彈” , 不能拿起錘子當什么都是釘子,每一門技術都有它適用的場景和范圍。剛才幾個系統,幾個服務類型顯然都是 Golang 所擅長的范圍,這是技術需求的角度。

團隊需求是什么含義呢?想跟大家分享一個故事。前兩年,我朋友的一家公司有一個網站,網站第一個版本是請外包團隊實現的,拿到驗收發現很不錯,使用的是"世界上最好的語言"。然而問題來了,當這家公司拿到第一期交付成果以后,想要自己接過來,在上面疊加一些功能進行版本的迭代。結果發現團隊里沒有會"最好語言"的成員,出于種種原因既沒有從外部招到,也沒有從內部培養起來。結果是他們又花了幾個月,用另一門語言把這個網站重寫了一遍,這就是我們在團隊需求里面想提到的一點,一門技術不管是編程語言還是系統組件,要引入這門技術,首先團隊里要有人會這門技術。另一點也是通常會比較容易忽略的,就是對于一門技術的引入,除了團隊中有相應的人能夠寫這個代碼,很重要的是,有沒有人能夠 hold 這門技術。在遇到技術難題的時候,有人能夠處理。這門技術在團隊內的培訓時,能夠有帶頭人也是一個非常重要的方面。

從技術選型的角度主要是這三方面的考量,結合我們 2015 年搭建這套系統的現狀來看一下。當時我們團隊的技術棧編程語言方面是 C、Java、Golang。選擇掃碼支付系統實現的語言的時候,C 是第一個被我們否決掉的,開發效率就滿足不了我們快速迭代的要求。我們更多的可能是從 Java、Golang 進行權衡。Golang 團隊當時人數并不多,只有三位小伙伴,但是三位小伙伴都是非常不錯的,對 Golang 的理解也很棒。到現在我們回頭來看,從三個人到現在大概有接近兩年時間的發展,我們團隊中現在有 20 多位,超過整個研發團隊一半以上的人數,已經可以熟練的掌握 Golang,用 Golang 來實現我們的業務系統、業務功能, Golang 在我們團隊中的普及發展,也是非常迅速的。團隊背景大概是這樣。

技術需求方面,我們來看 Golang 的技術特點。我這里簡單列舉一些對我們感受比較深刻的方面:

第一,快速上手,學習曲線平滑,開發效率非常高。我們團隊發展歷程可以充分證明這一點,從三位 Golang 小伙伴到二十多位,一年多不到兩年的時間,大多數是從內部轉型過來的,不管是 C 還是 Java 轉型過來小伙伴,大家轉型和上手過程的普遍感受都是學習起來沒有什么困難,上手非常快,開發效率方面也非常不錯。在 2015 年最初搭建這套系統的時候,行業市場瞬息萬變,甚至不夸張的說, 當時這個系統 一天一個版本,開發效率非常高;

第二,天生支持并發編程,對于我們后端普遍需要并發處理的場景也是非常適合的;

第三,簡潔的錯誤處理: panic、recover、defer 。有人可能會喜歡,有人可能會不太習慣,我個人很習慣這樣的處理方式。這塊我們也遇到一些問題,踩過一些坑,這個在最后會跟大家分享。

剛剛是團隊需求、技術需求方面。接下來我們更關注業務需求方面。我們剛才提到三點:

第一,安全性。從安全性角度出發為什么選擇 Golang?選擇 Golang 靠不靠譜?一個支付系統,它的整個處理流程的安全性,實際上涉及到方方面面,包括數據傳輸的安全性,是否有數據泄露的風險,是否有防篡改的措施;數據落地存儲的時候,存儲是不是關鍵信息有做加密;網絡方面,網絡是不是有接入層、防火墻等等。整個系統的安全性,從接入層到應用層、系統組件,再到 Database,每一層可能都會有相應安全性方面的考量。落地到編程語言選擇,Golang 的安全性靠不靠譜呢?編程語言的安全性更關注什么呢?很自然的想到一點就是語言的漏洞。

Go語言在掃碼支付系統中的成功實踐
圖 2

關于漏洞,我們將收集到一個數據和大家分享一下,如圖 2 所示是一個漏洞搜集的網站,我用關鍵詞 Golang 搜索漏洞,可以看到五個,然后用關鍵詞 Java 搜索,有 1660 個。沒有黑 Java 的意思,解釋一下這 1000 多個是什么意思:畢竟 Java 發展這么多年已經非常成熟,JDK 的漏洞其實非常少了,1000 多個絕大多數都是各種框架的漏洞。例如我們一些存量系統,有的 web 平臺用的 ssh 框架,眾所周知的"萬年漏洞王"迫使我們每年都要對這套框架進行一次升級。反過來看 Golang,一方面是因為 Golang 比較新,曝出來的漏洞沒有那么多;另一方面,Golang 的安全性也確實沒有遇到過什么問題。而且 Golang 背靠 Google,有龐大的社區。所以從編程語言的安全性方面考慮的話,在我們看來選擇 Golang 沒有必要顧慮太多,這是安全性方面。

第二,穩定性。其實和安全性類似的一點是,同樣需要考量在系統整體架構,系統各個層級等方面的穩定性。昨天下午 B 站的老師也跟大家分享了微服務演進過程中,系統穩定性方面的考量,限流、容錯、故障隔離等。系統的接入層限流是不是足夠好,應用層是不是高可用,緩存、數據庫等組件也都需要有穩定性方面相應的考量。同樣,落地到我們的編程語言應用實現方面,在穩定性上更關注的是什么內容呢?在我們看來,應用高可用架構,即應用的實現要做到無狀態,支持橫向擴展。其實這一點,不管是 Golang 還是 Java 還是其他的語言,只要結構、代碼設計的好, 做到這一點 沒有什么壓力。

第三,吞吐量。隨著業務發展,交易量逐步增加,客戶越來越多,吞吐量是否得到很好的支撐?在這方面,準備了兩個并發處理能力方面的例子。這兩個也是我們系統中會經常用到的功能。一個是 http 接口的并發處理能力, 另外一個是 RSA 加解密的例子。

Go語言在掃碼支付系統中的成功實踐
圖 3

如圖 3 所示是我的實驗環境,是用自己的 MacBook,雙核 8G 的環境,Golang 是 1.7 的版本。同時為了有一個對標的效果,單獨拿 Golang 看它的效率可能看不出什么,因此拿 Java 做了一個對標,再強調一遍, 只是一個對標的目的, 沒有黑 Java 的意思。

Go語言在掃碼支付系統中的成功實踐
圖 4

如圖 4 所示,我們來看第一個http 接口,這是 Golang 版本非常簡單的 http 接口,這個不用多說,大家看一眼也知道,十幾行的代碼,啟動一個 http 服務,收到一個請求以后,應答,回十個字節,這是 Golang 的版本。Java 版本做的事情是一樣,但是 Java 代碼比較多,沒有截全,因為 Java 的 http 本身沒有帶多線程的方式,寫了一個簡單的線程池,用多線程的方式去處理 http 的請求。

接下來是測試的結果,十個用戶一萬個請求進行測試。上面是一個 Golang 的結果,吞吐量 12000 多,請求 響應 時間是 0.815 毫秒。下面是 Java 版本,吞吐量是 11000 多,響應時間是0.891 毫秒,這兩個版本差別不大,非常相近。從 http 接口方面來說,Java 和 Golang 的處理結果相差不是很大。

下一個例子是 RSA 加解密處理。上面是 Golang 的版本,也是采用并發處理的方式,循環 1000 次,每次進行一次加密、一次解密,加密的密鑰用 2048 byte 長 度的密鑰,待加密的數據是 245 byte。下面是 Java 的版本,也是截了一部分出來,實現方式和 Golang 實現方式一樣。

Go語言在掃碼支付系統中的成功實踐
圖 5

我們直接看結果,如圖 5 所示,上面是 Golang 的結果,下面是 Java 的結果, 用 的是 Mac 自帶的 time 命令來統計耗時。Golang 的結果,程序實際執行時間(real time)是 2.78 秒 ,J ava 執行時間是 7.74 秒,這里會看到三倍左右的差距。這個只能說明在 RSA 加解密處理的簡單場景上面,使用各自的標準庫,可能 Golang 的效率會比 Java 實現 效率 更高一些。當然大家也可以很容易的找出一些反例,在某些場景,Java 比 Golang 的實現效率更高一些。什么意思呢?從不同的場景,不同語言的實現效率或者好一些或者壞一些。對于我們選擇 Golang 來說,只要我們證明它在 我們常用的一些場景 效率沒有問題,我們就可以用 Golang 來做這套系統 。

實際上我們對于 Golang 的吞吐量方面的信心,一方面源于我們的測試結果,另一方面其實在我們搭建這套掃碼支付系統之前,我們還使用 Golang 做過另一個秒殺系統。這個秒殺系統第一個版本是使用 Java 來做擋板服務器,但是,可能是我們參數調優沒有做好,在壓力測試的時候,單臺壓到 500 tps 就上不去了。但由于時間緊任務重,沒有來得及做仔細的參數調優,我們換成用 Golang 試了試。結果一晚上的開發時間,輕松幾萬上去沒有什么問題。這也使得我們在 Golang 吞吐量方面建立了很強的信心。

從業務需求角度考慮,不管是安全性、穩定性、吞吐量,選擇 Golang 都沒有什么壓力。

最后總結一下,我們最終選擇 Golang 的出發點:作為需要快速原型、快速迭代的項目,需要的開發效率非常高,在滿足當前和未來可預期的高可用、吞吐量等業務需求的前提下, Golang 的高效開發效率,簡單部署和運維,是我們擁抱 Golang 的主要原因。

以上是整個技術選型方面的考量 關鍵點, 多說一句,剛才多次提到系統的吞吐量、高可用的關鍵點,其實除了編程語言這一層,更多的可能跟整體的系統架構有很大關系,當然這是另一個話題了。

架構演進

Go語言在掃碼支付系統中的成功實踐
圖 6

我們來一起看一下系統架構演進的過程。 如圖 6 所示, 是 2015 年上線的第一個掃碼交易處理系統。當時整個后臺系統非常簡單。因為當時需要版本快速迭代,而且我們更多的主要力量在為商家提供的收款產品。我們可以看到各種各樣的收款產品,包括云收銀的產品系列,iOS、安卓的 APP,SDK,包括 PC 端的商業軟件,右上角的智能 POS 系列產品等。最初上線的時候,需要利用這些產品快速鋪開前端市場,所以在后臺系統上,是一個非常簡單的架構。系統在上線之后的一段時間,其實還是相對穩定的,畢竟越簡單越穩定。但是隨著業務量的增加,以及業務上需要疊加的功能越來越多,這樣的一個單體應用結構很明顯是撐不住的。所以,接下來我們進行了一系列的架構調整、演進。

Go語言在掃碼支付系統中的成功實踐
圖 7

如圖 7 所示的架構是我們幾個月之前的系統結構,比第一個版本復雜很多。主要的掃碼處理系統是在圖左。我們看應用層,從一個單體應用延伸出了多個,包括我們剛剛提到的不同類型的服務:掃碼網關的實時交易處理服務,為商戶提供對賬報表的 批處理的服務 ,為商戶提供信息查詢的 平臺服務。 另外還搭建了我們的風控系統,因為風控在整個支付交易處理中也是非常重要的方面。APP 后臺,是我們 iOS、安卓的 App 提供的單獨的后臺服務。整個這一套系統,都是 使用 Golang 實現的。Golang 在統一系統實現的技術棧方面,為我們提供了很大的幫助 。 中間件方面 ,為了 解耦和提高穩定性, 我們引入了kafka、redis等系統組件。 為了實現跨機房災備系統搭建,我們自研了一套數據庫的同步工具,可以從 MongoDB 文檔型的數據庫,將數據實時同步到 MongoDB 或者 MySQL 等其他關系型數據庫,這套工具也是使用 Golang 來做的。

在整個架構的完善方面,根據業務職能拆出更多的系統。目前我們的系統在此基礎之上,進行了更多的一些往服務化方面的逐步演進,這是整個系統架構演進的過程。

一些坑

Go語言在掃碼支付系統中的成功實踐
圖 8

如圖 8 所示,很簡單的 十幾行代碼,它提供的是 TCP 長連接服務端的服務。每 accept 一條鏈接,收到客戶端的請求之后,開一個 goroutine,通過 handleConnection 這個函數進行客戶端連接的處理。針對 handleConnection 這個函數進行了一層包裝,稱之為 TcpRecoverWrap,包裝里做了什么,看名字也知道,是一個 recover 的包裝,具體的實現在圖右,非常簡單,也是 Golang 里面比較常用的處理方式,給一個函數加一個包裝,包裝里面加一個 defer 進行 recover 處理。

Go語言在掃碼支付系統中的成功實踐
圖 9

這段代碼看起來很簡單,那么問題來 了 ,是不是在 handleConnection 函數內發生的任何 panic 都能通過 TcpRecoverWrap 這樣的實現方式來解決?既然提出這個問題,答案肯定是否定的。來看一下 handleConnection 的具體 實現,如圖 9 右邊所示,是一個 TCP 的服務端,已經 accept 一個鏈接,開始 read,在一個死循環里面進行 read 操作,每 read 一條客戶端發來的請求信息,開一個 goroutine 進行實際的業務處理,把讀到的消息給到業務處理的函數,當業務處理完成,拿到業務處理結果以后,把結果寫到一個 channel 里面,這個結果由另一個 goroutine 來接收,接收到以后把應答的消息回復給 TCP 客戶端,也是很簡單的一段代碼。

我們剛才列出來的兩個問題,全都在這一段代碼里面了。第一個變量作用域,第二個 chan 操作。這幾十行代碼里,哪一個變量作用域存在問題?右上角的 reqBytes 的變量,我們看到前面在 for 循環外面定義了一個 reqBytes,接下來進入到循環中,每一次讀到的東西都放到 reqBytes,我們可以看到,其實每次循環,使用的 reqBytes 是一個變量,它的內存空間是一個。那么問題來了, goroutine 開啟方式是一個必包的方式, 外面的變量對于每個子 goroutine 來說是可見的,也就是每讀到一條消息,放到同樣一個變量里面,有可能的結果是,第一個消息開了一個 goro u tine,但這個 goroutine 還沒來得及調度的時候,又收到到第二個消息,那么第二個消息會把第一個 goroutine 里面的消息覆蓋,不同請求之間會產生關聯影響。

第二個 chan 操作問題。我們知道在寫 chan 的時候,如果 chan 已經被關了,那么對它進行寫入操作會 panic。我們看圖9中的 writeMsgQueue 這個 chan ,在 defer 里面進行了關閉。當這個 TCP 連接不可用的時候, handleConnection 函數 return 之前關閉這個 chan,目的是 chan 關閉后,通過檢查 chan 狀態,可以促使 goroutine 退出,避免 goroutine 泄露,但是這個 defer 的 close 引入了另一個問題,如果服務端收到消息、開 goroutine 進行業務處理的過程中,客戶端已經斷開了連接,那么此時 chan 已經關閉了,當服務端業務處理完成的時候,寫入一個已關閉的 chan ,就會panic。更可怕的是,這個 panic 是不能被 TcpRecoverWrap 包裝的,因為在執行 defer 結束、關閉了chan 之后,handleConnection 函數就已經 return,也就是這個 panic 是發生在另一個 goroutine 的,和 handleConnection 函數沒有關系,很顯然剛才的包裝方式是沒有辦法捕捉這樣的 panic 進行 recover 的。

Go語言在掃碼支付系統中的成功實踐
圖 10

今天分享的內容大概就是這些,那么怎么修這些問題呢?很簡單,變量作用域拿到 for 循環里面,panic 的問題可以加另外一個 tcp 關閉信號,通過這樣的方式,來修復剛才說的兩個問題。當然修復方式可能有很多種,僅供大家參考。


作者:佚名

來源:51CTO

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/257487.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/257487.shtml
英文地址,請注明出處:http://en.pswp.cn/news/257487.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一站式學習Wireshark(七):Statistics統計工具功能詳解與應用

Wireshark一個強大的功能在于它的統計工具。使用Wireshark的時候,我們有各種類型的工具可供選擇,從簡單的如顯示終端節點和會話到復雜的如Flow和IO圖表。本文將介紹基本網絡統計工具。包括:捕捉文件摘要(Summary),捕捉…

UIKit框架各個類的簡介

1.UIAcceleration: 被叫做加速事件的一個UIAcceleration類的實例是用來代表即時的三維加速數據。為了接收重力加速度,要注冊一個應用應用程序作為一個共享UIAccelerater對象的委托對象(參考UIAcceleromete類)。 2. UIAccelerater: UIAccelera…

php堆是什么,PHP 堆與堆排序的詳解

堆排序&#xff1a;堆排序是利用堆的性質進行的一種選擇排序。下面先討論一下堆。1.堆堆實際上是一棵完全二叉樹&#xff0c;其任何一非葉節點滿足性質&#xff1a;Key[i]<key[2i1]&&Key[i]<key[2i2]或者Key[i]>Key[2i1]&&key>key[2i2]即任何一非葉…

Odoo (OpenERP/TinyERP)-10.0 (Debian 8)

平臺&#xff1a; Ubuntu 類型&#xff1a; 虛擬機鏡像 軟件包&#xff1a; odoo-10.0commercial erp odoo open source openerp tinyerp服務優惠價: 按服務商許可協議 云服務器費用:查看費用 立即部署產品詳情 產品介紹Odoo https://www.odoo.com/ &#xff08;前Op…

iOS開發- 藍牙后臺接收數據(BLE4.0)

最近在做一個藍牙相關的項目, 需要在應用進入后臺, 或者手機屬于鎖屏狀態的情況下, 仍然保持藍牙連接, 并且能正常接收數據。 本來以后會很麻煩, 但是學習了下..發現就2步而已。簡單的不能再簡單了。 好了。下面是具體實現辦法。 1.在xxx-info.plist文件中, 新建一行 Required…

貪心(數據結構):COGS 468. [NOI2010]超級鋼琴

★★★☆ 輸入文件&#xff1a;piano.in 輸出文件&#xff1a;piano.out 簡單對比 時間限制&#xff1a;2 s 內存限制&#xff1a;512 MB 超級鋼琴 【問題描述】 小Z是一個小有名氣的鋼琴家&#xff0c;最近C博士送給了小Z一架超級鋼琴&#xff0c;小Z希望能夠用這架…

java實現選擇排序 帶打印,選擇排序算法的JAVA實現

選擇排序算法的JAVA實現package Utils.Sort;/***利用選擇排序法對數組排序&#xff0c;數組中元素必須實現了Comparable接口。*/public class ChooseSort implements SortStrategy{/***對數組obj中的元素以選擇排序算法進行排序*/public void sort(Comparable[] obj){if (obj …

angularjs初始化時不顯示模板內容, 不顯示html, 不顯示template

template的內容可能在需要的數據準備好之前就顯示出來了, ng-cloak可以解決這個問題 ng-cloak <div id"template1" ng-cloak>{{ hello }}</div> <div id"template2" class"ng-cloak">{{ world }}</div>

左右箭頭滑動列表

//slideshow 左右箭頭滑動一組li焦點圖 autoSlide();function autoSlide(){clearAutoSsetInterval(autoFunS,5000);}function autoFunS(){var loc$(".slideshow-box ul").css("left");if(loc"-2370px"){loc"1185";}var newlocparseInt…

20159206《網絡攻防實踐》第四周學習總結

20159206《網絡攻防實踐》第四周學習總結 教材學習內容總結 本章主要介紹了網絡嗅探和協議分析 網絡嗅探是一種常用的竊聽技術&#xff0c;利用計算機的網絡接口截獲目的地為其他計算機的數據報文&#xff0c;以監聽數據流中所包含的用戶賬戶密碼或私密信息等。 網絡泄灘具有很…

四六級php,詳解四六級查詢API+網頁

這個API是第三方API&#xff0c;第三方API的工作原理大都基于此&#xff0c;本文主要起一反三之作用&#xff0c;代碼的不處周之還望及時指出。開發環境&#xff1a;WinServer2012 php7.0 Apache2.4.8思路&#xff1a;向官方查詢界面傳遞參數&#xff0c;使用curl抓取結果網頁…

終于把joomla 的 protostar 模版的菜單,從垂直改到水平了

protostar-applying-menu-class-suffixes-horizontal-vs-vertical-menus.html joomla 3.7.5 附帶的這個template , 菜單丑的要死。 估計是新改的。 看網上的其他站點都沒這毛病。 最后終于找到解決方法了。“ nav-pills“ 前面是有空格的 To make the menu horizonal, you can …

Find non-overlap jobs with max cost

Given a set of n jobs with [start time, end time, cost] find a subset so that no 2 jobs overlap and the cost is maximum.Job: &#xff08;start_time, end_time] --- cost 如果只是求maxCost, 一維就可以做。 但是如果要知道有選了哪些job&#xff0c;則需要存成二維。…

php 跨區域,PHP跨時區的功能實現

現在有一個跨時區的應用&#xff0c;不同時區登錄的用戶需要看到自己時區的時間&#xff0c;同時也要能夠進行時區的切換。我的思路是&#xff0c;系統中所有存儲的時間都是GMT(UTC)時間&#xff0c;用戶登錄時&#xff0c;根據用戶所在的時區進行對應的顯示。首先了解一下PHP中…

js實現向上滾動效果

源碼&#xff1a;<style type"text/css"> #up_zzjs{border:1px solid #ccc;width:170px;height:182px;line-height:20px;overflow:hidden;} #up_zzjs #up_li{list-style-type:none;margin:0;padding:0;margin-left:6px;} /*系統支持ie8就選line-heigh…

利用數據的商業智能分析工具

商業智能可以定義為獲取和轉換原始數據的技術和工具&#xff0c;這些信息可以為業務運營提供有意義的好處。 商業智能的發展 商業智能&#xff08;BI&#xff09;是一個可追溯到19世紀中期的術語&#xff0c;基本上是一樣的定義。但作為結構化數據的自動化處理的參考&#xff0…

管理之道(三) - 不要吝惜贊美

多一句贊美 人們相互希望得越多&#xff0c;想要給予對方的越多……就必定越親密。   幾天前&#xff0c;我和一位朋友在紐約搭計程車&#xff0c;下車時&#xff0c;朋友對司機說&#xff1a;“謝謝&#xff0c;搭你的車十分舒適。”這司機聽了愣了一愣&#xff0c;然后說&a…

優酷視頻整段代理php,thinkphp仿優酷帶數據源碼|php仿優酷視頻源碼帶后臺功能強大...

本項目是仿優酷官網&#xff0c;優酷官網是一個集多種知識面為一體的網站&#xff0c;能全面的鍛煉我們的技能,所以我們決定仿優酷網。本項目后臺主要實現了&#xff1a;用戶管理、分類管理、視頻管理、評論管理、權限管理、輪播管理、網站配置和廣告管理以及登錄退出等模塊。前…

Centos7安裝Oracle JDK

查看Linux是否自帶的JDK&#xff0c;如有openJDK&#xff0c;則卸載1 java -version 1 rpm -qa | grep -E ^open[jre|jdk]|j[re|dk] 卸載openjdk1 su root 2 3 yum -y remove java java-1.7.0-openjdk 下載oracle jdk1 wget --no-cookies --header "Cookie: oraclelice…

前端每周清單第 30 期:WebVR 指南,Vue 代碼分割范式,理想的 React 架構特性

前端每周清單專注前端領域內容&#xff0c;以對外文資料的搜集為主&#xff0c;幫助開發者了解一周前端熱點&#xff1b;分為新聞熱點、開發教程、工程實踐、深度閱讀、開源項目、巔峰人生等欄目。歡迎關注【前端之巔】微信公眾號&#xff08;ID&#xff1a;frontshow&#xff…