中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

外包兼職做圖的網(wǎng)站百度免費(fèi)推廣怎么操作

外包兼職做圖的網(wǎng)站,百度免費(fèi)推廣怎么操作,在線制作視頻網(wǎng)站,wordpress 文章插入環(huán)繞廣告前言 ? 在分布式系統(tǒng)中,當(dāng)不同進(jìn)程或線程一起訪問(wèn)共享資源時(shí),會(huì)造成資源爭(zhēng)搶,如果不加以控制的話,就會(huì)引發(fā)程序錯(cuò)亂。而分布式鎖它采用了一種互斥機(jī)制來(lái)防止線程或進(jìn)程間相互干擾,從而保證了數(shù)據(jù)的一致性。 常見(jiàn)的分…

前言

? 在分布式系統(tǒng)中,當(dāng)不同進(jìn)程或線程一起訪問(wèn)共享資源時(shí),會(huì)造成資源爭(zhēng)搶,如果不加以控制的話,就會(huì)引發(fā)程序錯(cuò)亂。而分布式鎖它采用了一種互斥機(jī)制來(lái)防止線程或進(jìn)程間相互干擾,從而保證了數(shù)據(jù)的一致性。

常見(jiàn)的分布式鎖實(shí)現(xiàn)方案

  • 基于 Redis 實(shí)現(xiàn)分布式鎖
  • 基于 Zookeeper 實(shí)現(xiàn)分布式鎖

介紹

? **Redission是一個(gè)基于Redis實(shí)現(xiàn)的Java分布式對(duì)象存儲(chǔ)和緩存框架。它提供了豐富的分布式數(shù)據(jù)結(jié)構(gòu)和服務(wù)。**例如:分布式鎖、分布式隊(duì)列、分布式Rate Limiter等。

分布式鎖的特點(diǎn)

  • 互斥性是分布式鎖的重要特點(diǎn),在任意時(shí)刻,只有一個(gè)線程能夠持有鎖
  • **鎖的超時(shí)時(shí)間。**一個(gè)線程在持鎖期間掛掉了而沒(méi)主動(dòng)釋放鎖,此時(shí)通過(guò)超時(shí)時(shí)間來(lái)保證該線程在超時(shí)后可以釋放鎖,這樣其他線程才可以繼續(xù)獲取鎖;
  • 加鎖和解鎖必須是由同一個(gè)線程來(lái)設(shè)置
  • Redis 是緩存型數(shù)據(jù)庫(kù),擁有很高的性能,因此加鎖和釋放鎖開(kāi)銷較小,并且能夠很輕易地實(shí)現(xiàn)分布式鎖。

特性

高性能

? Redission是基于Redis的,因此它繼承了Redis的高性能和低延遲的特性。同時(shí),它采用了Netty的NIO框架,能夠并發(fā)地處理大量的請(qǐng)求,使得應(yīng)用程序的響應(yīng)速度得到了極大的提升。

易用性

? Redission提供了豐富的API和方法,同時(shí)還提供了文檔和示例,讓開(kāi)發(fā)者易于上手和使用。此外,它支持自動(dòng)配置和靈活的配置方式,使得開(kāi)發(fā)者可以根據(jù)自己的需求進(jìn)行配置和調(diào)整。

可擴(kuò)展性

? Redission的分布式架構(gòu)使得它支持水平擴(kuò)展,可以將數(shù)據(jù)和請(qǐng)求分散到更多的節(jié)點(diǎn)上進(jìn)行處理。這也使得它具備了更好的容錯(cuò)能力和可靠性。

常用場(chǎng)景

緩存

? Redission支持不同的數(shù)據(jù)存儲(chǔ)類型,例如:String、List、Set、Map、BloomFilter、HyperLogLog等,它可以將這些數(shù)據(jù)存儲(chǔ)在Redis中,以實(shí)現(xiàn)數(shù)據(jù)緩存的功能,從而提高應(yīng)用程序的性能和響應(yīng)速度。

分布式鎖

