成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

限流,永遠都不是一件簡單的事!

網(wǎng)絡(luò) 通信技術(shù)
隨著微服務(wù)的流行,服務(wù)之間的穩(wěn)定性變得越發(fā)重要,往往我們會花很多經(jīng)歷在維護服務(wù)的穩(wěn)定性上,限流和熔斷降級是我們最常用的兩個手段。前段時間在群里有些小伙伴對限流的使用些疑問,再加上最近公司大促也做了限流相關(guān)的事,所以在這里總結(jié)一下寫寫自己對限流的一些看法。

[[354146]]

本文轉(zhuǎn)載自微信公眾號「 咖啡拿鐵」,作者 咖啡拿鐵。轉(zhuǎn)載本文請聯(lián)系 咖啡拿鐵公眾號。

 背景

隨著微服務(wù)的流行,服務(wù)之間的穩(wěn)定性變得越發(fā)重要,往往我們會花很多經(jīng)歷在維護服務(wù)的穩(wěn)定性上,限流和熔斷降級是我們最常用的兩個手段。前段時間在群里有些小伙伴對限流的使用些疑問,再加上最近公司大促也做了限流相關(guān)的事,所以在這里總結(jié)一下寫寫自己對限流的一些看法。

剛才說了限流是我們保證服務(wù)穩(wěn)定性的手段之一,但是他并不是所有場景的穩(wěn)定性都能保證,和他名字一樣他只能在大流量或者突發(fā)流量的場景下才能發(fā)揮出自己的作用。比如我們的系統(tǒng)最高支持100QPS,但是突然有1000QPS請求打了進來,可能這個時候系統(tǒng)就會直接掛掉,導(dǎo)致后面一個請求都處理不了,但是如果我們有限流的手段,無論他有多大的QPS,我們都只處理100QPS的請求,其他請求都直接拒絕掉,雖然有900的QPS的請求我們拒絕掉了,但是我們的系統(tǒng)沒有掛掉,我們系統(tǒng)仍然可以不斷的處理后續(xù)的請求,這個是我們所期望的。有同學(xué)可能會說,現(xiàn)在都上的云了,服務(wù)的動態(tài)伸縮應(yīng)該是特別簡單的吧,如果我們發(fā)現(xiàn)流量特別大的時候,自動擴容機器到可以支撐目標(biāo)QPS那不就不需要限流了嗎?其實有這個想法的同學(xué)應(yīng)該還挺多的,有些同學(xué)可能被一些吹牛的文章給唬到了,所以才會這么想,這個想法在特別理想化的時候是可以實現(xiàn)的,但是在現(xiàn)實中其實有下面幾個問題:

  • 擴容是需要時間。擴容簡單來說就是搞一個新的機器,然后重新發(fā)布代碼,做java的同學(xué)應(yīng)該是知道發(fā)布成功一個代碼的時間一般不是以秒級計算,而是以分鐘級別計算,有時候你擴容完成,說不定流量尖峰都過去了。
  • 擴容到多少是個特別復(fù)雜的問題。擴容幾臺機器這個是比較復(fù)雜的,需要大量的壓測計算,以及整條鏈路上的一個擴容,如果擴容了你這邊的機器之后,其他團隊的機器沒有擴容可能最后還是有瓶頸這個也是一個問題。

所以單純的擴容是解決不了這個問題的,限流仍然是我們必須掌握的技能!

基本原理

想要掌握好限流,就需要先掌握他的一些基本算法,限流的算法基本上分為三種,計數(shù)器,漏斗,令牌桶,其他的一些都是在這些基礎(chǔ)上進行演變而來。

計數(shù)器算法

