2013-03-15 22 views
7

Tôi nghi ngờ điều này thậm chí còn có thể, nhưng đây là vấn đề và giải pháp đề xuất (tính khả thi của các giải pháp đề xuất là đối tượng của câu hỏi này):


Tôi có một số "dữ liệu toàn cầu" cần phải có sẵn cho tất cả các yêu cầu. Tôi đang lưu giữ dữ liệu này cho Riak và sử dụng Redis làm lớp lưu trữ cho tốc độ truy cập (hiện tại ...). Dữ liệu được chia thành khoảng 30 khối logic, mỗi khoảng 8 KB.dai dẳng trong bộ nhớ Python đối tượng cho máy chủ nginx/uwsgi

Mỗi yêu cầu được yêu cầu để đọc 4 trong số 8KB khối này, dẫn đến 32KB dữ liệu được đọc từ Redis hoặc Riak. Đây là trong ADDITION cho bất kỳ dữ liệu yêu cầu cụ thể mà cũng cần phải được đọc (mà là khá một chút).

Giả sử thậm chí 3000 yêu cầu mỗi giây (đây không phải là máy chủ trực tiếp nên tôi không có số thực, nhưng 3000ps là giả định hợp lý, có thể nhiều hơn), điều này có nghĩa là 96KBps chuyển từ Redis hoặc Riak trong ADDITION cho các cuộc gọi khác không đáng kể được thực hiện từ logic ứng dụng. Ngoài ra, Python đang phân tích cú pháp JSON của các đối tượng 8KB này 3000 lần mỗi giây.


Tất cả điều này - đặc biệt là Python phải liên tục deserialize dữ liệu - có vẻ như một sự lãng phí hoàn toàn, và một giải pháp hoàn hảo nhã sẽ chỉ có các dữ liệu deserialized lưu trữ trong một trong bộ nhớ vật bản địa Python, mà tôi có thể làm mới định kỳ và khi tất cả dữ liệu "tĩnh" này trở nên cũ. Một lần trong một vài phút (hoặc giờ), thay vì 3000 lần mỗi giây.

Nhưng tôi không biết điều này có thể xảy ra hay không. Bạn thực sự cần một ứng dụng "luôn chạy" để nó lưu trữ bất kỳ dữ liệu nào trong bộ nhớ của nó. Và tôi biết đây không phải là trường hợp trong sự kết hợp nginx + uwsgi + python (so với một cái gì đó như nút) - dữ liệu trong bộ nhớ python sẽ KHÔNG được duy trì trên tất cả các yêu cầu với kiến ​​thức của tôi, trừ khi tôi bị nhầm lẫn một cách khủng khiếp. Không may là đây là một hệ thống mà tôi đã "kế thừa" và do đó không thể thực hiện quá nhiều thay đổi về công nghệ cơ sở, cũng như tôi không am hiểu về cách kết hợp nginx + uwsgi + python hoạt động như thế nào khi bắt đầu Python xử lý và lưu giữ dữ liệu trong bộ nhớ Python - điều đó có nghĩa là tôi có thể bị nhầm lẫn với giả định của tôi ở trên!


Vì vậy, tư vấn trực tiếp về việc liệu giải pháp này sẽ làm việc + tài liệu tham khảo vào tài liệu mà có thể giúp tôi hiểu làm thế nào nginx + uwsgi + python sẽ làm việc trong điều kiện bắt đầu quy trình mới và cấp phát bộ nhớ, sẽ giúp rất nhiều .

Tái bút:

  1. đã trải qua một số tài liệu cho nginx, uwsgi vv nhưng chưa hiểu hết được hậu quả mỗi lần sử dụng-trường hợp của tôi được nêu ra. Hy vọng thực hiện một số tiến bộ về điều đó trong tương lai

  2. Nếu điều trong bộ nhớ COULD hoạt động, tôi sẽ đổi Redis, vì tôi đang lưu bộ nhớ CHỈ dữ liệu tĩnh tôi đã đề cập ở trên, trong đó. Điều này làm cho bộ nhớ cache Python trong bộ nhớ trong bộ nhớ còn hấp dẫn hơn nữa, hấp dẫn hơn cho tôi, giảm một phần chuyển động trong hệ thống và ít nhất BỐN chuyến đi khứ hồi theo yêu cầu.

+0

Dữ liệu này trông như thế nào? Cấu trúc cứng nhắc như thế nào? Mức độ thường xuyên thay đổi? – abarnert

+0

Tập hợp lớn các cặp khóa-giá trị với một số tham gia lồng nhau. Cấu trúc mẫu (được biểu thị bằng JSON): {key1: value1, key2: {subkey1: [value1, value2, value3], subkey2: value2}, key3: [value1, value2, value3]}. Vì vậy, một số lượng hợp lý của đa dạng trong dữ liệu, nhưng như tôi đã nói nó là khá tĩnh và tôi có thể chịu với việc cập nhật nó chỉ mỗi vài phút hoặc thậm chí mỗi 1 giờ. –

