[英]server-to-server multicast messaging with Google Cloud PubSub?
[英]Google Cloud Pubsub Data lost
我遇到了GCP pubsub的問題,在幾秒鍾內發布數千封郵件時,一小部分數據丟失了。
我正在發布pubsub上的message_id
和發布端以及接收端的每條消息都是唯一的session_id
,我看到的結果是接收端的某些消息具有相同的session_id
,但是message_id
不同。 此外,一些消息丟失了。
例如,在一次測試中,我向pubsub發送了5,000條消息,並且收到了5,000條消息,其中8條消息丟失。 日志丟失的消息如下所示:
MISSING sessionId:sessionId: 731 (missing in log from pull request, but present in log from Flask API)
messageId FOUND: messageId:108562396466545
API: 200 **** sessionId: 731, messageId:108562396466545 ******(Log from Flask API)
Pubsub: sessionId: 730, messageId:108562396466545(Log from pull request)
副本看起來像:
======= Duplicates FOUND on sessionId: 730=======
sessionId: 730, messageId:108562396466545
sessionId: 730, messageId:108561339282318
(both are logs from pull request)
所有缺失的數據和重復數據都是這樣的。
從上面的例子中可以看出,一些消息已經獲取了另一條消息的message_id
,並且已經使用兩個不同的message_id
發送了兩次。
我想知道是否有人會幫我弄清楚發生了什么? 提前致謝。
碼
我有一個API向pubsub發送消息,如下所示:
from flask import Flask, request, jsonify, render_template
from flask_cors import CORS, cross_origin
import simplejson as json
from google.cloud import pubsub
from functools import wraps
import re
import json
app = Flask(__name__)
ps = pubsub.Client()
...
@app.route('/publish', methods=['POST'])
@cross_origin()
@json_validator
def publish_test_topic():
pubsub_topic = 'test_topic'
data = request.data
topic = ps.topic(pubsub_topic)
event = json.loads(data)
messageId = topic.publish(data)
return '200 **** sessionId: ' + str(event["sessionId"]) + ", messageId:" + messageId + " ******"
這是我以前從pubsub讀取的代碼:
來自google.cloud導入pubsub導入重新導入json
ps = pubsub.Client()
topic = ps.topic('test-xiu')
sub = topic.subscription('TEST-xiu')
max_messages = 1
stop = False
messages = []
class Message(object):
"""docstring for Message."""
def __init__(self, sessionId, messageId):
super(Message, self).__init__()
self.seesionId = sessionId
self.messageId = messageId
def pull_all():
while stop == False:
m = sub.pull(max_messages = max_messages, return_immediately = False)
for data in m:
ack_id = data[0]
message = data[1]
messageId = message.message_id
data = message.data
event = json.loads(data)
sessionId = str(event["sessionId"])
messages.append(Message(sessionId = sessionId, messageId = messageId))
print '200 **** sessionId: ' + sessionId + ", messageId:" + messageId + " ******"
sub.acknowledge(ack_ids = [ack_id])
pull_all()
要生成session_id,請從API發送請求和日志記錄響應:
// generate trackable sessionId
var sessionId = 0
var increment_session_id = function () {
sessionId++;
return sessionId;
}
var generate_data = function () {
var data = {};
// data.sessionId = faker.random.uuid();
data.sessionId = increment_session_id();
data.user = get_rand(userList);
data.device = get_rand(deviceList);
data.visitTime = new Date;
data.location = get_rand(locationList);
data.content = get_rand(contentList);
return data;
}
var sendData = function (url, payload) {
var request = $.ajax({
url: url,
contentType: 'application/json',
method: 'POST',
data: JSON.stringify(payload),
error: function (xhr, status, errorThrown) {
console.log(xhr, status, errorThrown);
$('.result').prepend("<pre id='json'>" + JSON.stringify(xhr, null, 2) + "</pre>")
$('.result').prepend("<div>errorThrown: " + errorThrown + "</div>")
$('.result').prepend("<div>======FAIL=======</div><div>status: " + status + "</div>")
}
}).done(function (xhr) {
console.log(xhr);
$('.result').prepend("<div>======SUCCESS=======</div><pre id='json'>" + JSON.stringify(payload, null, 2) + "</pre>")
})
}
$(submit_button).click(function () {
var request_num = get_request_num();
var request_url = get_url();
for (var i = 0; i < request_num; i++) {
var data = generate_data();
var loadData = changeVerb(data, 'load');
sendData(request_url, loadData);
}
})
UPDATE
我對API進行了更改,問題似乎消失了。 我所做的更改不是對所有請求使用一個pubsub.Client()
,而是為每個請求進入初始化客戶端。新的API如下所示:
from flask import Flask, request, jsonify, render_template
from flask_cors import CORS, cross_origin
import simplejson as json
from google.cloud import pubsub
from functools import wraps
import re
import json
app = Flask(__name__)
...
@app.route('/publish', methods=['POST'])
@cross_origin()
@json_validator
def publish_test_topic():
ps = pubsub.Client()
pubsub_topic = 'test_topic'
data = request.data
topic = ps.topic(pubsub_topic)
event = json.loads(data)
messageId = topic.publish(data)
return '200 **** sessionId: ' + str(event["sessionId"]) + ", messageId:" + messageId + " ******"
Google Cloud Pub / Sub消息ID是唯一的。 “某些消息[以]取得另一條消息的message_id
應該是不可能的。” 看似收到消息ID 108562396466545的事實意味着Pub / Sub確實將消息傳遞給訂戶並且沒有丟失。
我建議您檢查session_id
的生成方式,以確保它們確實是唯一的,並且每條消息只有一條。 通過正則表達式搜索在JSON中搜索sessionId似乎有點奇怪。 您最好將此JSON解析為實際對象並以此方式訪問字段。
通常,Cloud Pub / Sub中的重復消息始終是可能的; 系統保證至少一次交付。 如果在訂閱方發生重復(例如,ack未及時處理)或具有不同的消息ID(例如,如果在發生錯誤之后重試消息的發布,則可以使用相同的消息ID來傳遞這些消息)超過截止日期)。
您不需要為每個發布操作創建新客戶端。 我敢打賭,“修復問題”的原因是因為它減輕了發布者客戶端存在的競爭。 我也不相信您在發布商方面顯示的日志行:
API:200 **** sessionId:731,messageId:108562396466545 ******
對應於publish_test_topic()成功發布sessionId 731。 在什么條件下打印日志? 到目前為止提供的代碼沒有顯示出來。
與谷歌的一些人交談,這似乎與Python客戶端有關:
我們的共識是,當前的python客戶端存在線程安全問題。 我們說話時,客戶端庫幾乎從頭開始重寫,因此我不想在當前版本中進行任何修復。 我們預計新版本將於6月底上市。
在app.yaml中使用thread_safe:false運行當前代碼或者更好但只是在每個調用中實例化客戶端應該是解決方法 - 您找到的解決方案。
有關詳細解決方案,請參閱問題中的更新
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.