首先我們來說一下計數(shù)器算法,這個算法比較簡單粗暴,我們只需要一個累加變量,然后每隔一秒鐘去刷新這個累加變量,然后再判斷這個累加變量是否大于我們的最大QPS。

  1. int curQps = 0; 
  2.     long lastTime = System.currentTimeMillis(); 
  3.     int maxQps = 100; 
  4.     Object lock = new Object(); 
  5.     boolean check(){ 
  6.         synchronized (lock){ 
  7.             long now = System.currentTimeMillis(); 
  8.             if (now - lastTime > 1000){ 
  9.                 lastTime = now; 
  10.                 curQps = 0; 
  11.             } 
  12.             curQps++; 
  13.             if (curQps > maxQps){ 
  14.                 return false
  15.             } 
  16.         } 
  17.         return true
  18.     } 

這個代碼比較簡單,我們定義了當(dāng)前的qps,以及上一次刷新累加變量的時間,還有我們的最大qps和我們的lock鎖,我們每次檢查的時候,都需要判斷是否需要刷新,如果需要刷新那么需要把時間和qps都進行重置,然后再進行qps的累加判斷。

這個算法因為太簡單了所以帶來的問題也是特別明顯,如果我們最大的qps是100,在0.99秒的時候來了100個請求,然后在1.01秒的時候又來了100個請求,這個是可以通過我們的程序的,但是我們其實在0.03秒之內(nèi)通過了200個請求,這個肯定不符合我們的預(yù)期,因為很有可能這200個請求直接就會將我們機器給打掛。

滑動窗口計數(shù)器

為了解決上面的臨界的問題,我們這里可以使用滑動窗口來解決這個問題:

如上圖所示,我們將1s的普通計數(shù)器,分成了5個200ms,我們統(tǒng)計的當(dāng)前qps都需要統(tǒng)計最近的5個窗口的所有qps,再回到剛才的問題,0.99秒和1.01秒其實都在我們的最近5個窗口之內(nèi),所以這里不會出現(xiàn)剛才的臨界的突刺問題。

其實換個角度想,我們普通的計數(shù)器其實就是窗口數(shù)量為1的滑動窗口計數(shù)器,只要我們分的窗口越多,我們使用計數(shù)器方案的時候統(tǒng)計就會越精確,但是相對來說維護的窗口的成本就會增加,等會我們介紹sentinel的時候會詳細介紹他是怎么實現(xiàn)滑動窗口計數(shù)的。

漏斗算法

解決計數(shù)器中臨界的突刺問題也可以通過漏斗算法來實現(xiàn),如下圖所示:

在漏斗算法中我們需要關(guān)注漏桶和勻速流出,不論流量有多大都會先到漏桶中,然后以均勻的速度流出。如何在代碼中實現(xiàn)這個勻速呢?比如我們想讓勻速為100q/s,那么我們可以得到每流出一個流量需要消耗10ms,類似一個隊列,每隔10ms從隊列頭部取出流量進行放行,而我們的隊列也就是漏桶,當(dāng)流量大于隊列的長度的時候,我們就可以拒絕超出的部分。

漏斗算法同樣的也有一定的缺點:無法應(yīng)對突發(fā)流量(和上面的臨界突刺不一樣,不要混淆)。比如一瞬間來了100個請求,在漏桶算法中只能一個一個的過去,當(dāng)最后一個請求流出的時候時間已經(jīng)過了一秒了,所以漏斗算法比較適合請求到達比較均勻,需要嚴(yán)格控制請求速率的場景。

令牌桶算法

為了解決突發(fā)流量情況,我們可以使用令牌桶算法,如下圖所示:

這個圖上需要關(guān)注三個階段:

  • 生產(chǎn)令牌:我們在這里同樣的還是假設(shè)最大qps是100,那么我們從漏斗的每10ms過一個流量轉(zhuǎn)化成每10ms生產(chǎn)一個令牌,直到達到最大令牌。
  • 消耗令牌:我們每一個流量都會消耗令牌桶,這里的消耗的規(guī)則可以多變,既可以是簡單的每個流量消耗一個令牌,又可以是根據(jù)不同的流量數(shù)據(jù)包大小或者流量類型來進行不同的消耗規(guī)則,比如查詢的流量消耗1個令牌,寫入的流量消耗2個令牌。
  • 判斷是否通過:如果令牌桶足夠那么我們就允許流量通過,如果不足夠可以等待或者直接拒絕,這個就可以采用漏斗那種用隊列來控制。