Trả lời

3

Điều bạn đang đề xuất không khả thi trực tiếp. Vì các quy trình mới có thể được tách lên và nằm ngoài tầm kiểm soát của bạn, nên không có cách nào để giữ dữ liệu Python gốc trong bộ nhớ.

Tuy nhiên, có một số cách để giải quyết vấn đề này.

Thông thường, bạn chỉ cần một cấp bộ nhớ khóa-giá trị. Và đôi khi, có bộ đệm có kích thước cố định cho các giá trị (bạn có thể sử dụng trực tiếp các đối tượng str/bytes/bytearray; bất kỳ thứ gì bạn cần phải struct trong đó hoặc theo thứ tự khác) là tất cả những gì bạn cần. Trong trường hợp đó, tích hợp sẵn caching framework của uWSGI sẽ giúp bạn giải quyết mọi thứ bạn cần.

Nếu bạn cần kiểm soát chính xác hơn, bạn có thể xem bộ nhớ cache được triển khai như thế nào trên đầu trang SharedArea và làm điều gì đó tùy chỉnh. Tuy nhiên, tôi sẽ không đề nghị điều đó. Về cơ bản nó cung cấp cho bạn cùng một loại API bạn nhận được với một tập tin, và những lợi thế thực sự duy nhất chỉ bằng cách sử dụng một tập tin là máy chủ sẽ quản lý tuổi thọ của tập tin; nó hoạt động trong tất cả các ngôn ngữ được hỗ trợ uWSGI, ngay cả những ngôn ngữ không cho phép các tệp; và nó giúp bạn dễ dàng di chuyển bộ nhớ cache tùy chỉnh của mình sang bộ nhớ cache được phân phối (nhiều máy tính) nếu sau này bạn cần. Tôi không nghĩ bất kỳ cái nào trong số đó phù hợp với bạn.

Một cách khác để lưu trữ khóa-giá trị bằng phẳng, nhưng không có bộ đệm có kích thước cố định, là với stdlib của Python anydbm. Tra cứu khóa-giá trị là như pythonic khi nó nhận được: nó trông giống như một dict, ngoại trừ việc nó được sao lưu vào cơ sở dữ liệu trên BDB (hoặc tương tự), được lưu vào bộ nhớ cache thích hợp trong bộ nhớ, thay vì được lưu trữ trong một bảng băm bộ nhớ.

Nếu bạn cần xử lý một vài loại đơn giản khác — bất kỳ thứ gì cực kỳ nhanh đến un/pickle, như int s — bạn có thể muốn xem xét shelve.

Nếu cấu trúc của bạn đủ cứng, bạn có thể sử dụng cơ sở dữ liệu khóa-giá trị cho cấp cao nhất, nhưng truy cập các giá trị thông qua ctypes.Structure hoặc de/serialize với struct. Nhưng thông thường, nếu bạn có thể làm điều đó, bạn cũng có thể loại bỏ cấp cao nhất, tại thời điểm đó toàn bộ điều của bạn chỉ là một lớn Structure hoặc Array.

Vào thời điểm đó, bạn chỉ có thể sử dụng một tập tin đơn giản để lưu trữ-một trong hai mmap nó (ví ctypes), hoặc chỉ openread nó (ví struct).

Hoặc sử dụng multiprocessing 's Shared ctypes Objects để truy cập trực tiếp vào Structure trực tiếp ra khỏi khu vực bộ nhớ dùng chung.

Trong khi đó, nếu bạn không thực sự cần tất cả dữ liệu bộ nhớ cache tất cả thời gian, chỉ cần bit và miếng mỗi lần trong một thời gian, đó là chính xác những gì cơ sở dữ liệu được cho. Một lần nữa, anydbm, v.v ... có thể là tất cả những gì bạn cần, nhưng nếu bạn có cấu trúc phức tạp, hãy vẽ sơ đồ ER, biến nó thành một tập hợp các bảng và sử dụng một cái gì đó như MySQL.

+0

Với dữ liệu hỗn hợp (phao và chuỗi), một số tìm kiếm chung cho điểm chuẩn cho thấy simplejson nhanh hơn cpickle. Đó là lý do tại sao tôi đã nói về ví dụ JSON, và cũng "xếp" vv vào lúc này dường như nằm ngoài phạm vi. Và sẽ đọc từ tập tin thực sự được nhanh hơn so với đánh Redis - nói trên localhost? Tất nhiên, xem xét chúng tôi đang nói về khoảng 31KB chỉ của dữ liệu tĩnh, có vẻ như nó muốn được đánh bộ nhớ cache đĩa một lần nữa và một lần nữa chứ không phải là nhấn trục chính ở tất cả. "Caching của uwsgi" trông rất thú vị, và gần như là một trận đấu hoàn hảo, trừ khi tôi gặp phải một số vấn đề. –

+0

