2012-08-07 6 views
14

Tôi đang tìm cách triển khai bộ đếm lượt xem trang trong bộ nhớ bảng xanh. Nếu giả sử hai người dùng truy cập vào trang cùng một lúc và giá trị hiện tại trên PageViews = 100, liệu có đảm bảo rằng PageViews = 102 sau khi hoạt động cập nhật không?Hoạt động nguyên tử trong bộ nhớ bảng màu xanh lá cây

+1

Tôi không biết câu hỏi nhưng tại sao không chỉ thêm một cơ sở dữ liệu SQL 100 mb với $ 5 một tháng. SQL đối phó với khóa. – Paparazzi

Trả lời

23

Câu trả lời tùy thuộc vào cách bạn triển khai bộ đếm của mình. :-)

Bộ nhớ bảng không có toán tử "tăng", vì vậy, bạn cần đọc giá trị hiện tại (100) và cập nhật giá trị mới (101). Bảng lưu trữ sử dụng đồng thời lạc quan, vì vậy nếu bạn làm những gì đến một cách tự nhiên khi sử dụng thư viện máy khách lưu trữ .NET, bạn có thể thấy một ngoại lệ khi hai tiến trình đã cố thực hiện điều này cùng một lúc. Đây sẽ là dòng chảy:

  1. Process A đọc giá trị của trang được xem và nhận được 100.
  2. Process B đọc giá trị lần truy cập trang và nhận được 100.
  3. Process A chia ra một bản cập nhật có điều kiện để lần xem trang phương tiện "đặt PageViews thành 101 miễn là hiện tại là 100." Điều này thành công.
  4. Quy trình B thực hiện các thao tác tương tự và không thành công, vì điều kiện tiên quyết (PageViews == 100) là sai.

Điều hiển nhiên cần làm khi bạn nhận được lỗi là lặp lại quy trình. (Đọc giá trị hiện tại, bây giờ là 101 và cập nhật lên 102.) Điều này sẽ luôn luôn (cuối cùng) dẫn đến bộ đếm của bạn có giá trị chính xác.

Có các khả năng khác và chúng tôi đã thực hiện toàn bộ tập hợp Cloud Cover về cách triển khai bộ đếm thực sự có thể mở rộng: http://channel9.msdn.com/Shows/Cloud+Cover/Cloud-Cover-Episode-43-Scalable-Counters-with-Windows-Azure.

Điều được mô tả trong video đó có thể quá mức cần thiết nếu không xảy ra xung đột. Tức là, nếu tỷ lệ lần truy cập của bạn là một lần mỗi giây, mẫu "đọc, tăng, viết" bình thường sẽ an toàn và hiệu quả. Mặt khác, nếu bạn nhận được 1000 lượt truy cập mỗi giây, bạn sẽ muốn làm điều gì đó thông minh hơn.

EDIT

Chỉ muốn làm rõ cho những người đọc để hiểu đồng thời lạc quan ... hoạt động có điều kiện là không thực sự "thiết lập Số lần xem trang cho 101 miễn là nó hiện 100." Nó giống như "đặt PageViews thành 101 miễn là nó chưa thay đổi kể từ lần cuối tôi xem nó." (Điều này được thực hiện bằng cách sử dụng ETag đã trở lại trong yêu cầu HTTP.)

+0

Tôi sẽ đề nghị sử dụng AutoRenewLease.DoOnce (bởi người bạn tốt của chúng tôi smarx, http://blog.smarx.com/posts/managing-concurrency-in-windows-azure-with-leases) :) –

+0

Nhiều như tôi thích mọi người bằng cách sử dụng mã của tôi :-), tôi không nghĩ rằng tôi làm theo cách đó sẽ giúp đỡ ở đây? – smarx

+0

Rất tiếc, DoOnce sai, nhưng tôi sẽ sử dụng AutoRenewLease trên một blob có tên = PageView.PartitionKey + "_" + PageView.RowKey. Một khi nó đã bị khóa, nó sẽ nhận được bản ghi đó và tăng số lượng. Bằng cách này bạn có thể chắc chắn rằng mỗi lần xem trang được tính. Và tất cả điều này sử dụng Xử lý lỗi tạm thời để đảm bảo rằng - trong trường hợp xảy ra sự cố - mã sẽ thử lại cho đến khi có thể ghi lại số lần xem trang. –

8

Bạn cũng có thể suy nghĩ lại phần 'đếm'. Tại sao không biến điều này thành quy trình 2 bước?

Bước 1 - Ghi lần xem trang

Mỗi lần ai đó xem một trang thêm một kỷ lục vào một bảng (chúng ta hãy gọi nó xem trang). Các thông tin mà bạn sẽ thêm vào một trong những cửa hàng sẽ được như sau:

  • PartitionKey = pagename
  • RowKey = Random GUID

Sau một vài lần xem bạn sẽ phải một cái gì đó như thế này:

  • MyPage.aspx - someGuid
  • MyPage.aspx - someGuid
  • SomePage.aspx - someGuid
  • MyPage.aspx - someGuid

Bước 2 - Đếm xem trang