單機限流

上面我們已經(jīng)介紹了限流的一些基本算法,我們把這些算法應(yīng)用到我們的分布式服務(wù)中又可以分為兩種,一個是單機限流,一個是集群限流。單機限流指的是每臺機器各自做自己的限流,互不影響。我們接下來看看單機限流怎么去實現(xiàn)呢?

guava

guava是谷歌開源的java核心工具庫,里面包括集合,緩存,并發(fā)等好用的工具,當(dāng)然也提供了我們這里所需要的的限流的工具,核心類就是RateLimiter。

  1. //  RateLimiter rateLimiter = RateLimiter.create(100, 500, TimeUnit.MILLISECONDS); 預(yù)熱的rateLimit 
  2.     RateLimiter rateLimiter = RateLimiter.create(100); // 簡單的rateLimit 
  3.     boolean limitResult = rateLimiter.tryAcquire(); 

使用方式比較簡單,如上面代碼所示,我們只需要構(gòu)建一個RateLimiter,然后再調(diào)用tryAcquire方法,如果返回為true代表我們此時流量通過,相反則被限流。在guava中RateLimiter也分為兩種,一個是普通的令牌桶算法的實現(xiàn),還有一個是帶有預(yù)熱的RateLimiter,可以讓我們令牌桶的釋放速度逐步增加直到最大,這個帶有預(yù)熱的在sentinel也有,這個可以在一些冷系統(tǒng)中比如數(shù)據(jù)庫連接池沒有完全填滿,還在不斷初始化的場景下使用。

在這里只簡單的介紹一下guava的令牌桶怎么去實現(xiàn)的:

普通的令牌桶創(chuàng)建了一個SmoothBursty的類,這個類也就是我們實現(xiàn)限流的關(guān)鍵,具體怎么做限流的在我們的tryAcquire中:

這里分為四步:

  • Step1: 加上一個同步鎖,需要注意一下這里在sentinel中并沒有加鎖這個環(huán)節(jié),在guava中是有這個的,后續(xù)也會將sentinel的一些問題。
  • Step2: 判斷是否能申請令牌桶,如果桶內(nèi)沒有足夠的令牌并且等待時間超過我們的timeout,這里我們就不進行申請了。
  • Step3: 申請令牌并獲取等待時間,在我們tryAcquire中的timeout參數(shù)就是就是我們的最大等待時間,如果我們只是調(diào)用tryAcquire(),不會出現(xiàn)等待,第二步的時候已經(jīng)快速失敗了。
  • Step4: sleep等待的時間。

扣除令牌的方法具體在reserverEarliestAvailable方法中:

這里雖然看起來過程比較多,但是如果我們只是調(diào)用tryAcquire(),就只需要關(guān)注兩個紅框:

  • Step1: 根據(jù)當(dāng)前最新時間發(fā)放token,在guava中沒有采用使用其他線程異步發(fā)放token的方式,把token的更新放在了我們每次調(diào)用限流方法中,這個設(shè)計可以值得學(xué)習(xí)一下,很多時候不一定需要異步線程去執(zhí)行也可以達到我們想要的目的,并且也沒有異步線程的復(fù)雜。
  • Step2: 扣除令牌,這里我們已經(jīng)在canAcquire中校驗過了,令牌一定能扣除成功。

guava的限流目前就提供了這兩種方式的限流,很多中間件或者業(yè)務(wù)服務(wù)都把guava的限流作為自己的工具,但是guava的方式比較局限,動態(tài)改變限流,以及更多策略的限流都不支持,所以我們接下來介紹一下sentinel。

sentinel

sentinel是阿里巴巴開源的分布式服務(wù)框架的輕量級流量控制框架,承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,他的核心是流量控制但是不局限于流量控制,還支持熔斷降級,監(jiān)控等等。

