當(dāng)前位置:首頁(yè) > 公眾號(hào)精選 > 小林coding
[導(dǎo)讀]金九銀十,又是一年校招季,經(jīng)歷過才深知不易。最近,和作為校招面試官的同事聊了聊,問他們是如何去考察一個(gè)學(xué)生的,我簡(jiǎn)單歸為以下幾點(diǎn): 聰明、反應(yīng)快;算法不錯(cuò),代碼基本功好;基礎(chǔ)過硬;語(yǔ)言組織和表達(dá)能力。

前言

金九銀十,又是一年校招季。

經(jīng)歷過,才深知不易。最近,和作為校招面試官的同事聊了聊,問他們是如何去考察一個(gè)學(xué)生的,我簡(jiǎn)單歸為以下幾點(diǎn):

  1. 聰明、反應(yīng)快,這點(diǎn)自不必說,聰明意味著學(xué)習(xí)能力、適應(yīng)力強(qiáng),能夠快速勝任工作。

  2. 算法不錯(cuò),代碼基本功好,這點(diǎn)其實(shí)考察的是算法能力和代碼是否寫得優(yōu)雅。

  3. 基礎(chǔ)過硬,技術(shù)崗面試最核心的還是考察「技術(shù)儲(chǔ)備」,包括了語(yǔ)言基本功,操作系統(tǒng)、網(wǎng)絡(luò)、體系結(jié)構(gòu)、系統(tǒng)設(shè)計(jì)。

  4. 語(yǔ)言組織和表達(dá)能力,這點(diǎn)很重要,很多同學(xué)懂得某個(gè)知識(shí)點(diǎn),卻很難用簡(jiǎn)潔準(zhǔn)確的語(yǔ)言表述出來。

想必有很多同學(xué)在刷題、刷面經(jīng),不過我想說“面經(jīng)雖好,不要貪杯哦~”,面經(jīng)可以刷,看看面試官都是怎么提問的,但不要寄希望于原題。
因?yàn)槊嬖囘^程中的問題往往是一環(huán)扣一環(huán)的,這意味著你需要有足夠的技術(shù)深度,將知識(shí)由點(diǎn)連接成面,而不是停留在相互孤立的知識(shí)點(diǎn)上。

所以還是建議系統(tǒng)性的看書,如果覺得時(shí)間不夠,可以關(guān)注書里的重點(diǎn)章節(jié)。

那么回到技術(shù)面試上,除了算法和網(wǎng)絡(luò)、操作系統(tǒng)這種基礎(chǔ)之外,還有一類系統(tǒng)設(shè)計(jì)和優(yōu)化的問題。這類問題需要你有一個(gè)全局的技術(shù)視野,以及熟悉一些常用的系統(tǒng)優(yōu)化方法論,也就是工程上的一些 Best Practice,而不至于自己臨時(shí)拍腦袋瞎設(shè)計(jì)。

在互聯(lián)網(wǎng)公司,經(jīng)常面臨一個(gè)“三高”問題:

  • 高并發(fā)

  • 高性能

  • 高可用

這篇文章將總結(jié)一下后臺(tái)服務(wù)器開發(fā)中有哪些常用的解決“三高”問題的方法和思想。

希望這些知識(shí),能夠給你一絲啟發(fā)和幫助,助力你收割 各大公司  Offer~

先上本文思維導(dǎo)圖:

如何解決三高


正文

一、緩存

什么是緩存?看看維基百科怎么說:

In computing, a cache is a hardware or software component that stores data so that future requests for that data can be served faster; the data stored in a cache might be the result of an earlier computation or a copy of data stored elsewhere.

在計(jì)算機(jī)中,緩存是存儲(chǔ)數(shù)據(jù)的硬件或軟件組件,以便可以更快地滿足將來對(duì)該數(shù)據(jù)的請(qǐng)求。存儲(chǔ)在緩存中的數(shù)據(jù)可能是之前計(jì)算結(jié)果,也可能是存儲(chǔ)在其他位置的數(shù)據(jù)副本。

緩存本質(zhì)來說是使用空間換時(shí)間的思想,它在計(jì)算機(jī)世界中無處不在, 比如 CPU 就自帶 L1、L2、L3 Cache,這個(gè)一般應(yīng)用開發(fā)可能關(guān)注較少。但是在一些實(shí)時(shí)系統(tǒng)、大規(guī)模計(jì)算模擬、圖像處理等追求極致性能的領(lǐng)域,就特別注重編寫緩存友好的代碼。

什么是緩存友好?簡(jiǎn)單來說,就是代碼在訪問數(shù)據(jù)的時(shí)候,盡量使用緩存命中率高的方式。這個(gè)后面可以單獨(dú)寫一篇 CPU 緩存系統(tǒng)以及如何編寫緩存友好代碼的文章。

1.1 緩存為什么有效?

緩存之所以能夠大幅提高系統(tǒng)的性能,關(guān)鍵在于數(shù)據(jù)的訪問具有局部性,也就是二八定律:「百分之八十的數(shù)據(jù)訪問是集中在 20% 的數(shù)據(jù)上」。這部分?jǐn)?shù)據(jù)也被叫做熱點(diǎn)數(shù)據(jù)。

緩存一般使用內(nèi)存作為存儲(chǔ),內(nèi)存讀寫速度快于磁盤,但容量有限,十分寶貴,不可能將所有數(shù)據(jù)都緩存起來。

如果應(yīng)用訪問數(shù)據(jù)沒有熱點(diǎn),不遵循二八定律,即大部分?jǐn)?shù)據(jù)訪問并沒有集中在小部分?jǐn)?shù)據(jù)上,那么緩存就沒有意義,因?yàn)榇蟛糠謹(jǐn)?shù)據(jù)還沒有被再次訪問就已經(jīng)被擠出緩存了。每次訪問都會(huì)回源到數(shù)據(jù)庫(kù)查詢,那么反而會(huì)降低數(shù)據(jù)訪問效率。