Tôi cho rằng bộ nhớ cache uwsgi có thể truy cập được "trong quá trình" từ Python và tự nhiên nhanh hơn vài lần so với Redis. Điều đó có vẻ đúng, nhưng chỉ xác nhận để đảm bảo sự hiểu biết của tôi về các quy tắc cơ bản ở đây là chính xác. –

+0

Tại 32KB, sự khác biệt giữa bộ nhớ chia sẻ, tệp 'mmap'ed hoặc' đọc'ing tệp từ "đĩa" (như bạn nói, bộ nhớ cache trên đĩa OS), v.v. có lẽ không quan trọng lắm.Gửi nó qua một socket localhost TCP không nên thêm nhiều. (Nhưng rõ ràng, thử nghiệm.) Đối với vấn đề JSON-so-pickle, nếu bạn chỉ có một cấp (một dict đầy phao và dây), bạn sẽ không lưu trữ dữ liệu hỗn hợp; mỗi giá trị chỉ là một phao hoặc chuỗi đơn giản. Nhưng bạn không; bạn đã có một vài cấp độ, do đó, ... shelve là ra ngoài. – abarnert

0

Tôi chưa bao giờ thực sự cố gắng bản thân mình, nhưng bạn có thể có thể sử dụng uWSGI của SharedArea để thực hiện những gì bạn đang sau?

+0

Bạn sẽ phải xây dựng rất nhiều trên đầu trang để làm cho nó có thể sử dụng được. Về cơ bản, điều này cung cấp cho bạn cùng một loại API bạn nhận được từ một đối tượng tệp; đó là nó. Khi "Cảnh báo" ở đầu trang bạn đã liên kết cho biết: "SharedArea là một cơ chế cấp rất thấp. Để có một lựa chọn dễ sử dụng hơn, hãy xem các khuôn khổ Caching và Queue." – abarnert

0

"dữ liệu trong bộ nhớ python sẽ KHÔNG được duy trì trên tất cả các yêu cầu đối với kiến ​​thức của tôi, trừ khi tôi bị nhầm lẫn một cách khủng khiếp".

bạn bị nhầm lẫn.

toàn bộ điểm sử dụng uwsgi, cơ chế CGI là duy trì dữ liệu qua các chủ đề và tiết kiệm chi phí khởi tạo cho mỗi cuộc gọi. bạn phải đặt processes = 1 trong tệp .ini của bạn, hoặc, tùy thuộc vào cách cấu hình uwsgi, nó có thể khởi chạy hơn 1 quy trình nhân viên nhân danh bạn. đăng nhập env và tìm kiếm 'wsgi.multiprocess': False'wsgi.multithread': True và tất cả các chủ đề uwsgi.core cho công nhân đơn lẻ sẽ hiển thị cùng một dữ liệu.

bạn cũng có thể xem có bao nhiêu quy trình công nhân và chuỗi "cốt lõi" trong mỗi luồng, bạn có bằng cách sử dụng được xây dựng trong stats-server.

đó là lý do tại sao uwsgi cung cấp các chức năng lockunlock để thao tác lưu trữ dữ liệu theo nhiều luồng.

bạn có thể dễ dàng kiểm tra điều này bằng cách thêm một tuyến đường /status trong ứng dụng của bạn chỉ xuất hiện biểu tượng json của đối tượng dữ liệu toàn cầu của bạn và xem thường xuyên sau hành động cập nhật cửa hàng.

1

Bạn không nói gì về việc viết lại dữ liệu này, nó có tĩnh không? Trong trường hợp này, giải pháp là đơn giản, và tôi không có đầu mối gì với tất cả các câu trả lời "nó không khả thi".

Công nhân Uwsgi ứng dụng luôn chạy. Vì vậy, dữ liệu hoàn toàn được duy trì giữa các yêu cầu. Tất cả những gì bạn cần làm là lưu trữ nội dung trong một biến toàn cầu, có nghĩa là nó. Và hãy nhớ rằng đó là mỗi công nhân, và công nhân làm khởi động lại theo thời gian, vì vậy bạn cần chiến lược tải/hủy hợp lệ.

Nếu dữ liệu được cập nhật rất hiếm khi (hiếm khi đủ để khởi động lại máy chủ khi có), bạn có thể tiết kiệm nhiều hơn. Chỉ cần tạo các đối tượng trong khi xây dựng ứng dụng. Bằng cách này, chúng sẽ được tạo chính xác một lần, và sau đó tất cả các công nhân sẽ rút khỏi tổng thể và sử dụng lại cùng một dữ liệu. Tất nhiên, đó là copy-on-write, vì vậy nếu bạn cập nhật nó, bạn sẽ mất các lợi ích bộ nhớ (cùng một điều sẽ xảy ra nếu python quyết định thu gọn bộ nhớ của nó trong khi chạy gc, vì vậy nó không phải là siêu dự đoán).

+1

Whoa, necropost. Đã không nhận thấy ngày trước đó. Tôi tự hỏi tại sao SO quyết định cho tôi xem bài đăng này? – letitbee