? Redission提供了可重入鎖、公平鎖等常用的分布式鎖,還支持異步執(zhí)行、鎖的自動(dòng)續(xù)期、鎖的等待等特性。

分布式隊(duì)列

? Redission提供了分布式隊(duì)列的實(shí)現(xiàn),我們可以在不同的節(jié)點(diǎn)之間快速、可靠地實(shí)現(xiàn)任務(wù)的傳遞和處理。

Redis分布式鎖命令

常用命令

? Redis 分布式鎖常用命令如下所示:

  • SETNX key val:僅當(dāng)key不存在時(shí),設(shè)置一個(gè) key 為 value 的字符串,返回1;若 key 存在,設(shè)置失敗,返回 0;
  • Expire key timeout:為 key 設(shè)置一個(gè)超時(shí)時(shí)間,以 second 秒為單位,超過(guò)這個(gè)時(shí)間鎖會(huì)自動(dòng)釋放,避免死鎖;
  • DEL key:刪除 key。
    **上述 SETNX 命令相當(dāng)于搶占鎖操作,EXPIRE 是為避免出現(xiàn)意外用來(lái)設(shè)置鎖的過(guò)期時(shí)間,也就是說(shuō)到了指定的過(guò)期時(shí)間,該客戶端必須讓出鎖,讓其他客戶端去持有。**

? 但還有一種情況,如果在 SETNX 和 EXPIRE 之間服務(wù)器進(jìn)程突然掛掉,也就是還未設(shè)置過(guò)期時(shí)間,這樣就會(huì)導(dǎo)致 EXPIRE 執(zhí)行不了,因此還是會(huì)造成“死鎖”的問(wèn)題。為了避免這個(gè)問(wèn)題,Redis 作者在 2.6.12 版本后,對(duì) SET 命令參數(shù)做了擴(kuò)展,使它可以同時(shí)執(zhí)行 SETNX 和 EXPIRE 命令,從而解決了死鎖的問(wèn)題。

直接使用 SET 命令實(shí)現(xiàn),語(yǔ)法格式如下:

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]  
  • EX second:設(shè)置鍵的過(guò)期時(shí)間為 second 秒。 SET key value EX second 效果等同于 SETEX key second value 。
  • PX millisecond:設(shè)置鍵的過(guò)期時(shí)間為毫秒。SET key value PX millisecond 效果等同于 PSETEX key millisecondvalue 。
  • NX:只在鍵不存在時(shí),才對(duì)鍵進(jìn)行設(shè)置操作。 SET key value NX 效果等同于 SETNX key value 。
  • XX:只在鍵已經(jīng)存在時(shí),才對(duì)鍵進(jìn)行設(shè)置操作。

原理

使用

使用redisson實(shí)現(xiàn)分布式鎖的操作步驟,三部曲

  • 第一步: 獲取鎖 RLock redissonLock = redisson.getLock(lockKey);
  • 第二步: 加鎖,實(shí)現(xiàn)鎖續(xù)命功能 redissonLock.lock();
  • 第三步: 釋放鎖 redissonLock.unlock();

在這里插入圖片描述

Redis 實(shí)現(xiàn)分布式鎖主要步驟

  1. 指定一個(gè) key 作為鎖標(biāo)記,存入 Redis 中,指定一個(gè) 唯一的用戶標(biāo)識(shí) 作為 value。
  2. 當(dāng) key 不存在時(shí)才能設(shè)置值,確保同一時(shí)間只有一個(gè)客戶端進(jìn)程獲得鎖,滿足 互斥性 特性。
  3. 設(shè)置一個(gè)過(guò)期時(shí)間,防止因系統(tǒng)異常導(dǎo)致沒(méi)能刪除這個(gè) key,滿足 防死鎖 特性。
  4. 當(dāng)處理完業(yè)務(wù)之后需要清除這個(gè) key 來(lái)釋放鎖,清除 key 時(shí)需要校驗(yàn) value 值,需要滿足 只有加鎖的人才能釋放鎖 。

注意:

? 以上實(shí)現(xiàn)步驟考慮到了使用分布式鎖需要考慮的互斥性、防死鎖、加鎖和解鎖必須為同一個(gè)進(jìn)程等問(wèn)題,但是鎖的續(xù)期無(wú)法實(shí)現(xiàn)。所以通常情況都是采用 Redisson 實(shí)現(xiàn) Redis 的分布式鎖,借助 Redisson 的 WatchDog 機(jī)制 能夠很好的解決鎖續(xù)期的問(wèn)題。

? Watch Dog 機(jī)制其實(shí)就是一個(gè)后臺(tái)定時(shí)任務(wù)線程,獲取鎖成功之后,會(huì)將持有鎖的線程放入到一個(gè) RedissonLock.EXPIRATION_RENEWAL_MAP里面,然后每隔 10 秒 (internalLockLeaseTime / 3) 檢查一下,如果客戶端 1 還持有鎖 key(判斷客戶端是否還持有 key,其實(shí)就是遍歷 EXPIRATION_RENEWAL_MAP 里面線程 id 然后根據(jù)線程 id 去 Redis 中查,如果存在就會(huì)延長(zhǎng) key 的時(shí)間),那么就會(huì)不斷的延長(zhǎng)鎖 key 的生存時(shí)間。

Redisson的鎖機(jī)制

1)加鎖機(jī)制

? 加鎖其實(shí)是通過(guò)一段 lua 腳本實(shí)現(xiàn)的。這里 KEYS[1] 代表的是你加鎖的 key,比如你自己設(shè)置了加鎖的那個(gè)鎖 key 就是 “myLock”。

if (redis.call('exists', KEYS[1]) == 0) then " +"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +"redis.call('pexpire', KEYS[1], ARGV[1]); " +"return nil; " +"end; " +
"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +"redis.call('pexpire', KEYS[1], ARGV[1]); " +"return nil; " +"end; " +
"return redis.call('pttl', KEYS[1]);"

? ARGV[1] 代表的是鎖 key 的默認(rèn)生存時(shí)間,默認(rèn) 30 秒。ARGV[2] 代表的是加鎖的客戶端的 ID,類似于下面這樣:285475da-9152-4c83-822a-67ee2f116a79:52。至于最后面的一個(gè) 1 是為了后面可重入做的計(jì)數(shù)統(tǒng)計(jì).

? 第一段 if 判斷語(yǔ)句,就是用 exists myLock 命令判斷一下,如果你要加鎖的那個(gè)鎖 key 不存在的話,你就進(jìn)行加鎖。如何加鎖呢?使用 hincrby 命令設(shè)置一個(gè) hash 結(jié)構(gòu)。接著會(huì)執(zhí)行 pexpire myLock 30000 命令,設(shè)置 myLock 這個(gè)鎖 key 的生存時(shí)間是 30 秒。到此為止,加鎖完成。

2)鎖互斥機(jī)制

? 第二個(gè) if 判斷,判斷一下,myLock 鎖 key 的 hash 數(shù)據(jù)結(jié)構(gòu)中,是否包含客戶端 2 的 ID,這里明顯不是,因?yàn)槟抢锇氖强蛻舳?1 的 ID。所以,客戶端 2 會(huì)執(zhí)行:

return redis.call('pttl', KEYS[1]);

返回的一個(gè)數(shù)字,這個(gè)數(shù)字代表了 myLock 這個(gè)鎖 key 的剩余生存時(shí)間。

3)Watch dog 機(jī)制

? 主要用于鎖續(xù)費(fèi)服務(wù)。只要客戶端 1 一旦加鎖成功,就會(huì)啟動(dòng)一個(gè) Watch Dog。也就是說(shuō)leaseTime 必須是 -1 才會(huì)開(kāi)啟 Watch Dog 機(jī)制,也就是如果你想開(kāi)啟 Watch Dog 機(jī)制必須使用默認(rèn)的加鎖時(shí)間為 30s。

4)可重入加鎖機(jī)制