1.2 緩存分類

  • 1. 本地緩存:

    使用進(jìn)程內(nèi)成員變量或者靜態(tài)變量,適合簡(jiǎn)單的場(chǎng)景,不需要考慮緩存一致性、過期時(shí)間、清空策略等問題。

    可以直接使用語(yǔ)言標(biāo)準(zhǔn)庫(kù)內(nèi)的容器來做存儲(chǔ)。例如:

    本地緩存
  • 2. 分布式緩存:

    當(dāng)緩存的數(shù)據(jù)量增大以后,單機(jī)不足以承載緩存服務(wù)時(shí),就要考慮對(duì)緩存服務(wù)做水平擴(kuò)展,引入緩存集群。

    將數(shù)據(jù)分片后分散存儲(chǔ)在不同機(jī)器中,如何決定每個(gè)數(shù)據(jù)分片存放在哪臺(tái)機(jī)器呢?一般是采用一致性 Hash 算法,它能夠保證在緩存集群動(dòng)態(tài)調(diào)整,不斷增加或者減少機(jī)器后,客戶端訪問時(shí)依然能夠根據(jù) key 訪問到數(shù)據(jù)。

    一致性 Hash 算法也是值得用一篇文章來講的,如果暫時(shí)還不懂的話可以去搜一下。

    常用的組件有 Memcache、 Redis Cluster 等,第二個(gè)是在高性能內(nèi)存存儲(chǔ) Redis 的基礎(chǔ)上,提供分布式存儲(chǔ)的解決方案。

1.3 緩存使用指南

1. 適合緩存的場(chǎng)景:

  • 讀多寫少:

    比如電商里的商品詳情頁(yè)面,訪問頻率很高,但是一般寫入只在店家上架商品和修改信息的時(shí)候發(fā)生。如果把熱點(diǎn)商品的信息緩存起來,這將攔截掉很多對(duì)數(shù)據(jù)庫(kù)的訪問,提高系統(tǒng)整體的吞吐量。

    因?yàn)橐话銛?shù)據(jù)庫(kù)的 QPS 由于有「ACID」約束、并且數(shù)據(jù)是持久化在硬盤的,所以比 Redis 這類基于內(nèi)存的 NoSQL 存儲(chǔ)低不少。常常是一個(gè)系統(tǒng)的瓶頸,如果我們把大部分的查詢都在 Redis 緩存中命中了,那么系統(tǒng)整體的 QPS 也就上去了。

  • 計(jì)算耗時(shí)大,且實(shí)時(shí)性不高:
    比如王者榮耀里的全區(qū)排行榜,一般一周更新一次,并且計(jì)算的數(shù)據(jù)量也比較大,所以計(jì)算后緩存起來,請(qǐng)求排行榜直接從緩存中取出,就不用實(shí)時(shí)計(jì)算了。

2. 不適合緩存的場(chǎng)景

  • 寫多讀少,頻繁更新。

  • 對(duì)數(shù)據(jù)一致性要求嚴(yán)格: 因?yàn)榫彺鏁?huì)有更新策略,所以很難做到和數(shù)據(jù)庫(kù)實(shí)時(shí)同步。

  • 數(shù)據(jù)訪問完全隨機(jī): 因?yàn)檫@樣會(huì)導(dǎo)致緩存的命中率極低。

1.4 緩存更新的策略

如何更新緩存其實(shí)已經(jīng)有總結(jié)得非常好的「最佳實(shí)踐」,我們按照套路來,大概率不會(huì)犯錯(cuò)。

主要分為兩類 Cache-AsideCache-As-SoR。 SoR 即「System Of Record,記錄系統(tǒng)」,表示數(shù)據(jù)源,一般就是指數(shù)據(jù)庫(kù)。

1、Cache-Aside:

Cache-Aside架構(gòu)圖

這應(yīng)該是最容易想到的模式了,獲取數(shù)據(jù)時(shí)先從緩存讀,如果 cache hit 則直接返回,沒命中就從數(shù)據(jù)源獲取,然后更新緩存。

寫數(shù)據(jù)的時(shí)候則先更新數(shù)據(jù)源,然后設(shè)置緩存失效,下一次獲取數(shù)據(jù)的時(shí)候必然 cache miss,然后觸發(fā)回源。

直接看偽代碼:

Cache-Aside 代碼示范

可以看到這種方式對(duì)于緩存的使用者是不透明的,需要使用者手動(dòng)維護(hù)緩存。

2、Cache-As-SoR:

Cache-As-SoR架構(gòu)圖

從字面上來看,就是把 Cache 當(dāng)作 SoR,也就是數(shù)據(jù)源,所以一切讀寫操作都是針對(duì) Cache 的,由 Cache 內(nèi)部自己維護(hù)和數(shù)據(jù)源的一致性。

這樣對(duì)于使用者來說就和直接操作 SoR 沒有區(qū)別了,完全感知不到 Cache 的存在。

CPU 內(nèi)部的 L1、L2、L3 Cache 就是這種方式,作為數(shù)據(jù)的使用方應(yīng)用程序,是完全感知不到在內(nèi)存和我們之間還存在幾層的 Cache,但是我們之前又提到編寫 “緩存友好”的代碼,不是透明的嗎?這是不是沖突呢?

其實(shí)不然,緩存友好是指我們通過學(xué)習(xí)了解緩存內(nèi)部實(shí)現(xiàn)、更新策略之后,通過調(diào)整數(shù)據(jù)訪問順序提高緩存的命中率。

Cache-As-SoR 又分為以下三種方式:

  • Read Through:這種方式和 Cache-Aside 非常相似,都是在查詢時(shí)發(fā)生 cache miss 去更新緩存,但是區(qū)別在于 Cache-Aside 需要調(diào)用方手動(dòng)更新緩存,而 Cache-As-SoR 則是由緩存內(nèi)部實(shí)現(xiàn)自己負(fù)責(zé),對(duì)應(yīng)用層透明。

  • Write Through:直寫式,就是在將數(shù)據(jù)寫入緩存的同時(shí),緩存也去更新后面的數(shù)據(jù)源,并且必須等到數(shù)據(jù)源被更新成功后才可返回。這樣保證了緩存和數(shù)據(jù)庫(kù)里的數(shù)據(jù)一致性。

  • Write Back:回寫式,數(shù)據(jù)寫入緩存即可返回,緩存內(nèi)部會(huì)異步的去更新數(shù)據(jù)源,這樣好處是寫操作特別快,因?yàn)橹恍枰戮彺妗2⑶揖彺鎯?nèi)部可以合并對(duì)相同數(shù)據(jù)項(xiàng)的多次更新,但是帶來的問題就是數(shù)據(jù)不一致,可能發(fā)生寫丟失。


二、預(yù)處理和延后處理

