RedisCluster模式hashtag使用

基礎(chǔ)補(bǔ)充文檔:

Redis集群模式介紹:

https://www.cnblogs.com/zhonglongbo/p/13128955.html

Redis主流集群模式:

主從模式、哨兵模式、集群模式

遇到的問(wèn)題:

使用Rediscluster模式集群,出現(xiàn)單點(diǎn)熱點(diǎn)key,既集群中N個(gè)數(shù)據(jù)節(jié)點(diǎn)中么库,單一節(jié)點(diǎn)承接了這個(gè)場(chǎng)景下的所有流量;導(dǎo)致單節(jié)點(diǎn)cpu飆升到60%甘有,其余節(jié)點(diǎn)cpu10%诉儒;

這個(gè)場(chǎng)景是geohash運(yùn)算,屬于讀流量中的cpu密集型操作亏掀;

為了分散讀流量到各個(gè)節(jié)點(diǎn)忱反,我們選擇了,基于當(dāng)前key數(shù)據(jù)生成N-1個(gè)副本的策略滤愕;

Rediscluster?集群模式的工作原理:

分片策略:

Redis 集群將數(shù)據(jù)劃分為16384(2的14次方)個(gè)哈希槽(slots)温算,每個(gè)節(jié)點(diǎn)負(fù)責(zé)其中一部分槽位。當(dāng)客戶端發(fā)起請(qǐng)求時(shí)间影,根據(jù)鍵(key)的CRC16值進(jìn)行哈希計(jì)算注竿,然后對(duì)16384取模,得到對(duì)應(yīng)的槽位索引魂贬,從而確定請(qǐng)求應(yīng)該發(fā)送到哪個(gè)節(jié)點(diǎn)巩割。

以下圖為例,該集群有4個(gè) Redis 節(jié)點(diǎn)付燥,每個(gè)節(jié)點(diǎn)負(fù)責(zé)集群中的一部分?jǐn)?shù)據(jù)宣谈,數(shù)據(jù)量可以不均勻。比如性能好的實(shí)例節(jié)點(diǎn)可以多分擔(dān)一些壓力键科。


哈希槽(slots)的劃分

這個(gè)前面已經(jīng)說(shuō)過(guò)了闻丑,我們會(huì)將整個(gè)Redis數(shù)據(jù)庫(kù)劃分為16384個(gè)哈希槽,你的Redis集群可能有n個(gè)實(shí)例節(jié)點(diǎn)勋颖,每個(gè)節(jié)點(diǎn)可以處理0個(gè) 到至多 16384 個(gè)槽點(diǎn)梆掸,這些節(jié)點(diǎn)把 16384個(gè)槽位瓜分完成。

而你實(shí)際存儲(chǔ)的Redis鍵值信息也必然歸屬于這 16384 個(gè)槽的其中一個(gè)牙言。slots 與 Redis Key 的映射是通過(guò)以下兩個(gè)步驟完成的:

使用 CRC16 算法計(jì)算鍵值對(duì)信息的Key酸钦,會(huì)得出一個(gè) 16 bit 的值。

將 第1步中得到的 16 bit 的值對(duì) 16384 取模,得到的值會(huì)在 0 ~ 16383 之間卑硫,映射到對(duì)應(yīng)到哈希槽中徒恋。

當(dāng)然,可能在一些特殊的情況下欢伏,你想把某些key固定到某個(gè)slot上面入挣,也就是同一個(gè)實(shí)例節(jié)點(diǎn)上。這時(shí)候可以用hash tag能力硝拧,強(qiáng)制 key 所歸屬的槽位等于 tag 所在的槽位径筏。

其實(shí)現(xiàn)方式為在key中加個(gè){},例如test_key{1}障陶。使用hash tag后客戶端在計(jì)算key的crc16時(shí)滋恬,只計(jì)算{}中數(shù)據(jù)。如果沒使用hash tag抱究,客戶端會(huì)對(duì)整個(gè)key進(jìn)行crc16計(jì)算恢氯。下面演示下hash tag使用:

127.0.0.1:6380> cluster keyslot user:case{1}

(integer) 1024

127.0.0.1:6380> cluster keyslot user:favor

(integer) 1023

127.0.0.1:6380> cluster keyslot user:info{1}

(integer) 1024

