如何锁定Google Cloud Storage文本文件以实现事务操作

1 投票
2 回答
2053 浏览
提问于 2025-04-18 14:01

我有一个文本文件(比如叫“X”),它存储在GCS(谷歌云存储)上,是通过GCS客户端库创建和更新的。我使用的是GAE Python(谷歌应用引擎的Python版本)。每当我的网站用户添加一些数据时,我就会在“默认”队列中添加一个任务(taskqueue.Task),这个任务会执行一些操作,包括修改文件(“X”)。

有时候,我在日志中看到以下错误:

E 2014-07-20 03:19:06.238 500 3KB 430ms /t
0.1.0.2 - - [19/Jul/2014:14:49:06 -0700] "POST /t HTTP/1.1" 500 2569 "http://www.myappdomain.com/p" "AppEngine-Google; (+http://code.google.com/appengine)" "www.myappdomain.com" ms=430 cpu_ms=498 cpm_usd=0.000287 queue_name=default task_name=14629523467445182169 instance=00c61b117c48b4db44a58e0d454310843e7848 app_engine_release=1.9.7 trace_id=3db3eb580b76133e90947539c0446910  
   I 03:19:05.813 [class TaskQueueWorker]  work=[sitemap_index_entry]  
   I 03:19:05.813 country_id=[US] country_name=[USA] state_id=[CA] state_name=[California] city_id=[SVL] city_name=[Sunnyvale]  
   I 03:19:05.836 locality_id_old=[-1] locality_id_new=[28]  
   I 03:19:05.879 locality_name_old=[] locality_name_new=[XYZ]  
   I 03:19:05.879 command=[ADD]  
   E 03:19:06.207 File on GCS has changed while reading.  
Traceback (most recent call last):  
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1535, in __call__
    rv = self.handle_exception(request, response, e)  
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1529, in __call__
    rv = self.router.dispatch(request, response)  
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher
    return route.handler_adapter(request, response)  
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 1102, in __call__
    return handler.dispatch()  
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 572, in dispatch
    return self.handle_exception(e, self.app.debug)  
  File "/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.5.2/webapp2.py", line 570, in dispatch
    return method(*args, **kwargs)  
  File "/base/data/home/apps/s~myappdomain/1.377368272328585247/main_v3.py", line 15259, in post
    gcs_file = gcs.open (index_filename, mode='r')  
  File "/base/data/home/apps/s~myappdomain/1.377368272328585247/cloudstorage/cloudstorage_api.py", line 94, in open
    buffer_size=read_buffer_size)  
  File "/base/data/home/apps/s~myappdomain/1.377368272328585247/cloudstorage/storage_api.py", line 220, in __init__
    check_response_closure()  
  File "/base/data/home/apps/s~myappdomain/1.377368272328585247/cloudstorage/storage_api.py", line 448, in _checker
    self._check_etag(resp_headers.get('etag'))  
  File "/base/data/home/apps/s~myappdomain/1.377368272328585247/cloudstorage/storage_api.py", line 476, in _check_etag
    raise ValueError('File on GCS has changed while reading.')  
ValueError: File on GCS has changed while reading.  
   I 03:19:06.235 Saved; key: __appstats__:045800, part: 144 bytes, full: 74513 bytes, overhead: 0.002 + 0.004; link: http://www.myappdomain.com/_ah/stats/details?time=1405806545812  

我怀疑是因为多个任务同时被触发,试图打开并更新文件(“X”),这导致了上面的异常。请给我建议一个方法来锁定对这个文件的访问,这样一次只有一个任务可以修改它(类似于事务处理)。

非常感谢你的帮助和指导。

更新
另一种防止上述问题的方法可能是修改以下队列的queue.yaml参数之一:

bucket_size

或者

max_concurrent_requests

但我不确定该修改哪一个。

2 个回答

0

你也可以直接依赖GCS(谷歌云存储)来使用预条件

这可以让你只更新文件。具体内容可以参考文档:

预条件通常用于一些会改变数据的请求,比如上传、删除、复制或者更新文件信息,目的是为了防止“竞争条件”的发生。竞争条件是指当同一个请求被重复发送,或者不同的操作互相干扰时可能出现的问题。比如,在网络中断后多次重试请求,或者多个用户同时对同一个文件进行读取-修改-写入操作,就可能导致竞争条件的出现。

2

一个最大并发请求数为1的任务队列应该确保每次只对一个文件进行编辑。

https://developers.google.com/appengine/docs/python/config/queue#Python_Defining_push_queues_and_processing_rates

如果你想防止同时运行太多任务,或者想避免数据存储的冲突,就可以使用最大并发请求数。

最大并发请求数(仅适用于推送队列) 设置在指定队列中可以同时执行的任务最大数量。这个值是一个整数。默认情况下,这个设置是没有限制的,也就是说可以同时运行的任务数量没有上限。使用这个设置的一个目的就是为了防止同时运行太多任务,或者避免数据存储的冲突。

限制同时运行的任务数量可以让你更好地控制队列的执行速度。例如,你可以限制运行队列任务的实例数量。在一个特定的队列中限制并发请求的数量,可以让你为其他队列或在线处理留出更多的资源。

当然,你还应该设计一些逻辑来处理失败的任务,比如让它们重试,否则你可能会遇到比现在更糟糕的问题。

撰写回答