預(yù)先延后,這其實(shí)是一個(gè)事物的兩面,不管是預(yù)先還是延后核心思想都是將本來該在實(shí)時(shí)鏈路上處理的事情剝離,要么提前要么延后處理。降低實(shí)時(shí)鏈路的路徑長(zhǎng)度, 這樣能有效提高系統(tǒng)性能。

2.1 預(yù)處理

舉個(gè)我們團(tuán)隊(duì)實(shí)際中遇到的問題:

前兩個(gè)月支付寶聯(lián)合杭州市政府發(fā)放消費(fèi)劵,但是要求只有杭州市常駐居民才能領(lǐng)取,那么需要在搶卷請(qǐng)求進(jìn)入后臺(tái)的時(shí)候就判斷一下用戶是否是杭州常駐居民。

而判斷用戶是否是常駐居民這個(gè)是另外一個(gè)微服務(wù)接口,如果直接實(shí)時(shí)的去調(diào)用那個(gè)接口,短時(shí)的高并發(fā)很有可能把這個(gè)服務(wù)也拖掛,最終導(dǎo)致整個(gè)系統(tǒng)不可用,并且 RPC 本身也是比較耗時(shí)的,所以就考慮在這里進(jìn)行優(yōu)化。

那么該怎么做呢?很簡(jiǎn)單的一個(gè)思路,提前將杭州所有常駐居民的 user_id 存到緩存中, 比如可以直接存到 Redis。大概就是千萬量級(jí),這樣,當(dāng)請(qǐng)求到來的時(shí)候我們直接通過緩存可以快速判斷是否來自杭州常駐居民。如果不是則直接在這里返回前端。

這里通過預(yù)先處理減少了實(shí)時(shí)鏈路上的 RPC 調(diào)用,既減少了系統(tǒng)的外部依賴,也極大的提高了系統(tǒng)的吞吐量。

預(yù)處理在 CPU 和操作系統(tǒng)中也廣泛使用,比如 CPU 基于歷史訪存信息,將內(nèi)存中的指令和數(shù)據(jù)預(yù)取到 Cache 中,這樣可以大大提高Cache 命中率。 還比如在 Linux 文件系統(tǒng)中,預(yù)讀算法會(huì)預(yù)測(cè)即將訪問的 page,然后批量加載比當(dāng)前讀請(qǐng)求更多的數(shù)據(jù)緩存在 page cache 中,這樣當(dāng)下次讀請(qǐng)求到來時(shí)可以直接從 cache 中返回,大大減少了訪問磁盤的時(shí)間。

2.2 延后處理

還是支付寶,上栗子:

集五?;顒?dòng)

這是支付寶春節(jié)集五?;顒?dòng)開獎(jiǎng)當(dāng)晚,不過,作為非酋的我一般是不屑于參與這種活動(dòng)的。

大家發(fā)現(xiàn)沒有,這類活動(dòng)中獎(jiǎng)獎(jiǎng)金一般會(huì)顯示 「稍后到賬」,為什么呢?那當(dāng)然是到賬這個(gè)操作不簡(jiǎn)單!

到賬即轉(zhuǎn)賬,A 賬戶給 B 賬戶轉(zhuǎn)錢,A 減錢, B 就必須要同時(shí)加上錢,也就是說不能 A 減了錢但 B 沒有加上,這就會(huì)導(dǎo)致資金損失。資金安全是支付業(yè)務(wù)的生命線,這可不行。

這兩個(gè)動(dòng)作必須一起成功或是一起都不成功,不能只成功一半,這是保證數(shù)據(jù)一致性。 保證兩個(gè)操作同時(shí)成功或者失敗就需要用到事務(wù)

如果去實(shí)時(shí)的做到賬,那么大概率數(shù)據(jù)庫(kù)的 TPS(每秒處理的事務(wù)數(shù)) 會(huì)是瓶頸。通過產(chǎn)品提示,將到賬操作延后處理,解決了數(shù)據(jù)庫(kù) TPS 瓶頸。

延后處理還有一個(gè)非常著名的例子,COW(Copy On Write,寫時(shí)復(fù)制)。 Linux 創(chuàng)建進(jìn)程的系統(tǒng)調(diào)用 fork,fork 產(chǎn)生的子進(jìn)程只會(huì)創(chuàng)建虛擬地址空間,而不會(huì)分配真正的物理內(nèi)存,子進(jìn)程共享父進(jìn)程的物理空間,只有當(dāng)某個(gè)進(jìn)程需要寫入的時(shí)候,才會(huì)真正分配物理頁(yè),拷貝該物理頁(yè),通過 COW 減少了很多不必要的數(shù)據(jù)拷貝。


三、池化

后臺(tái)開發(fā)過程中你一定離不開各種 「池子」: 內(nèi)存池、連接池、線程池、對(duì)象池……

內(nèi)存、連接、線程這些都是資源,創(chuàng)建線程、分配內(nèi)存、數(shù)據(jù)庫(kù)連接這些操作都有一個(gè)特征, 那就是創(chuàng)建和銷毀過程都會(huì)涉及到很多系統(tǒng)調(diào)用或者網(wǎng)絡(luò) IO。 每次都在請(qǐng)求中去申請(qǐng)創(chuàng)建這些資源,就會(huì)增加請(qǐng)求處理耗時(shí),但是如果我們用一個(gè) 容器(池) 把它們保存起來,下次需要的時(shí)候,直接拿出來使用,避免重復(fù)創(chuàng)建和銷毀浪費(fèi)的時(shí)間。

3.1 內(nèi)存池

在 C/C++ 中,經(jīng)常使用 malloc、new 等 API 動(dòng)態(tài)申請(qǐng)內(nèi)存。由于申請(qǐng)的內(nèi)存塊大小不一,如果頻繁的申請(qǐng)、釋放會(huì)導(dǎo)致大量的內(nèi)存碎片,并且這些  API 底層依賴系統(tǒng)調(diào)用,會(huì)有額外的開銷。

內(nèi)存池就是在使用內(nèi)存前,先向系統(tǒng)申請(qǐng)一塊空間留做備用,使用者需要內(nèi)池時(shí)向內(nèi)存池申請(qǐng),用完后還回來。