使用sentinel的限流稍微比guava復(fù)雜很多,下面寫了一個最簡單的代碼:

  1. String KEY = "test"
  2.         // ============== 初始化規(guī)則 ========= 
  3.         List<FlowRule> rules = new ArrayList<FlowRule>(); 
  4.         FlowRule rule1 = new FlowRule(); 
  5.         rule1.setResource(KEY); 
  6.         // set limit qps to 20 
  7.         rule1.setCount(20); 
  8.         rule1.setGrade(RuleConstant.FLOW_GRADE_QPS); 
  9.         rule1.setLimitApp("default"); 
  10.         rules.add(rule1); 
  11.         rule1.setControlBehavior(CONTROL_BEHAVIOR_DEFAULT); 
  12.         FlowRuleManager.loadRules(rules); 
  13.         // ================ 限流判定 =========== 
  14.         Entry entry = null
  15.  
  16.         try { 
  17.             entry = SphU.entry(KEY); 
  18.             // do something 
  19.  
  20.         } catch (BlockException e1) { 
  21.             // 限流會拋出BlockException 異常 
  22.         }finally { 
  23.             if (entry != null) { 
  24.                 entry.exit(); 
  25.             } 
  26.         } 
  • Step1:在sentinel中比較強調(diào)Resource這個概念,我們所保護的或者說所作用于都是基于Resource來說,所以我們首先需要確定我們的Resource的key,這里我們簡單的設(shè)置為test了。
  • Step2:然后我們初始化我們這個Resource的一個限流規(guī)則,我們這里選擇的是針對QPS限流并且策略選擇的是默認,這里默認的話就是使用的滑動窗口版的計數(shù)器,然后加載到全局的規(guī)則管理器里面,整個規(guī)則的設(shè)置和guava的差別比較大。
  • Step3: 在sentinel第二個比較重要的概念就是Entry,Entry表示一次資源操作,內(nèi)部會保存當(dāng)前invocation信息,在finally的時候需要對entry進行退出。我們執(zhí)行限流判定的時候?qū)嶋H上也就是獲取Entry,SphU.entry也就是我們執(zhí)行我們上面限流規(guī)則的關(guān)鍵,這里和guava不一樣如果被限流了,就會拋出BlockException,我們在進行限流的處理。

雖然sentinel的使用整體比guava復(fù)雜很多,但是算法的可選比guava的限流也多一點。

基于并發(fā)數(shù)(線程數(shù))

我們之前介紹的都是基于QPS的,在sentinel中提供了基于并發(fā)數(shù)的策略,效果類似于信號量隔離,當(dāng)我們需要讓業(yè)務(wù)線程池不被慢調(diào)用耗盡,我們就可以使用這種模式。

通常來說我們同一個服務(wù)提供的http接口都是使用的一個線程池,比如我們使用的tomcat-web服務(wù)器那么我們就會有個tomcat的業(yè)務(wù)線程池,如果在http中有兩個方法A和B,B的速度相對來說比較快,A的速度相對來說比較慢,如果大量的調(diào)用A這個方法,由于A的速度太慢,線程得不到釋放,有可能導(dǎo)致線程池被耗盡,另一個方法B就得不到線程。這個場景我們之前有遇到過直接導(dǎo)致整個服務(wù)所接收的請求全部被拒絕。有的同學(xué)說限制A的QPS不是就可以了嗎,要注意的是QPS是每秒的,如果我們這個A接口的耗時大于1s,那么下一波A來了之后QPS是要重新計算的。

基于這個就提供了基于并發(fā)數(shù)的限流,我們設(shè)置Grade為FLOW_GRADE_THREAD,就可以實現(xiàn)這個限流模式。

基于QPS