? 當(dāng)鎖key已經(jīng)存在,第二個(gè) if 判斷會(huì)成立,因?yàn)?myLock 的 hash 數(shù)據(jù)結(jié)構(gòu)中包含的那個(gè) ID 即客戶端 1 的 ID,此時(shí)就會(huì)執(zhí)行可重入加鎖的邏輯,

5)鎖釋放機(jī)制

  1. 刪除鎖。
  2. 廣播釋放鎖的消息,通知阻塞等待的進(jìn)程(向通道名為 redisson_lock__channel publish 一條 UNLOCK_MESSAGE 信息)。
  3. 取消 Watch Dog 機(jī)制,即將 RedissonLock.EXPIRATION_RENEWAL_MAP 里面的線程 id 刪除,并且 cancel 掉 Netty 的那個(gè)定時(shí)任務(wù)線程。

源碼分析

? 重點(diǎn)主要是依賴lua腳本的原子性,實(shí)現(xiàn)加鎖和釋放鎖的功能。

實(shí)例化RedissonLock

  • super(commandExecutor, name); 父類name賦值,后續(xù)通過(guò)getName()獲取
  • commandExecutor: 執(zhí)行l(wèi)ua腳本的executor
  • id 是個(gè)UUID, 后面被用來(lái)當(dāng)做和threadId組成 value值**,用作判斷加鎖和釋放鎖是否是同一個(gè)線程的校驗(yàn)。**
  • internalLockLeaseTime : 取自 Config#lockWatchdogTimeout,默認(rèn)30秒,這個(gè)參數(shù)還有另外一個(gè)作用,鎖續(xù)命的執(zhí)行周期 internalLockLeaseTime/3 = 10秒

加鎖和鎖的續(xù)命redissonLock.lock()

  • **Thread.currentThread().interrupt()。**當(dāng)發(fā)生異常,則通知線程進(jìn)行中斷并釋放鎖。

  • lockInterruptibly(-1, null); 此環(huán)節(jié)會(huì)先獲取當(dāng)前線程的線程ID,之后會(huì)嘗試獲取鎖的剩余時(shí)間。

    ? 如果當(dāng)前鎖的剩余時(shí)間為null,說(shuō)明沒(méi)有線程持有該鎖,直接返回讓當(dāng)前線程加鎖成功。如果當(dāng)前線程的剩余時(shí)間不為null,就會(huì)一直嘗試獲取鎖。

    ? Redisson 提供了一個(gè)續(xù)期機(jī)制, 只要客戶端 1 一旦加鎖成功,就會(huì)啟動(dòng)一個(gè) Watch Dog。**也就是說(shuō)leaseTime 必須是 -1 才會(huì)開(kāi)啟 Watch Dog 機(jī)制,也就是如果你想開(kāi)啟 Watch Dog 機(jī)制必須使用默認(rèn)的加鎖時(shí)間為 30s。**如果你自己自定義時(shí)間,超過(guò)這個(gè)時(shí)間,鎖就會(huì)自定釋放,并不會(huì)延長(zhǎng)。

  • **tryAcquireAsync(leaseTime, unit, threadId)(自旋獲取鎖的方法)。**其內(nèi)部專門(mén)創(chuàng)建異步任務(wù)用于嘗試獲取鎖。其任務(wù)內(nèi)部會(huì)注冊(cè)監(jiān)聽(tīng)事件,當(dāng)剩余時(shí)間為null,就會(huì)再次去獲取鎖,并給鎖延長(zhǎng)過(guò)期時(shí)間。

  • tryLockInnerAsync 其內(nèi)部實(shí)現(xiàn)是lua腳本。

  • scheduleExpirationRenewal(final long threadId)。又是lua腳本 判斷是否存在,存在就調(diào)用pexpire

釋放鎖redissonLock.unlock()

  • unlock()。先獲取鎖狀態(tài),如果鎖狀態(tài)為null,則拋出異常。否則就釋放鎖,并刪除key。
  • unlockInnerAsync(long threadId)。unlock的內(nèi)部實(shí)現(xiàn),也是lua腳本,用于獲取當(dāng)前線程的鎖狀態(tài)。

Redissson tryLock源碼