內(nèi)存池的思想非常簡(jiǎn)單,實(shí)現(xiàn)卻不簡(jiǎn)單,難點(diǎn)在于以下幾點(diǎn):

  • 如何快速分配內(nèi)存

  • 降低內(nèi)存碎片率

  • 維護(hù)內(nèi)存池所需的額外空間盡量少

如果不考慮效率,我們完全可以將內(nèi)存分為不同大小的塊,然后用鏈表連接起來,分配的時(shí)候找到大小最合適的返回,釋放的時(shí)候直接添加進(jìn)鏈表。如:

空閑鏈表

當(dāng)然這只是玩具級(jí)別的實(shí)現(xiàn),業(yè)界有性能非常好的實(shí)現(xiàn)了,我們可以直接拿來學(xué)習(xí)和使用。

比如 Google 的 「tcmalloc」 和 Facebook 的 「jemalloc」。

限于篇幅我們不在這里詳細(xì)講解它們的實(shí)現(xiàn)原理,如果感興趣可以搜來看看,也推薦去看看被譽(yù)為神書的 CSAPP(《深入理解計(jì)算機(jī)系統(tǒng)》)第 10 章,那里也講到了動(dòng)態(tài)內(nèi)存分配算法。

3.2 線程池

線程是干嘛的?線程就是我們程序執(zhí)行的實(shí)體。在服務(wù)器開發(fā)領(lǐng)域,我們經(jīng)常會(huì)為每個(gè)請(qǐng)求分配一個(gè)線程去處理,但是線程的創(chuàng)建銷毀、調(diào)度都會(huì)帶來額外的開銷,線程太多也會(huì)導(dǎo)致系統(tǒng)整體性能下降。在這種場(chǎng)景下,我們通常會(huì)提前創(chuàng)建若干個(gè)線程,通過線程池來進(jìn)行管理。當(dāng)請(qǐng)求到來時(shí),只需從線程池選一個(gè)線程去執(zhí)行處理任務(wù)即可。

線程池常常和隊(duì)列一起使用來實(shí)現(xiàn)任務(wù)調(diào)度,主線程收到請(qǐng)求后將創(chuàng)建對(duì)應(yīng)的任務(wù),然后放到隊(duì)列里,線程池中的工作線程等待隊(duì)列里的任務(wù)。

線程池實(shí)現(xiàn)上一般有四個(gè)核心組成部分:

  • 管理器(Manager): 用于創(chuàng)建并管理線程池。

  • 工作線程(Worker): 執(zhí)行任務(wù)的線程。

  • 任務(wù)接口(Task): 每個(gè)具體的任務(wù)必須實(shí)現(xiàn)任務(wù)接口,工作線程將調(diào)用該接口來完成具體的任務(wù)。

  • 任務(wù)隊(duì)列(TaskQueue): 存放還未執(zhí)行的任務(wù)。

線程池模型

線程池在 C、C++ 中沒有具體的實(shí)現(xiàn),需要應(yīng)用開發(fā)者手動(dòng)實(shí)現(xiàn)上訴幾個(gè)部分。

在 Java 中 「ThreadPoolExecutor」 類就是線程池的實(shí)現(xiàn)。后續(xù)我也會(huì)寫文章分析 C++ 如何寫一個(gè)簡(jiǎn)單的線程池以及 Java 中線程池是如何實(shí)現(xiàn)的。

3.3 連接池

顧名思義,連接池是創(chuàng)建和管理連接的。

大家最熟悉的莫過于數(shù)據(jù)庫(kù)連接池,這里我們簡(jiǎn)單分析下如果不用數(shù)據(jù)庫(kù)連接池,一次 SQL 查詢請(qǐng)求會(huì)經(jīng)過哪些步驟:

  1. 和 MySQL server 建立 TCP 連接:

  • 三次握手

  1. MySQL 權(quán)限認(rèn)證:

  • Server 向 Client 發(fā)送 密鑰

  • Client 使用密鑰加密用戶名、密碼等信息,將加密后的報(bào)文發(fā)送給 Server

  • Server 根據(jù) Client 請(qǐng)求包,驗(yàn)證是否是合法用戶,然后給 Client 發(fā)送認(rèn)證結(jié)果

  1. Client 發(fā)送 SQL 語(yǔ)句

  2. Server 返回語(yǔ)句執(zhí)行結(jié)果

  3. MySQL 關(guān)閉

  4. TCP 連接斷開

  • 四次揮手

可以看出不使用連接池的話,為了執(zhí)行一條 SQL,會(huì)花很多時(shí)間在安全認(rèn)證、網(wǎng)絡(luò)IO上。

如果使用連接池,執(zhí)行一條 SQL 就省去了建立連接和斷開連接所需的額外開銷。

還能想起哪里用到了連接池的思想嗎?我認(rèn)為 HTTP 長(zhǎng)鏈接也算一個(gè)變相的鏈接池,雖然它本質(zhì)上只有一個(gè)連接,但是思想?yún)s和連接池不謀而合,都是為了復(fù)用同一個(gè)連接發(fā)送多個(gè) HTTP 請(qǐng)求,避免建立和斷開連接的開銷。

池化實(shí)際上是預(yù)處理和延后處理的一種應(yīng)用場(chǎng)景,通過池子將各類資源的創(chuàng)建提前和銷毀延后。


四、同步變異步

對(duì)于處理耗時(shí)的任務(wù),如果采用同步的方式,那么會(huì)增加任務(wù)耗時(shí),降低系統(tǒng)并發(fā)度。

可以通過將同步任務(wù)變?yōu)楫惒竭M(jìn)行優(yōu)化。

舉個(gè)例子,比如我們?nèi)?KFC 點(diǎn)餐,遇到排隊(duì)的人很多,當(dāng)點(diǎn)完餐后,大多情況下我們會(huì)隔幾分鐘就去問好了沒,反復(fù)去問了好幾次才拿到,在這期間我們也沒法干活了,這時(shí)候我們是這樣的:

同步寫法

這個(gè)就叫同步輪訓(xùn), 這樣效率顯然太低了。

服務(wù)員被問煩了,就在點(diǎn)完餐后給我們一個(gè)號(hào)碼牌,每次準(zhǔn)備好了就會(huì)在服務(wù)臺(tái)叫號(hào),這樣我們就可以在被叫到的時(shí)候再去取餐,中途可以繼續(xù)干自己的事。