如上,使用hash tag 后會(huì)對(duì)應(yīng)到通一個(gè)hash slot:1024中鼓寺。

哈希槽(slots)的映射

一種是初始化的時(shí)候均勻分配 勋拟,使用 cluster create 創(chuàng)建,會(huì)將 16384 個(gè)slots 平均分配在我們的集群實(shí)例上妈候,比如你有n個(gè)節(jié)點(diǎn)敢靡,那每個(gè)節(jié)點(diǎn)的槽位就是 16384 / n 個(gè)了 。

另一種是通過(guò) CLUSTER MEET 命令將 node1苦银、node2醋安、ndoe3、node4 4個(gè)節(jié)點(diǎn)聯(lián)通成一個(gè)集群墓毒,剛聯(lián)通的時(shí)候因?yàn)檫€沒分配哈希槽,還是處于offline狀態(tài)亲怠。我們使用?cluster addslots?命令來(lái)指定所计。

指定的好處就是性能好的實(shí)例節(jié)點(diǎn)可以多分擔(dān)一些壓力。

可以通過(guò) addslots 命令指定哈希槽范圍团秽,比如下圖中主胧,我們哈希槽是這么分配的:實(shí)例 1 管理 0 ~ 7120 哈希槽,實(shí)例 2 管理 7121~9945 哈希槽习勤,實(shí)例 3 管理 9946 ~ 13005 哈希槽踪栋,實(shí)例 4 管理 13006 ~ 16383 哈希槽。

redis-cli -h 192.168.0.1 –p 6379 cluster addslots 0,7120

redis-cli -h 192.168.0.2 –p 6379 cluster addslots 7121,9945

redis-cli -h 192.168.0.3 –p 6379 cluster addslots 9946,13005

redis-cli -h 192.168.0.4 –p 6379 cluster addslots 13006,16383

slots 和 Redis 實(shí)例之間的映射關(guān)系如下:


key?testkey_1?和?testkey_2?經(jīng)過(guò) CRC16 計(jì)算后再對(duì)slots的總個(gè)數(shù) 16384 取模图毕,結(jié)果分別匹配到了 cache1 和 cache3 上夷都。

補(bǔ)充知識(shí)點(diǎn):為什么選擇0-16383即16384個(gè)槽位?

計(jì)算公式 HASH_SLOT = RCR16(key) mod 16384

如果槽位為65536(2^16)予颤,發(fā)送心跳信息的消息頭達(dá)8k囤官,發(fā)送的心跳包過(guò)于龐大冬阳。

在消息頭中最占空間的是myslots[CLUSTER_SLOTS/8]。 當(dāng)槽位為65536時(shí)党饮,這塊的大小是: 65536÷8÷1024=8kb?

在消息頭中最占空間的是myslots[CLUSTER_SLOTS/8]肝陪。 當(dāng)槽位為16384時(shí),這塊的大小是: 16384÷8÷1024=2kb?

因?yàn)槊棵腌娦趟常瑀edis節(jié)點(diǎn)需要發(fā)送一定數(shù)量的ping消息作為心跳包氯窍,如果槽位為65536,這個(gè)ping消息的消息頭太大了蹲堂,浪費(fèi)帶寬狼讨。

redis的集群主節(jié)點(diǎn)數(shù)量基本不可能超過(guò)1000個(gè)。

集群節(jié)點(diǎn)越多贯城,心跳包的消息體內(nèi)攜帶的數(shù)據(jù)越多熊楼。如果節(jié)點(diǎn)過(guò)1000個(gè),也會(huì)導(dǎo)致網(wǎng)絡(luò)擁堵能犯。因此redis作者不建議redis cluster節(jié)點(diǎn)數(shù)量超過(guò)1000個(gè)鲫骗。 那么,對(duì)于節(jié)點(diǎn)數(shù)在1000以內(nèi)的redis cluster集群踩晶,16384個(gè)槽位夠用了执泰。沒有必要拓展到65536個(gè)。

槽位越小渡蜻,節(jié)點(diǎn)少的情況下术吝,壓縮比高,容易傳輸