基于QPS的限流sentinel也提供了4種策略:

  • 默認策略:設(shè)置Behavior為CONTROL_BEHAVIOR_DEFAULT,這個模式是滑動窗口計數(shù)器模式。這種方式適用于對系統(tǒng)處理能力確切已知的情況下,比如通過壓測確定了系統(tǒng)的準(zhǔn)確水位時。
  • Warm Up:設(shè)置為Behavior為CONTROL_BEHAVIOR_WARM_UP,類似之前guava中介紹的warmup。預(yù)熱啟動方式。當(dāng)系統(tǒng)長期處于低水位的情況下,當(dāng)流量突然增加時,直接把系統(tǒng)拉升到高水位可能瞬間把系統(tǒng)壓垮。這個模式下QPS的曲線圖如下:

  • 勻速排隊:設(shè)置Behavior為CONTROL_BEHAVIOR_RATE_LIMITER,這個模式其實就是漏斗算法,優(yōu)缺點之前也講解過了
  • Warm Up + 勻速排隊:設(shè)置Behavior為CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER,之前warm up到高水位之后使用的是滑動窗口的算法限流,這個模式下繼續(xù)使用勻速排隊的算法。

基于調(diào)用關(guān)系

sentinel提供了更為復(fù)雜的一種限流,可以基于調(diào)用關(guān)系去做更為靈活的限流:

  • 根據(jù)調(diào)用方限流:調(diào)用方的限流使用比較復(fù)雜,需要調(diào)用ContextUtil.enter(resourceName, origin),origin就是我們的調(diào)用方標(biāo)識,然后在我們的rule設(shè)置參數(shù)的時候,對limitApp進行設(shè)置就可以進行對調(diào)用方的限流:
    • 設(shè)置為default,默認對所有調(diào)用方都限流。
    • 設(shè)置為{some_origin_name},代表對特定的調(diào)用者才限流。
    • 設(shè)置為other,會對配置的一個referResource參數(shù)代表的調(diào)用者除外的進行限流。

關(guān)聯(lián)流量控制:在sentinel中也支持,兩個有關(guān)聯(lián)的資源可以互相影響流量控制,比如有兩個接口都使用的是同一個資源,一個接口比較重要,另外一個接口不是那么重要,我們可以設(shè)置一個規(guī)則當(dāng)重要的接口大量訪問的時候,就可以對另外一個不重要接口進行限流,防止這個接口突然出現(xiàn)流量影響重要的接口。

sentinel的一些問題

sentinel雖然提供了這么多算法,但是也有一些問題:

  • 首先來說sentinel上手比較難,對比guava的兩行代碼來說,使用sentinel需要了解一些名詞,然后針對這些名詞再來使用,雖然sentinel提供了一些注解來幫助我們簡化使用,但是整體來說還是比guava要復(fù)雜。
  • sentinel有一定的運維成本,sentinel的使用往往需要搭建sentinel的server后臺,對比guava的開箱即用來說,有一定的運維成本。
  • sentinel的限流統(tǒng)計有一定的并發(fā)問題,在sentinel的源碼中是沒有加鎖的地方的,極端情況下如果qps限制的是10,如果有100個同時過限流的邏輯,這個時候都會通過,而guava不會發(fā)生這樣的情況。

這些問題基本上都是和guava的限流來比較的,畢竟sentinel的功能更多,付出的成本相對來說也會更多。

集群限流

之前說的所有限流都是單機限流,但是我們現(xiàn)在都是微服務(wù)集群的架構(gòu)模式,通常一個服務(wù)會有多臺機器,比如有一個訂單服務(wù),這個服務(wù)有10臺機器,那么我們想做整個集群限流到500QPS,我們應(yīng)該怎么去做呢?這個很簡單,直接每臺機器都限流50就好了,50*10就是500,但是在現(xiàn)實環(huán)境中會出現(xiàn)負載不均衡的情況,在微服務(wù)調(diào)用的時候負載均衡的算法多種多樣,比如同機房優(yōu)先,輪訓(xùn),隨機等算法,這些算法都有可能導(dǎo)致我們的負載不是特別的均衡,就會導(dǎo)致我們整個集群的QPS可能有沒有500,甚至在400的時候就被限流了,這個是我們真實場景中所遇到過的。既然單機限流有問題,那么我們應(yīng)該設(shè)計一個更加完善的集群限流的方案