這就叫異步,在很多編程語(yǔ)言中有異步編程的庫(kù),比如 C++ std::future、Python asyncio 等,但是異步編程往往需要回調(diào)函數(shù)(Callback function),如果回調(diào)函數(shù)的層級(jí)太深,這就是回調(diào)地獄(Callback hell)?;卣{(diào)地獄如何優(yōu)化又是一個(gè)龐大的話題。。。。

這個(gè)例子相當(dāng)于函數(shù)調(diào)用的異步化,還有的是情況是處理流程異步化,這個(gè)會(huì)在接下來消息隊(duì)列中講到。


五、消息隊(duì)列

消息隊(duì)列示意圖

這是一個(gè)非常簡(jiǎn)化的消息隊(duì)列模型,上游生產(chǎn)者將消息通過隊(duì)列發(fā)送給下游消費(fèi)者。在這之間,消息隊(duì)列可以發(fā)揮很多作用,比如:

5.1 服務(wù)解耦

有些服務(wù)被其它很多服務(wù)依賴,比如一個(gè)論壇網(wǎng)站,當(dāng)用戶成功發(fā)布一條帖子有一系列的流程要做,有積分服務(wù)計(jì)算積分,推送服務(wù)向發(fā)布者的粉絲推送一條消息….. 對(duì)于這類需求,常見的實(shí)現(xiàn)方式是直接調(diào)用:

直接調(diào)用

這樣如果需要新增一個(gè)數(shù)據(jù)分析的服務(wù),那么又得改動(dòng)發(fā)布服務(wù),這違背了依賴倒置原則即上層服務(wù)不應(yīng)該依賴下層服務(wù),那么怎么辦呢?

發(fā)布訂閱模式

引入消息隊(duì)列作為中間層,當(dāng)帖子發(fā)布完成后,發(fā)送一個(gè)事件到消息隊(duì)列里,而關(guān)心帖子發(fā)布成功這件事的下游服務(wù)就可以訂閱這個(gè)事件,這樣即使后續(xù)繼續(xù)增加新的下游服務(wù),只需要訂閱該事件即可,完全不用改動(dòng)發(fā)布服務(wù),完成系統(tǒng)解耦。

5.2 異步處理

有些業(yè)務(wù)涉及到的處理流程非常多,但是很多步驟并不要求實(shí)時(shí)性。那么我們就可以通過消息隊(duì)列異步處理。比如淘寶下單,一般包括了風(fēng)控、鎖庫(kù)存、生成訂單、短信/郵件通知等步驟。但是核心的就風(fēng)控和鎖庫(kù)存, 只要風(fēng)控和扣減庫(kù)存成功,那么就可以返回結(jié)果通知用戶成功下單了。后續(xù)的生成訂單,短信通知都可以通過消息隊(duì)列發(fā)送給下游服務(wù)異步處理。大大提高了系統(tǒng)響應(yīng)速度。

這就是處理流程異步化。

5.3 流量削峰

一般像秒殺、抽獎(jiǎng)、搶卷這種活動(dòng)都伴隨著短時(shí)間海量的請(qǐng)求, 一般超過后端的處理能力,那么我們就可以在接入層將請(qǐng)求放到消息隊(duì)列里,后端根據(jù)自己的處理能力不斷從隊(duì)列里取出請(qǐng)求進(jìn)行業(yè)務(wù)處理。

就像最近長(zhǎng)江汛期,上游短時(shí)間大量的洪水匯聚直奔下游,但是通過三峽大壩將這些水緩存起來,然后勻速的向下游釋放,起到了很好的削峰作用。

起到了平均流量的作用。

5.4 總結(jié)

消息隊(duì)列的核心思想就是把同步的操作變成異步處理,異步處理會(huì)帶來相應(yīng)的好處,比如:

  • 服務(wù)解耦

  • 提高系統(tǒng)的并發(fā)度,將非核心操作異步處理,不會(huì)阻塞住主流程

但是軟件開發(fā)沒有銀彈,所有的方案選擇都是一種 trade-off。 同樣,異步處理也不全是好處,也會(huì)導(dǎo)致一些問題:

  • 降低了數(shù)據(jù)一致性,從強(qiáng)一致性變?yōu)樽罱K一致性

  • 有消息丟失的風(fēng)險(xiǎn),比如宕機(jī),需要有容災(zāi)機(jī)制


六、批量處理

在涉及到網(wǎng)絡(luò)連接、IO等情況時(shí),將操作批量進(jìn)行處理能夠有效提高系統(tǒng)的傳輸速率和吞吐量。

在前后端通信中,通過合并一些頻繁請(qǐng)求的小資源可以獲得更快的加載速度。

比如我們后臺(tái) RPC 框架,經(jīng)常有更新數(shù)據(jù)的需求,而有的數(shù)據(jù)更新的接口往往只接受一項(xiàng),這個(gè)時(shí)候我們往往會(huì)優(yōu)化下更新接口,

使其能夠接受批量更新的請(qǐng)求,這樣可以將批量的數(shù)據(jù)一次性發(fā)送,大大縮短網(wǎng)絡(luò) RPC 調(diào)用耗時(shí)。


七、數(shù)據(jù)庫(kù)

我們常把后臺(tái)開發(fā)調(diào)侃為「CRUD」,數(shù)據(jù)庫(kù)在整個(gè)應(yīng)用開發(fā)過程中的重要性不言而喻。

而且很多時(shí)候系統(tǒng)的瓶頸也往往處在數(shù)據(jù)庫(kù)這里,慢的原因也有很多,比如可能是沒用索引、沒用對(duì)索引、讀寫鎖沖突等等。

那么如何使用數(shù)據(jù)才能又快又好呢?下面這幾點(diǎn)需要重點(diǎn)關(guān)注:

7.1 索引

索引可能是我們平時(shí)在使用數(shù)據(jù)庫(kù)過程中接觸得最多的優(yōu)化方式。索引好比圖書館里的書籍索引號(hào),想象一下,如果我讓你去一個(gè)沒有書籍索引號(hào)的圖書館找《人生》這本書,你是什么樣的感受?當(dāng)然是懷疑人生,同理,你應(yīng)該可以理解當(dāng)你查詢數(shù)據(jù),卻不用索引的時(shí)候數(shù)據(jù)庫(kù)該有多崩潰了吧。