Redis主節(jié)點(diǎn)的配置信息中它所負(fù)責(zé)的哈希槽是通過(guò)一張bitmap的形式來(lái)保存的茸苇,在傳輸過(guò)程中會(huì)對(duì)bitmap進(jìn)行壓縮排苍,但是如果bitmap的填充率slots / N很高的話(N表示節(jié)點(diǎn)數(shù)),bitmap的壓縮率就很低学密。 如果節(jié)點(diǎn)數(shù)很少淘衙,而哈希槽數(shù)量很多的話,bitmap的壓縮率就很低腻暮。?

通過(guò)java代碼計(jì)算槽位與節(jié)點(diǎn)的數(shù)據(jù):

? ? ? ? // 設(shè)定一個(gè)容器對(duì)象

? ? ? ? HashMap<@Nullable Object, @Nullable Object> objectObjectHashMap = Maps.newHashMap();

? ? ? ? // 初始化設(shè)定有32個(gè)節(jié)點(diǎn)的RedisCluster集群

? ? ? ? int n = 32;

? ? ? ? for (int i = 0; i < 200; i++) {

? ? ? ? ? ? // 利用JedisClusterCRC16 計(jì)算 key的hashtag:"123:{1}" 屬于哪一個(gè)slot

? ? ? ? ? ? int slot = JedisClusterCRC16.getSlot("123:{" + i + "}");

? ? ? ? ? ? for (int j = 0; j < n; j++) {

? ? ? ? ? ? ? ? // 計(jì)算當(dāng)前slot 屬于哪一個(gè) node彤守;

? ? ? ? ? ? ? ? if (slot > j * (16383 / n) && slot < (j + 1) * (16383 / n)) {

? ? ? ? ? ? ? ? ? ? // 以下計(jì)算,只記錄每個(gè)節(jié)點(diǎn)從小到大第一個(gè)明確的hashtag分配的數(shù)據(jù)

? ? ? ? ? ? ? ? ? ? if (Objects.isNull(objectObjectHashMap.get(j + 1))) {

? ? ? ? ? ? ? ? ? ? ? ? objectObjectHashMap.put(j + 1, i + "---" + slot);

? ? ? ? ? ? ? ? ? ? ? ? if (objectObjectHashMap.size() >= n) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? outer:

? ? ? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? // 隨機(jī)獲取當(dāng)前 key hashtag對(duì)應(yīng)的 node和slot

? ? ? ? // 下面的代碼也可用于 隨機(jī)分發(fā)查詢流量哭靖,用于組裝一個(gè)key

? ? ? ? if(!objectObjectHashMap.isEmpty()) {

? ? ? ? ? ? for (int j = 0; j < 100; j++) {

? ? ? ? ? ? ? ? ThreadLocalRandom threadLocalRandom = ThreadLocalRandom.current();

? ? ? ? ? ? ? ? int i = threadLocalRandom.nextInt(n);

? ? ? ? ? ? ? ? System.out.println(i+1);

? ? ? ? ? ? ? ? System.out.println(objectObjectHashMap.get(++i));

? ? ? ? ? ? }

? ? ? ? }

補(bǔ)充知識(shí)點(diǎn):hashtag

在Redis中具垫,hashtag(哈希標(biāo)簽)是一個(gè)用于數(shù)據(jù)分片的機(jī)制,它允許將多個(gè)鍵映射到同一個(gè)哈希槽中试幽。這是通過(guò)在鍵的名稱中包含一對(duì)大括號(hào)({})來(lái)實(shí)現(xiàn)的筝蚕,大括號(hào)內(nèi)可以包含任意字符串。Redis集群使用CRC16算法對(duì)鍵進(jìn)行哈希,然后對(duì)16384取模饰及,以此確定鍵應(yīng)該存儲(chǔ)在哪個(gè)槽位上蔗坯。

使用hashtag的目的是為了在集群環(huán)境中能夠?qū)σ唤M相關(guān)的鍵執(zhí)行原子操作。例如燎含,如果你有一個(gè)用戶信息存儲(chǔ)在Redis中宾濒,可能包含用戶的姓名、郵箱屏箍、年齡等多個(gè)字段绘梦,你可以使用hashtag將這些字段組織在一起,如下所示:

user{123}:username

user{123}:email

user{123}:age

在這個(gè)例子中赴魁,user{123}是哈希標(biāo)簽卸奉,它確保所有以u(píng)ser{123}:開頭的鍵都會(huì)被分配到同一個(gè)哈希槽中。這意味著颖御,即使用戶的數(shù)據(jù)分布在不同的Redis節(jié)點(diǎn)上榄棵,你也可以通過(guò)一個(gè)命令來(lái)同時(shí)操作這些鍵,例如使用DEL命令刪除一個(gè)用戶的所有信息:

DEL user{123}:username user{123}:email user{123}:age

這種方式在Redis集群中特別有用潘拱,因?yàn)樗试S跨多個(gè)節(jié)點(diǎn)執(zhí)行命令疹鳄,而不需要客戶端知道每個(gè)鍵具體存儲(chǔ)在哪個(gè)節(jié)點(diǎn)上。Redis集群會(huì)自動(dòng)將命令路由到正確的節(jié)點(diǎn)芦岂,并執(zhí)行相應(yīng)的操作瘪弓。

需要注意的是,hashtag只在Redis集群模式下有效禽最,它不會(huì)影響非集群模式下的鍵腺怯。此外,hashtag的使用也需要謹(jǐn)慎川无,因?yàn)樗赡軙?huì)導(dǎo)致數(shù)據(jù)傾斜呛占,如果不正確地使用,可能會(huì)將大量的鍵映射到同一個(gè)槽位懦趋,從而影響集群的負(fù)載均衡晾虑。