Redis

這個方案不依賴限流的框架,我們整個集群使用同一個redis即可,需要自己封裝一下限流的邏輯,這里我們使用最簡單的計數(shù)器去設(shè)計,我們將我們的系統(tǒng)時間以秒為單位作為key,設(shè)置到redis里面(可以設(shè)置一定的過期時間用于空間清理),利用redis的int原子加法,每來一個請求都進行+1,然后再判斷當(dāng)前值是否超過我們限流的最大值。

redis的方案實現(xiàn)起來整體來說比較簡單,但是強依賴我們的系統(tǒng)時間,如果不同機器之間的系統(tǒng)時間有偏差限流就有可能不準(zhǔn)確。

sentinel

在sentinel中提供了集群的解決方案,這個對比其他的一些限流框架是比較有特色的。在sentinel中提供了兩種模式:

  • 獨立模式:限流服務(wù)作為單獨的server進行部署,如下圖所示,所有的應(yīng)用都向單獨部署的token-server進行獲取token,這種模式適用于跨服務(wù)之間的全局限流,比如下面圖中,A和B都會去token-server去拿,這個場景一般來說比較少,更多的還是服務(wù)內(nèi)集群的限流比較多。
  • 內(nèi)嵌模式:在內(nèi)嵌模式下,我們會把server部署到我們應(yīng)用實例中,我們也可以通過接口轉(zhuǎn)換我們的server-client身份,當(dāng)然我們可以自己引入一些zk的一些邏輯設(shè)置讓我們的leader去當(dāng)server,機器掛了也可以自動切換。這種比較適合同一個服務(wù)集群之間的限流,靈活性比較好,但是要注意的是大量的token-server的訪問也有可能影響我們自己的機器。

當(dāng)然sentinel也有一些兜底的策略,如果token-server掛了我們可以退化成我們單機限流的模式,不會影響我們正常的服務(wù)。

實戰(zhàn)

我們上面已經(jīng)介紹了很多限流的工具,但是很多同學(xué)對怎么去限流仍然比較迷惑。我們?nèi)绻麑σ粋€場景或者一個資源做限流的話有下面幾個點需要確認一下:

  • 什么地方去做限流
  • 限多少流
  • 怎么去選擇工具

什么地方去做限流

這個問題比較復(fù)雜,很多公司以及很多團隊的做法都不相同,在美團的時候搞了一波SOA,那個時候我記得所有的服務(wù)所有的接口都需要做限流,叫每個團隊去給接口評估一個合理的QPS上限,這樣做理論上來說是對的,我們每個接口都應(yīng)該給與一個上限,防止把整體系統(tǒng)拖垮,但是這樣做的成本是非常之高的,所以大部分公司還是選擇性的去做限流。

首先我們需要確定一些核心的接口,比如電商系統(tǒng)中的下單,支付,如果流量過大那么電商系統(tǒng)中的路徑就有問題,比如像對賬這種邊緣的接口(不影響核心路徑),我們可以不設(shè)置限流。

其次我們不一定只在接口層才做限流,很多時候我們直接在網(wǎng)關(guān)層把限流做了,防止流量進一步滲透到核心系統(tǒng)中。當(dāng)然前端也能做限流,當(dāng)前端捕獲到限流的錯誤碼之后,前端可以提示等待信息,這個其實也算是限流的一部分。其實當(dāng)限流越在下游觸發(fā)我們的資源的浪費就越大,因為在下游限流之前上游已經(jīng)做了很多工作了,如果這時候觸發(fā)限流那么之前的工作就會白費,如果涉及到一些回滾的工作還會加大我們的負擔(dān),所以對于限流來說應(yīng)該是越上層觸發(fā)越好。

限多少流