數(shù)據(jù)庫(kù)表的索引就像圖書館里的書籍索引號(hào)一樣,可以提高我們檢索數(shù)據(jù)的效率。索引能提高查找效率,可是你有沒有想過為什么呢?這是因?yàn)樗饕话愣允且粋€(gè)排序列表,排序意味著可以基于二分思想進(jìn)行查找,將查詢時(shí)間復(fù)雜度做到 O(log(N)),快速的支持等值查詢和范圍查詢。

二叉搜索樹查詢效率無疑是最高的,因?yàn)槠骄鶃碚f每次比較都能縮小一半的搜索范圍,但是一般在數(shù)據(jù)庫(kù)索引的實(shí)現(xiàn)上卻會(huì)選擇 B 樹或 B+ 樹而不用二叉搜索樹,為什么呢?

這就涉及到數(shù)據(jù)庫(kù)的存儲(chǔ)介質(zhì)了,數(shù)據(jù)庫(kù)的數(shù)據(jù)和索引都是存放在磁盤,并且是 InnoDB 引擎是以頁(yè)為基本單位管理磁盤的,一頁(yè)一般為 16 KB。AVL 或紅黑樹搜索效率雖然非常高,但是同樣數(shù)據(jù)項(xiàng),它也會(huì)比 B、B+ 樹更高,高就意味著平均來說會(huì)訪問更多的節(jié)點(diǎn),即磁盤IO次數(shù)!

根據(jù) Google 工程師 Jeff Dean 的統(tǒng)計(jì),訪問內(nèi)存數(shù)據(jù)耗時(shí)大概在 100 ns,訪問磁盤則是 10,000,000 ns。

所以表面上來看我們使用 B、B+ 樹沒有 二叉查找樹效率高,但是實(shí)際上由于 B、B+ 樹降低了樹高,減少了磁盤 IO 次數(shù),反而大大提升了速度。

這也告訴我們,沒有絕對(duì)的快和慢,系統(tǒng)分析要抓主要矛盾,先分析出決定系統(tǒng)瓶頸的到底是什么,然后才是針對(duì)瓶頸的優(yōu)化。

其實(shí)關(guān)于索引想寫的也還有很多,但還是受限于篇幅,以后再單獨(dú)寫。

先把我認(rèn)為索引必知必會(huì)的知識(shí)列出來,大家可以查漏補(bǔ)缺:

  • 主鍵索引和普通索引,以及它們之間的區(qū)別

  • 最左前綴匹配原則

  • 索引下推

  • 覆蓋索引、聯(lián)合索引

7.2 讀寫分離

一般業(yè)務(wù)剛上線的時(shí)候,直接使用單機(jī)數(shù)據(jù)庫(kù)就夠了,但是隨著用戶量上來之后,系統(tǒng)就面臨著大量的寫操作和讀操作,單機(jī)數(shù)據(jù)庫(kù)處理能力有限,容易成為系統(tǒng)瓶頸。

由于存在讀寫鎖沖突,并且很多大型互聯(lián)網(wǎng)業(yè)務(wù)往往讀多寫少,讀操作會(huì)首先成為數(shù)據(jù)庫(kù)瓶頸,我們希望消除讀寫鎖沖突從而提升數(shù)據(jù)庫(kù)整體的讀寫能力。

那么就需要采用讀寫分離的數(shù)據(jù)庫(kù)集群方式,一主多從,主庫(kù)會(huì)同步數(shù)據(jù)到從庫(kù)。寫操作都到主庫(kù),讀操作都去從庫(kù)。

讀寫分離

讀寫分離到之后就避免了讀寫鎖爭(zhēng)用,這里解釋一下,什么叫讀寫鎖爭(zhēng)用:

MySQL 中有兩種鎖:

  • 排它鎖( X 鎖): 事務(wù) T 對(duì)數(shù)據(jù) A 加上 X 鎖時(shí),只允許事務(wù) T 讀取和修改數(shù)據(jù) A。

  • 共享鎖( S 鎖): 事務(wù) T 對(duì)數(shù)據(jù) A 加上 S 鎖時(shí),其他事務(wù)只能再對(duì)數(shù)據(jù) A 加 S 鎖,而不能加 X 鎖,直到 T 釋放 A 上的 S 鎖。

讀寫分離解決問題的同時(shí)也會(huì)帶來新問題,比如主庫(kù)和從庫(kù)數(shù)據(jù)不一致

MySQL 的主從同步依賴于 binlog,binlog(二進(jìn)制日志)是 MySQL Server 層維護(hù)的一種二進(jìn)制日志,是獨(dú)立于具體的存儲(chǔ)引擎。它主要存儲(chǔ)對(duì)數(shù)據(jù)庫(kù)更新(insert、delete、update)的 SQL 語(yǔ)句,由于記錄了完整的 SQL 更新信息,所以 binlog 是可以用來數(shù)據(jù)恢復(fù)和主從同步復(fù)制的。

從庫(kù)從主庫(kù)拉取 binlog 然后依次執(zhí)行其中的 SQL 即可達(dá)到復(fù)制主庫(kù)的目的,由于從庫(kù)拉取 binlog 存在網(wǎng)絡(luò)延遲等,所以主從數(shù)據(jù)存在延遲問題。

那么這里就要看業(yè)務(wù)是否允許短時(shí)間內(nèi)的數(shù)據(jù)不一致,如果不能容忍,那么可以通過如果讀從庫(kù)沒獲取到數(shù)據(jù)就去主庫(kù)讀一次來解決。

7.3 分庫(kù)分表

如果用戶越來越多,寫請(qǐng)求暴漲,對(duì)于上面的單 Master 節(jié)點(diǎn)肯定扛不住,那么該怎么辦呢?多加幾個(gè) Master?不行,這樣會(huì)帶來更多的數(shù)據(jù)不一致的問題,增加系統(tǒng)的復(fù)雜度。那該怎么辦?就只能對(duì)庫(kù)表進(jìn)行拆分了。

常見的拆分類型有垂直拆分和水平拆分。