gì chúng tôi muốn làm bây giờ là có được tất cả những hồ sơ, đếm chúng, tăng một truy cập một nơi nào đó và xóa tất cả hồ sơ. Giả sử bạn có nhiều công nhân đang chạy. Cả hai công nhân của bạn sẽ có một vòng lặp ngẫu nhiên chạy từ 1 đến 10 phút. Mỗi khi thời gian của người lao động trôi qua, nó sẽ lấy tiền thuê trên một blob nếu không có hợp đồng thuê nào được thực hiện (điều này luôn luôn là cùng một đốm màu, bạn có thể sử dụng AutoRenewLease).

Nhân viên đầu tiên nhận được khóa có thể đi trước và làm đếm:

  1. Nhận tất cả các bản ghi từ bảng PageViewRecordings hoặc từ bộ nhớ cache
  2. Đếm tất cả các lượt truy cập mỗi trang
  3. Cập nhật đếm đâu đó
  4. Xóa các bản ghi đã được tính đến khi đếm

Vấn đề ở đây là t mũ nó rất khó để biến điều này thành một quá trình idempotent. Điều gì sẽ xảy ra nếu trường hợp của bạn bị treo giữa số đếm và xóa? Bạn sẽ tăng số lượng trang, nhưng vì các mục không bị xóa, chúng sẽ được thêm vào tổng số lần tiếp theo khi bạn xử lý chúng.

Đây là lý do tại sao tôi sẽ đề xuất những điều sau đây. Trong cùng một bảng (PageViews), bạn cũng sẽ ghi lại tổng số lần xem trang, trong cùng một phân vùng đó. Tuy nhiên, dữ liệu sẽ có một chút khác nhau (điều này sẽ là một hồ sơ duy nhất trong phân vùng mà giữ tổng số):

  • PartitionKey = pagename
  • RowKey = Guid.Empty (chỉ cần không sử dụng một GUID ngẫu nhiên , theo cách này, chúng tôi biết sự khác biệt giữa lượt xem trang được ghi lại và bản ghi giữ tổng số).
  • Đếm = Quan điểm trang hiện đếm

này là hoàn toàn có thể bởi vì Bảng lưu trữ là schema ít hơn. Và vì sao chúng ta lại đang làm việc này? Bởi vì chúng ta có các giao dịch nếu chúng ta giới hạn mình vào cùng một bảng + phân vùng với một maxmium của 100 thực thể. Chúng ta có thể làm gì với điều này?

  1. Sử dụng, chúng tôi nhận 100 bản ghi từ bảng + phân vùng đó.
  2. Bản ghi đầu tiên chúng tôi nhận được là bản ghi 'bộ đếm'. Tại sao? Bởi vì nó là rowkey Guid.Empty và phân loại là hoặc null
  3. Đếm những hồ sơ này (-1 vì kỷ lục đầu tiên không phải là một lần xem trang, nó chỉ giữ chỗ truy cập của chúng tôi)
  4. Cập nhật các tước tài sản của bản ghi truy cập
  5. Xóa 99 (hoặc ít hơn) các bản ghi khác
  6. LưuCách sử dụng Lô.
  7. Lặp lại cho đến khi chỉ còn lại 1 bản ghi (bản ghi truy cập).

Và mỗi X phút nhân viên của bạn sẽ thấy nếu không có hợp đồng thuê, hãy thuê và khởi động lại quy trình.

Câu trả lời này có đủ rõ ràng hay tôi nên thêm một số mã?

+0

Bây giờ tôi hiểu những gì bạn đang nói về hợp đồng thuê blob. Điều này là hợp lý, nhưng tôi vẫn thích thứ gì đó như sharding (như trong tập Cover Cloud). – smarx

+0

Tôi thích ý tưởng này. Không cần mã, tôi hiểu rõ. Nhưng bạn có nghĩa là, "nếu có ** không phải là ** một hợp đồng thuê thì nhân viên sẽ thuê và khởi động lại quy trình" đúng không? – States

+0

Có, tôi đã cập nhật câu trả lời. –

1

Tôi đến cùng một câu hỏi. Với thư viện python Azure, tôi đang phát triển tăng số lượt truy cập đơn giản bằng cách sử dụng eTagIf-Match thay vì khóa. Ý tưởng cơ bản là thử lại để tăng bộ đếm cho đến khi bản cập nhật chạy thành công theo một tiêu chí nhất định, không có bản cập nhật nào khác can thiệp vào bản cập nhật đang chạy này. Nếu yêu cầu cập nhật là nặng, sharding nên được gọi.

https://github.com/flyakite/simple-scalable-datastore/blob/master/datastore/azuretable.py

1

Nếu sử dụng trang web Azure, sau đó Azure Queues và WebJobs là một tùy chọn. Trong một kịch bản của tôi mặc dù tôi thực sự sẽ có cách tiếp cận sharding và có WebJobs cập nhật các tập hợp định kỳ. Bảng lưu trữ bảng Azure của UserPageViews với PartitionKey = Người dùng và RowKey = Trang. Hai người dùng đồng thời có cùng id người dùng sẽ không được phép.