@Overridepublic boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {long time = unit.toMillis(waitTime);long current = System.currentTimeMillis();long threadId = Thread.currentThread().getId();// 1.嘗試獲取鎖Long ttl = tryAcquire(leaseTime, unit, threadId);// lock acquiredif (ttl == null) {return true;}// 申請(qǐng)鎖的耗時(shí)如果大于等于最大等待時(shí)間,則申請(qǐng)鎖失敗.time -= System.currentTimeMillis() - current;if (time <= 0) {acquireFailed(threadId);return false;}current = System.currentTimeMillis();/*** 2.訂閱鎖釋放事件,并通過(guò) await 方法阻塞等待鎖釋放,有效的解決了無(wú)效的鎖申請(qǐng)浪費(fèi)資源的問(wèn)題:* 基于信息量,當(dāng)鎖被其它資源占用時(shí),當(dāng)前線程通過(guò) Redis 的 channel 訂閱鎖的釋放事件,一旦鎖釋放會(huì)發(fā)消息通知待等待的線程進(jìn)行競(jìng)爭(zhēng).** 當(dāng) this.await 返回 false,說(shuō)明等待時(shí)間已經(jīng)超出獲取鎖最大等待時(shí)間,取消訂閱并返回獲取鎖失敗.* 當(dāng) this.await 返回 true,進(jìn)入循環(huán)嘗試獲取鎖.*/RFuture<RedissonLockEntry> subscribeFuture = subscribe(threadId);// await 方法內(nèi)部是用 CountDownLatch 來(lái)實(shí)現(xiàn)阻塞,獲取 subscribe 異步執(zhí)行的結(jié)果(應(yīng)用了 Netty 的 Future)if (!subscribeFuture.await(time, TimeUnit.MILLISECONDS)) {if (!subscribeFuture.cancel(false)) {subscribeFuture.onComplete((res, e) -> {if (e == null) {unsubscribe(subscribeFuture, threadId);}});}acquireFailed(threadId);return false;}try {// 計(jì)算獲取鎖的總耗時(shí),如果大于等于最大等待時(shí)間,則獲取鎖失敗.time -= System.currentTimeMillis() - current;if (time <= 0) {acquireFailed(threadId);return false;}/*** 3.收到鎖釋放的信號(hào)后,在最大等待時(shí)間之內(nèi),循環(huán)一次接著一次的嘗試獲取鎖* 獲取鎖成功,則立馬返回 true,* 若在最大等待時(shí)間之內(nèi)還沒(méi)獲取到鎖,則認(rèn)為獲取鎖失敗,返回 false 結(jié)束循環(huán)*/while (true) {long currentTime = System.currentTimeMillis();// 再次嘗試獲取鎖ttl = tryAcquire(leaseTime, unit, threadId);// lock acquiredif (ttl == null) {return true;}// 超過(guò)最大等待時(shí)間則返回 false 結(jié)束循環(huán),獲取鎖失敗time -= System.currentTimeMillis() - currentTime;if (time <= 0) {acquireFailed(threadId);return false;}/*** 6.阻塞等待鎖(通過(guò)信號(hào)量(共享鎖)阻塞,等待解鎖消息):*/currentTime = System.currentTimeMillis();if (ttl >= 0 && ttl < time) {//如果剩余時(shí)間(ttl)小于wait time ,就在 ttl 時(shí)間內(nèi),從Entry的信號(hào)量獲取一個(gè)許可(除非被中斷或者一直沒(méi)有可用的許可)。getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);} else {//則就在wait time 時(shí)間范圍內(nèi)等待可以通過(guò)信號(hào)量getEntry(threadId).getLatch().tryAcquire(time, TimeUnit.MILLISECONDS);}// 更新剩余的等待時(shí)間(最大等待時(shí)間-已經(jīng)消耗的阻塞時(shí)間)time -= System.currentTimeMillis() - currentTime;if (time <= 0) {acquireFailed(threadId);return false;}}} finally {// 7.無(wú)論是否獲得鎖,都要取消訂閱解鎖消息unsubscribe(subscribeFuture, threadId);}
//        return get(tryLockAsync(waitTime, leaseTime, unit));}

流程分析:

  1. 嘗試獲取鎖,返回 null 則說(shuō)明加鎖成功,返回一個(gè)數(shù)值,則說(shuō)明已經(jīng)存在該鎖,ttl 為鎖的剩余存活時(shí)間。
  2. 如果此時(shí)客戶端 2 進(jìn)程獲取鎖失敗,那么使用客戶端 2 的線程 id(其實(shí)本質(zhì)上就是進(jìn)程 id)通過(guò) Redis 的 channel 訂閱鎖釋放的事件,。如果等待的過(guò)程中一直未等到鎖的釋放事件通知,當(dāng)超過(guò)最大等待時(shí)間則獲取鎖失敗,返回 false,也就是第 39 行代碼。如果等到了鎖的釋放事件的通知,則開(kāi)始進(jìn)入一個(gè)不斷重試獲取鎖的循環(huán)。
  3. 循環(huán)中每次都先試著獲取鎖,并得到已存在的鎖的剩余存活時(shí)間。如果在重試中拿到了鎖,則直接返回。如果鎖當(dāng)前還是被占用的,那么等待釋放鎖的消息,具體實(shí)現(xiàn)使用了 JDK 的信號(hào)量 Semaphore 來(lái)阻塞線程,當(dāng)鎖釋放并發(fā)布釋放鎖的消息后,信號(hào)量的 release() 方法會(huì)被調(diào)用,此時(shí)被信號(hào)量阻塞的等待隊(duì)列中的一個(gè)線程就可以繼續(xù)嘗試獲取鎖了。

特別注意:

? 以上過(guò)程存在一個(gè)細(xì)節(jié),這里有必要說(shuō)明一下,也是分布式鎖的一個(gè)關(guān)鍵點(diǎn):當(dāng)鎖正在被占用時(shí),等待獲取鎖的進(jìn)程并不是通過(guò)一個(gè) while(true) 死循環(huán)去獲取鎖,而是利用了 Redis 的發(fā)布訂閱機(jī)制,通過(guò) await 方法阻塞等待鎖的進(jìn)程,有效的解決了無(wú)效的鎖申請(qǐng)浪費(fèi)資源的問(wèn)題。

優(yōu)缺點(diǎn)

方案優(yōu)點(diǎn)

  1. Redisson 通過(guò) Watch Dog 機(jī)制很好的解決了鎖的續(xù)期問(wèn)題。
  2. 和 Zookeeper 相比較,Redisson 基于 Redis 性能更高,適合對(duì)性能要求高的場(chǎng)景。
  3. 通過(guò) Redisson 實(shí)現(xiàn)分布式可重入鎖,比原生的 SET mylock userId NX PX milliseconds + lua 實(shí)現(xiàn)的效果更好些,雖然基本原理都一樣,但是它幫我們屏蔽了內(nèi)部的執(zhí)行細(xì)節(jié)。
  4. 在等待申請(qǐng)鎖資源的進(jìn)程等待申請(qǐng)鎖的實(shí)現(xiàn)上也做了一些優(yōu)化,減少了無(wú)效的鎖申請(qǐng),提升了資源的利用率。

方案缺點(diǎn)

? **使用 Redisson 實(shí)現(xiàn)分布式鎖方案最大的問(wèn)題就是如果你對(duì)某個(gè) Redis Master 實(shí)例完成了加鎖,此時(shí) Master 會(huì)異步復(fù)制給其對(duì)應(yīng)的 slave 實(shí)例。**但是這個(gè)過(guò)程中一旦 Master 宕機(jī),主備切換,slave 變?yōu)榱?Master。接著就會(huì)導(dǎo)致,客戶端 2 來(lái)嘗試加鎖的時(shí)候,在新的 Master 上完成了加鎖,而客戶端 1 也以為自己成功加了鎖,此時(shí)就會(huì)導(dǎo)致多個(gè)客戶端對(duì)一個(gè)分布式鎖完成了加鎖,這時(shí)系統(tǒng)在業(yè)務(wù)語(yǔ)義上一定會(huì)出現(xiàn)問(wèn)題,導(dǎo)致各種臟數(shù)據(jù)的產(chǎn)生。