考慮拼夕夕電商系統(tǒng),一般有 訂單表、用戶表、支付表、商品表、商家表等, 最初這些表都在一個(gè)數(shù)據(jù)庫(kù)里。
后來隨著砍一刀帶來的海量用戶,拼夕夕后臺(tái)扛不住了! 于是緊急從阿貍粑粑那里挖來了幾個(gè) P8、P9 大佬對(duì)系統(tǒng)進(jìn)行重構(gòu)。

  1. P9 大佬第一步先對(duì)數(shù)據(jù)庫(kù)進(jìn)行垂直分庫(kù),
    根據(jù)業(yè)務(wù)關(guān)聯(lián)性強(qiáng)弱,將它們分到不同的數(shù)據(jù)庫(kù), 比如訂單庫(kù),商家?guī)?、支付?kù)、用戶庫(kù)。

  2. 第二步是對(duì)一些大表進(jìn)行垂直分表,將一個(gè)表按照字段分成多表,每個(gè)表存儲(chǔ)其中一部分字段。 比如商品詳情表可能最初包含了幾十個(gè)字段,但是往往最多訪問的是商品名稱、價(jià)格、產(chǎn)地、圖片、介紹等信息,所以我們將不常訪問的字段單獨(dú)拆成一個(gè)表。

  • 由于垂直分庫(kù)已經(jīng)按照業(yè)務(wù)關(guān)聯(lián)切分到了最小粒度,數(shù)據(jù)量任然非常大,P9 大佬開始水平分庫(kù),比如可以把訂單庫(kù)分為訂單1庫(kù)、訂單2庫(kù)、訂單3庫(kù)…… 那么如何決定某個(gè)訂單放在哪個(gè)訂單庫(kù)呢?可以考慮對(duì)主鍵通過哈希算法計(jì)算放在哪個(gè)庫(kù)。

  • 分完庫(kù),單表數(shù)據(jù)量任然很大,查詢起來非常慢,P9 大佬決定按日或者按月將訂單分表,叫做日表、月表。

分庫(kù)分表同時(shí)會(huì)帶來一些問題,比如平時(shí)單庫(kù)單表使用的主鍵自增特性將作廢,因?yàn)槟硞€(gè)分區(qū)庫(kù)表生成的主鍵無法保證全局唯一,這就需要引入全局 UUID 服務(wù)了。

經(jīng)過一番大刀闊斧的重構(gòu),拼夕夕恢復(fù)了往日的活力,大家又可以愉快的在上面互相砍一刀了。

(分庫(kù)分表會(huì)引入很多問題,并沒有一一介紹,這里只是為了講解什么是分庫(kù)分表)


八、具體技法

8.1 零拷貝

高性能的服務(wù)器應(yīng)當(dāng)避免不必要數(shù)據(jù)復(fù)制,特別是在用戶空間和內(nèi)核空間之間的數(shù)據(jù)復(fù)制。 比如 HTTP 靜態(tài)服務(wù)器發(fā)送靜態(tài)文件的時(shí)候,一般我們會(huì)這樣寫:

發(fā)送文件

如果了解 Linux IO 的話就知道這個(gè)過程包含了內(nèi)核空間和用戶空間之間的多次拷貝:

IO示意圖

內(nèi)核空間和用戶空間之間數(shù)據(jù)拷貝需要 CPU 親自完成,但是對(duì)于這類數(shù)據(jù)不需要在用戶空間進(jìn)行處理的程序來說,這樣的兩次拷貝顯然是浪費(fèi)。什么叫 「不需要在用戶空間進(jìn)行處理」?

比如 FTP 或者 HTTP 靜態(tài)服務(wù)器,它們的作用只是將文件從磁盤發(fā)送到網(wǎng)絡(luò),不需要在中途對(duì)數(shù)據(jù)進(jìn)行編解碼之類的計(jì)算操作。

如果能夠直接將數(shù)據(jù)在內(nèi)核緩存之間移動(dòng),那么除了減少拷貝次數(shù)以外,還能避免內(nèi)核態(tài)和用戶態(tài)之間的上下文切換。

而這正是零拷貝(Zero copy)干的事,主要就是利用各種零拷貝技術(shù),減少不必要的數(shù)據(jù)拷貝,將 CPU 從數(shù)據(jù)拷貝這樣簡(jiǎn)單的任務(wù)解脫出來,讓 CPU 專注于別的任務(wù)。

常用的零拷貝技術(shù):

  1. mmap

    mmap通過內(nèi)存映射,將文件映射到內(nèi)核緩沖區(qū),同時(shí),用戶空間可以共享內(nèi)核空間的數(shù)據(jù)。這樣,在進(jìn)行網(wǎng)絡(luò)傳輸時(shí),就可以減少內(nèi)核空間到用戶空間的拷貝次數(shù)。

mmap

  1. sendfile

    sendfile是 Linux2.1 版本提供的,數(shù)據(jù)不經(jīng)過用戶態(tài),直接從頁(yè)緩存拷貝到 socket 緩存,同時(shí)由于和用戶態(tài)完全無關(guān),就減少了一次上下文切換。

    在 Linux 2.4 版本,對(duì) sendfile 進(jìn)行了優(yōu)化,直接通過 DMA 將磁盤文件數(shù)據(jù)讀取到 socket 緩存,真正實(shí)現(xiàn)了 ”0” 拷貝。前面 mmap 和 2.1 版本的 sendfile 實(shí)際上只是消除了用戶空間和內(nèi)核空間之間拷貝,而頁(yè)緩存和 socket 緩存之間的拷貝依然存在。

8.2 無鎖化

在多線程環(huán)境下,為了避免 競(jìng)態(tài)條件(race condition), 我們通常會(huì)采用加鎖來進(jìn)行并發(fā)控制,鎖的代價(jià)也是比較高的,鎖會(huì)導(dǎo)致上線文切換,甚至被掛起直到鎖被釋放。

基于硬件提供的原子操作 CAS(Compare And Swap) 實(shí)現(xiàn)一些高性能無鎖的數(shù)據(jù)結(jié)構(gòu),比如無鎖隊(duì)列,可以在保證并發(fā)安全的情況下,提供更高的性能。

首先需要理解什么是 CAS,CAS 有三個(gè)操作數(shù),內(nèi)存里當(dāng)前值M,預(yù)期值 E,修改的新值 N,CAS 的語(yǔ)義就是:

如果當(dāng)前值等于預(yù)期值,則將內(nèi)存修改為新值,否則不做任何操作。

用 C 語(yǔ)言來表達(dá)就是:

CAS

注意,上面 CAS 函數(shù)實(shí)際上是一條原子指令,那么是如何用的呢?

假設(shè)我需要實(shí)現(xiàn)這樣一個(gè)功能:

對(duì)一個(gè)全局變量 global 在兩個(gè)不同線程分別對(duì)它加 100 次,這里多線程訪問一個(gè)全局變量存在 race condition,所以我們需要采用線程同步操作,下面我分別用鎖和CAS的方法來實(shí)現(xiàn)這個(gè)功能。

CAS和鎖示范

通過使用原子操作大大降低了鎖沖突的可能性,提高了程序的性能。

除了 CAS,還有一些硬件原子指令:

  • Fetch-And-Add,對(duì)變量原子性 + 1

  • Test-And-Set,這是各種鎖算法的核心,在  AT&T/GNU 匯編語(yǔ)法下,叫 xchg 指令,我會(huì)單獨(dú)寫一篇如何使用 xchg 實(shí)現(xiàn)各種鎖。

8.3 序列化與反序列化

先看看維基百科怎么定義的序列化:

In computing, serialization (US spelling) or serialisation (UK spelling) is the process of translating a data structure or object state into a format that can be stored (for example, in a file or memory data buffer) or transmitted (for example, across a computer network) and reconstructed later (possibly in a different computer environment). When the resulting series of bits is reread according to the serialization format, it can be used to create a semantically identical clone of the original object. For many complex objects, such as those that make extensive use of references, this process is not straightforward. Serialization of object-oriented objects does not include any of their associated methods with which they were previously linked.

我相信你大概率沒有看完上面的英文描述,其實(shí)我也不愛看英文資料,總覺得很慢,但是計(jì)算機(jī)領(lǐng)域一手的學(xué)習(xí)資料都是美帝那邊的,所以沒辦法,必須逼自己去試著讀一些英文的資料。

實(shí)際上也沒有那么難,熟悉常用的幾百個(gè)專業(yè)名詞,句子都是非常簡(jiǎn)單的一些從句。沒看的話,再倒回去看看?

這里我就不做翻譯了,主要是水平太低,估計(jì)做到「信達(dá)雅」的信都很難。

扯遠(yuǎn)了,還是回到序列化來。

所有的編程一定是圍繞數(shù)據(jù)展開的,而數(shù)據(jù)呈現(xiàn)形式往往是結(jié)構(gòu)化的,比如結(jié)構(gòu)體(Struct)、類(Class)。 但是當(dāng)我們 通過網(wǎng)絡(luò)、磁盤等傳輸、存儲(chǔ)數(shù)據(jù)的時(shí)候卻要求是二進(jìn)制流。 比如 TCP 連接,它提供給上層應(yīng)用的是面向連接的可靠字節(jié)流服務(wù)。那么如何將這些結(jié)構(gòu)體和類轉(zhuǎn)化為可存儲(chǔ)和可傳輸?shù)淖止?jié)流呢?這就是序列化要干的事情,反之,從字節(jié)流如何恢復(fù)為結(jié)構(gòu)化的數(shù)據(jù)就是反序列化。

序列化解決了對(duì)象持久化和跨網(wǎng)絡(luò)數(shù)據(jù)交換的問題。

序列化一般按照序列化后的結(jié)果是否可讀,可分為以下兩類:

  • 文本類型:

    如 JSON、XML,這些類型可讀性非常好,是自解釋的。也常常用在前后端數(shù)據(jù)交互上,因?yàn)榻涌谡{(diào)試,可讀性高非常方便。但是缺點(diǎn)就是信息密度低,序列化后占用空間大。

  • 二進(jìn)制類型

    如 Protocol Buffer、Thrift等,這些類型采用二進(jìn)制編碼,數(shù)據(jù)組織得更加緊湊,信息密度高,占用空間小,但是帶來的問題就是基本不可讀。

還有 Java 、Go 這類語(yǔ)言內(nèi)置了序列化方式,比如在 Java 里實(shí)現(xiàn)了 Serializable 接口即表示該對(duì)象可序列化。

說到這讓我想起了大一寫的的兩個(gè)程序,一個(gè)是用剛 C 語(yǔ)言寫的公交管理系統(tǒng),當(dāng)時(shí)需要將公交線路、站點(diǎn)信息持久化保存,當(dāng)時(shí)的方案就是每個(gè)公交線路寫在一行,用 "|"分割信息,比如:

5|6:00-22:00|大學(xué)城|南山站|北京站
123|6:30-23:00|南湖大道|茶山劉|世界

第一列就是線路編號(hào)、第二項(xiàng)是發(fā)車時(shí)間、后面就是途徑的站點(diǎn)。是不是非常原始?實(shí)際上這也是一種序列化方式,只是效率很低,也不通用。而且存在一個(gè)問題就是如果信息中包含 “|”怎么辦?當(dāng)然是用轉(zhuǎn)義。

第二個(gè)程序是用 Java 寫的網(wǎng)絡(luò)五子棋,當(dāng)時(shí)需要通過網(wǎng)絡(luò)傳輸表示棋子位置的對(duì)象,查了一圈最后發(fā)現(xiàn)只需要實(shí)現(xiàn) Serializable 接口,自己什么都不用干,就能自己完成對(duì)象的序列化,然后通過網(wǎng)絡(luò)傳輸后反序列化。當(dāng)時(shí)哪懂得這就叫序列化,只覺得牛逼、神奇!

最后完成了一個(gè)可以網(wǎng)絡(luò)五子棋,拉著隔壁室友一起玩。。。真的是成就感滿滿哈哈哈。

說來在編程方面,已經(jīng)很久沒有這樣的成就感了。


總結(jié)

這篇文章主要是粗淺的介紹了一些系統(tǒng)設(shè)計(jì)、系統(tǒng)優(yōu)化的套路和最佳實(shí)踐。

不知道你發(fā)現(xiàn)沒有,從緩存到消息隊(duì)列、CAS……,很多看起來很牛逼的架構(gòu)設(shè)計(jì)其實(shí)都來源于操作系統(tǒng)、體系結(jié)構(gòu)。

所以我非常熱衷學(xué)習(xí)一些底層的基礎(chǔ)知識(shí),這些看似古老的技術(shù)是經(jīng)過時(shí)間洗禮留下來的好東西。現(xiàn)在很多的新技術(shù)、框架看似非常厲害,實(shí)則不少都是新瓶裝舊酒,每幾年又會(huì)被淘汰一批。


絮叨

大家好,我是小林,一個(gè)專為大家圖解的工具人,如果覺得文章對(duì)你有幫助,歡迎分享給你的朋友,我們下次見!

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