限多少流這個問題大部分的時候可能就是一個歷史經(jīng)驗值,我們可以通過日常的qps監(jiān)控圖,然后再在這個接觸上加一點冗余的QPS可能這個就是我們的限流了。但是有一個場景需要注意,那就是大促(這里指的是電商系統(tǒng)里面的場景,其他系統(tǒng)類比流量較高的場景)的時候,我們系統(tǒng)的流量就會突增,再也不是我們?nèi)粘5腝PS了,這種情況下,往往需要我們在大促之前給我們系統(tǒng)進行全鏈路壓測,壓測出一個合理的上限,然后限流就基于這個上限去設(shè)置。

怎么去選擇工具

一般來說大一點的互聯(lián)網(wǎng)公司都有自己的統(tǒng)一限流的工具這里直接采用就好。對于其他情況的話,如果沒有集群限流或者熔斷這些需求,我個人覺得選擇RateLimter是一個比較不錯的選擇,應(yīng)該其使用比較簡單,基本沒有學(xué)習(xí)成本,如果有其他的一些需求我個人覺得選擇sentinel,至于hytrix的話我個人不推薦使用,因為這個已經(jīng)不再維護了。

總結(jié)

限流雖然只有兩個字,但是真正要理解限流,做好限流,是一件非常不容易的事,對于我個人而已,這篇文章也只是一些淺薄的見識,如果大家有什么更好的意見可以關(guān)注我的公眾號留言進行討論。 

 

責(zé)任編輯:武曉燕 來源: 咖啡拿鐵
相關(guān)推薦

2024-12-10 08:34:28

2015-06-12 10:01:25

程序員代碼

2021-05-17 10:27:42

地址虛擬邏輯

2010-09-13 11:04:03

編程

2013-05-30 08:48:30

團隊

2021-05-16 15:49:12

數(shù)字化轉(zhuǎn)型IT技術(shù)

2020-11-18 14:13:48

手機iPhone三星

2021-04-29 16:00:54

數(shù)字化信息化IT項目

2016-01-22 11:51:36

測試浪費時間

2019-11-14 19:03:51

人工智能設(shè)計無人駕駛

2011-10-14 19:58:04

C語言

2015-11-13 11:15:40

SELinuxFedoraLinux

2014-10-29 15:04:05

觸控科技陳昊芝

2020-04-06 14:09:36

存儲閃存技術(shù)

2022-06-08 12:29:24

編程語言JavaPython

2022-04-28 23:19:58

元宇宙NFT數(shù)字資產(chǎn)

2020-01-10 14:56:54

存儲技術(shù)容器

2017-08-14 15:34:14

廣州

2011-06-30 11:23:32

Python

2017-07-12 10:25:17

Python微信itchat 包
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 四虎影院美女 | 美女操网站 | 久久国产成人 | 精品一区二区三区四区五区 | 国产97人人超碰caoprom | 91观看 | 91电影 | 国产精品视频一二三区 | 色在线看 | 一区二区三区av | 欧美不卡一区二区 | 91精品欧美久久久久久久 | 亚洲国产成人精品女人久久久 | 久久久久久久久久久久久91 | 中文字幕不卡在线观看 | 亚洲一区在线日韩在线深爱 | 精品国产一区二区三区性色av | 久草免费电影 | 欧美午夜视频 | 韩国精品一区 | 国产精品一区二区不卡 | 日韩在线欧美 | 日韩视频 中文字幕 | 国产精品污www一区二区三区 | 五月婷婷激情网 | www.788.com色淫免费 | 91精品国产91久久久久久 | 国产乱码精品1区2区3区 | 蜜桃视频一区二区三区 | 亚洲一区二区三区免费 | 九九热re| 中文字幕欧美一区二区 | 影视一区| 天天天久久久 | 国产精品国色综合久久 | 在线播放一区 | 日韩精品一区二区三区视频播放 | 亚洲精品视频一区二区三区 | 久草网站| 国产精品久久久久久一区二区三区 | 中文字幕精品一区 |