? 所以這個(gè)就是 Redis Cluster 或者說(shuō)是 Redis Master-Slave 架構(gòu)的主從異步復(fù)制導(dǎo)致的 Redis 分布式鎖的最大缺陷(在 Redis Master 實(shí)例宕機(jī)的時(shí)候,可能導(dǎo)致多個(gè)客戶端同時(shí)完成加鎖)。

?

http://m.risenshineclean.com/news/65188.html

相關(guān)文章:

  • 廣州網(wǎng)站優(yōu)化哪家快洛陽(yáng)市網(wǎng)站建設(shè)
  • 做綠色軟件的網(wǎng)站知乎百度關(guān)鍵詞推廣費(fèi)用
  • 網(wǎng)站獨(dú)立ip多代表什么競(jìng)價(jià)推廣網(wǎng)絡(luò)推廣運(yùn)營(yíng)
  • 做網(wǎng)站定金交多少合適合肥網(wǎng)站推廣優(yōu)化公司
  • 上行10m企業(yè)光纖做網(wǎng)站環(huán)球資源外貿(mào)平臺(tái)免費(fèi)
  • 上海公司注冊(cè)查詢seo視頻教程
  • 大連做網(wǎng)站需要多少錢(qián)競(jìng)價(jià)托管選擇微競(jìng)價(jià)
  • 南寧外包seo服務(wù)福州百度seo排名
  • 培訓(xùn)機(jī)構(gòu)招生方案win優(yōu)化大師有用嗎
  • 深圳做app網(wǎng)站制作湘潭網(wǎng)站seo磐石網(wǎng)絡(luò)
  • 做裝修公司網(wǎng)站百度應(yīng)用商店下載安裝
  • 啟源網(wǎng)站建設(shè)seo計(jì)費(fèi)系統(tǒng)開(kāi)發(fā)
  • 做網(wǎng)站注冊(cè)營(yíng)業(yè)執(zhí)照蘭州seo培訓(xùn)
  • 響應(yīng)式網(wǎng)站好不好引流推廣方法
  • 夏縣網(wǎng)站建設(shè)指數(shù)運(yùn)算法則
  • 做葡萄酒的網(wǎng)站日本疫情最新數(shù)據(jù)
  • 做網(wǎng)站避免上當(dāng)簡(jiǎn)單網(wǎng)頁(yè)設(shè)計(jì)模板html
  • 東莞公司網(wǎng)站價(jià)格競(jìng)價(jià)托管服務(wù)多少錢(qián)
  • 丹東網(wǎng)站建設(shè)磁力庫(kù)
  • 西安做網(wǎng)站選哪家指數(shù)型基金是什么意思
  • firework做網(wǎng)站教程seo課程多少錢(qián)
  • 蘭州網(wǎng)站建設(shè)哪家專業(yè)百度網(wǎng)盤(pán)app下載安裝
  • 網(wǎng)站推廣服務(wù)費(fèi)會(huì)計(jì)分錄怎么做專業(yè)軟文發(fā)布平臺(tái)
  • 360網(wǎng)站備案查詢熱狗網(wǎng)站關(guān)鍵詞優(yōu)化
  • 網(wǎng)站備案費(fèi)用seo推廣軟件哪個(gè)好
  • 做企業(yè)網(wǎng)站收費(fèi)多少怎么做產(chǎn)品推廣和宣傳
  • 企業(yè)服務(wù)局搜索引擎優(yōu)化內(nèi)容包括哪些方面
  • 布吉網(wǎng)站設(shè)計(jì)快速優(yōu)化網(wǎng)站排名軟件
  • 移動(dòng)互聯(lián)網(wǎng)應(yīng)用程序開(kāi)發(fā)影響seo排名的因素
  • 網(wǎng)站界面設(shè)計(jì)分析熱搜關(guān)鍵詞