Redis源碼關(guān)于hashtag計(jì)算:

源碼:

源碼有2處。

第一處:

https://github.com/redis/redis/blob/6.2.6/src/redis-cli.c

line:3282

方法:clusterManagetKeyHashSlot

第二處:

https://github.com/redis/redis/blob/6.2.6/src/cluster.c

line:749

方法:keyHashSlot

// 源碼位置

// https://github.com/redis/redis/blob/6.2.6/src/cluster.c

unsigned int keyHashSlot(char *key, int keylen) {

? ? // s代表{在key中的位置愕够,e代表}在key中的位置

? ? int s, e;

? ? // 若無(wú){,則s等于keylen

? ? for (s = 0; s < keylen; s++)

? ? ? ? // 遇到第一個(gè){跳出

? ? ? ? if (key[s] == '{') break;

? ? // 若key中無(wú){佛猛,則s等于keylen惑芭,整個(gè)key參與hash

? ? // 0x3FFF對(duì)應(yīng)10進(jìn)制為16383

? ? // 16383對(duì)應(yīng)二進(jìn)制為14個(gè)1

? ? // 按位與運(yùn)算時(shí)只取crc16結(jié)果的低14位

? ? if (s == keylen) return crc16(key,keylen) & 0x3FFF;


? ? // 若key中有{,查看是否有}

? ? // 若key中無(wú)}继找,則e等于keylen遂跟,整個(gè)key參與hash

? ? for (e = s+1; e < keylen; e++)

? ? ? ? // 遇到第一個(gè)}跳出

? ? ? ? if (key[e] == '}') break;


? ? // key中無(wú)},整個(gè)key參與hash

? ? // key中有},但{}之間為空,整個(gè)key參與hash

? ? if (e == keylen || e == s+1) return crc16(key,keylen) & 0x3FFF;

? ? // {}中間部分參與hash

? ? // key+s+1 指針操作,向右移動(dòng)s+1

? ? // e-s-1為{}中間字符串的長(zhǎng)度

? ? return crc16(key+s+1,e-s-1) & 0x3FFF;

}

hashtag場(chǎng)景注意事項(xiàng)介紹:

1.僅{...}里的部分參與hash幻锁。

2.如果有多個(gè)花括號(hào)凯亮,從左向右,取第一個(gè)花括號(hào)中的內(nèi)容進(jìn)行hash哄尔。

3.如果第一個(gè)花括號(hào)中內(nèi)容為空如:a{}c28oce6y假消,則整個(gè)key參與hash。

4.相同的hashtag被分配到相同的節(jié)點(diǎn)岭接,相同的槽富拗。

hash算法采用crc16。crc16算法為redis自己封裝的鸣戴,源碼位置:https://github.com/redis/redis/blob/6.2.6/src/crc16.c


hashtag使用中的缺點(diǎn):

在Redis集群中使用hashtag雖然提供了一定的便利性啃沪,但也存在一些缺點(diǎn)。以下是根據(jù)搜索結(jié)果得出的hashtag的主要缺點(diǎn):

1.?數(shù)據(jù)傾斜:

使用hashtag可能會(huì)導(dǎo)致數(shù)據(jù)集中在集群的某個(gè)實(shí)例中窄锅,造成數(shù)據(jù)傾斜创千。例如,如果大量使用相同的hashtag入偷,可能會(huì)導(dǎo)致所有相關(guān)的數(shù)據(jù)都被存儲(chǔ)在同一個(gè)節(jié)點(diǎn)上追驴。這種情況可能會(huì)影響集群的負(fù)載均衡,使得單個(gè)節(jié)點(diǎn)承受過(guò)大的壓力盯串,而其他節(jié)點(diǎn)資源未被充分利用氯檐。

2.?影響集群性能:

當(dāng)大量數(shù)據(jù)因?yàn)閔ashtag而被集中存儲(chǔ)在同一節(jié)點(diǎn)時(shí),可能會(huì)影響該節(jié)點(diǎn)的性能体捏,尤其是在高并發(fā)場(chǎng)景下冠摄,節(jié)點(diǎn)可能會(huì)成為瓶頸,導(dǎo)致響應(yīng)速度變慢几缭。

3.?遷移和擴(kuò)展困難:

在使用hashtag后河泳,如果需要對(duì)集群進(jìn)行擴(kuò)展或縮減,數(shù)據(jù)遷移可能會(huì)變得復(fù)雜年栓。因?yàn)樾枰_保hashtag相關(guān)的數(shù)據(jù)在遷移過(guò)程中保持一致性拆挥,這可能需要額外的人工干預(yù)和復(fù)雜的數(shù)據(jù)遷移策略。

4.?限制批量操作:

在Redis集群中某抓,批量操作(如pipeline)要求所有涉及的key必須位于同一個(gè)槽位中纸兔。如果使用hashtag導(dǎo)致數(shù)據(jù)分布在不同的槽位,將無(wú)法執(zhí)行批量操作否副,這限制了某些操作的執(zhí)行汉矿。

5.?增加復(fù)雜性:

引入hashtag機(jī)制增加了Redis集群使用和管理的復(fù)雜性。開發(fā)者和運(yùn)維人員需要對(duì)hashtag的工作原理有深入的理解备禀,才能有效地避免潛在的問(wèn)題洲拇。

6.?熱點(diǎn)問(wèn)題:

hashtag可能導(dǎo)致某些key成為熱點(diǎn)key奈揍,即頻繁訪問(wèn)的key。當(dāng)這些熱點(diǎn)key集中在同一節(jié)點(diǎn)時(shí)赋续,可能會(huì)導(dǎo)致該節(jié)點(diǎn)過(guò)載男翰,影響整個(gè)集群的性能和穩(wěn)定性。

綜上所述:

在使用hashtag時(shí)纽乱,需要權(quán)衡其帶來(lái)的便利性和可能引發(fā)的問(wèn)題蛾绎,合理規(guī)劃數(shù)據(jù)分片策略,以確保集群的健康運(yùn)行和數(shù)據(jù)的均衡分布迫淹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末秘通,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子敛熬,更是在濱河造成了極大的恐慌肺稀,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件应民,死亡現(xiàn)場(chǎng)離奇詭異话原,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诲锹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門繁仁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人归园,你說(shuō)我怎么就攤上這事黄虱。” “怎么了庸诱?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵捻浦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我桥爽,道長(zhǎng)朱灿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任钠四,我火速辦了婚禮盗扒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缀去。我一直安慰自己侣灶,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布缕碎。 她就那樣靜靜地躺著褥影,像睡著了一般。 火紅的嫁衣襯著肌膚如雪阎曹。 梳的紋絲不亂的頭發(fā)上伪阶,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音处嫌,去河邊找鬼栅贴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛熏迹,可吹牛的內(nèi)容都是我干的檐薯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼注暗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坛缕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起捆昏,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赚楚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后骗卜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宠页,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年寇仓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了举户。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遍烦,死狀恐怖俭嘁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情服猪,我是刑警寧澤供填,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站蔓姚,受9級(jí)特大地震影響捕虽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坡脐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一泄私、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧备闲,春花似錦晌端、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至泻骤,卻和暖如春漆羔,著一層夾襖步出監(jiān)牢的瞬間梧奢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工演痒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亲轨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓鸟顺,卻偏偏與公主長(zhǎng)得像惦蚊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子讯嫂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容