Những nhược điểm của việc sử dụng kết nối liên tục trong PDO là gì


181

Trong PDO, một kết nối có thể được thực hiện liên tục bằng cách sử dụng PDO::ATTR_PERSISTENTthuộc tính. Theo hướng dẫn sử dụng php -

Các kết nối liên tục không được đóng ở cuối tập lệnh, nhưng được lưu trữ và sử dụng lại khi tập lệnh khác yêu cầu kết nối sử dụng cùng thông tin đăng nhập. Bộ đệm kết nối liên tục cho phép bạn tránh được chi phí thiết lập kết nối mới mỗi khi tập lệnh cần nói chuyện với cơ sở dữ liệu, dẫn đến ứng dụng web nhanh hơn.

Hướng dẫn cũng khuyến nghị không sử dụng kết nối liên tục trong khi sử dụng trình điều khiển PDO ODBC, vì nó có thể cản trở quá trình Pooling kết nối ODBC.

Vì vậy, rõ ràng dường như không có nhược điểm nào của việc sử dụng kết nối liên tục trong PDO, ngoại trừ trong trường hợp cuối cùng. Tuy nhiên, tôi muốn biết liệu có bất kỳ nhược điểm nào khác khi sử dụng cơ chế này hay không, tức là tình huống cơ chế này dẫn đến suy giảm hiệu suất hoặc một cái gì đó tương tự.


Wow, bạn đã trả 1000 tiền thưởng cho câu hỏi đơn giản này?
Pacerier

Câu trả lời:


287

Hãy chắc chắn đọc câu trả lời dưới đây , trong đó chi tiết các cách để giảm thiểu các vấn đề được nêu ở đây.


Những nhược điểm tương tự tồn tại khi sử dụng PDO như với bất kỳ giao diện cơ sở dữ liệu PHP nào khác có các kết nối liên tục: nếu tập lệnh của bạn kết thúc bất ngờ ở giữa các hoạt động của cơ sở dữ liệu, yêu cầu tiếp theo có kết nối còn lại sẽ chọn nơi tập lệnh chết bị tắt. Kết nối được giữ mở ở cấp trình quản lý quy trình (Apache cho mod_php, quy trình FastCGI hiện tại nếu bạn đang sử dụng FastCGI, v.v.), không phải ở cấp độ PHP và PHP không cho biết quy trình cha mẹ cho phép kết nối chết khi kịch bản chấm dứt bất thường.

Nếu tập lệnh chết bảng bị khóa, các bảng đó sẽ vẫn bị khóa cho đến khi kết nối bị chết hoặc tập lệnh tiếp theo có kết nối sẽ tự mở khóa các bảng.

Nếu tập lệnh chết nằm ở giữa một giao dịch, có thể chặn vô số bảng cho đến khi bộ đếm thời gian bế tắc bắt đầu, và thậm chí sau đó, bộ đếm thời gian bế tắc có thể giết chết yêu cầu mới hơn thay vì yêu cầu cũ hơn gây ra sự cố.

Nếu tập lệnh chết nằm ở giữa một giao dịch, tập lệnh tiếp theo có kết nối đó cũng có trạng thái giao dịch. Rất có thể (tùy thuộc vào thiết kế ứng dụng của bạn) rằng tập lệnh tiếp theo có thể không thực sự cố gắng thực hiện giao dịch hiện tại hoặc sẽ cam kết khi không nên hoặc quay lại khi không nên có.

Đây chỉ là phần nổi của tảng băng chìm. Tất cả có thể được giảm nhẹ đến một mức độ bằng cách luôn cố gắng dọn dẹp sau khi kết nối bẩn trên mỗi yêu cầu tập lệnh, nhưng đó có thể là một nỗi đau tùy thuộc vào cơ sở dữ liệu. Trừ khi bạn đã xác định tạo ra các kết nối cơ sở dữ liệu như một điều đó là một nút cổ chai trong kịch bản của bạn (phương tiện này, bạn đã đang done profiling sử dụng Xdebug và / hoặc xhprof ), bạn nên không xem xét kết nối liên tục như một giải pháp cho bất cứ điều gì.

Hơn nữa, hầu hết các cơ sở dữ liệu hiện đại (bao gồm PostgreSQL) có các cách thực hiện nhóm kết nối ưa thích của riêng chúng mà không có nhược điểm ngay lập tức mà các kết nối liên tục dựa trên vanilla PHP làm.


Để làm rõ một điểm, chúng tôi sử dụng các kết nối liên tục tại nơi làm việc của tôi, nhưng không phải bằng sự lựa chọn. Chúng tôi đã gặp phải hành vi kết nối kỳ lạ , trong đó kết nối ban đầu từ máy chủ ứng dụng đến máy chủ cơ sở dữ liệu của chúng tôi mất đúng ba giây, khi đó nó chỉ mất một phần của một phần giây. Chúng tôi nghĩ rằng đó là một lỗi kernel. Chúng tôi đã từ bỏ việc cố gắng khắc phục sự cố vì nó xảy ra ngẫu nhiên và không thể sao chép theo yêu cầu và CNTT thuê ngoài của chúng tôi không có khả năng cụ thể để theo dõi nó.

Bất kể, khi những người trong kho đang xử lý vài trăm bộ phận đến và mỗi bộ phận mất ba giây rưỡi thay vì nửa giây, chúng tôi phải hành động trước khi họ bắt cóc tất cả chúng tôi và bắt chúng tôi giúp họ. Vì vậy, chúng tôi đã đưa ra một vài điều trong sự quái dị của ERP / CRM / CMS được phát triển tại nhà của chúng tôi và trải nghiệm tất cả sự khủng khiếp của các kết nối liên tục trong tay. Chúng tôi đã mất nhiều tuần để theo dõi tất cả các vấn đề nhỏ tinh tế và hành vi kỳ quái xảy ra dường như ngẫu nhiên. Nó chỉ ra rằng những lỗi nghiêm trọng một lần một tuần mà người dùng của chúng tôi siêng năng vắt kiệt khỏi ứng dụng của chúng tôi đã để lại các bảng bị khóa, giao dịch bị bỏ rơi và các trạng thái đáng tiếc khác.

Câu chuyện thổn thức này có một điểm: Nó đã phá vỡ những thứ mà chúng ta không bao giờ mong muốn phá vỡ, tất cả đều nhân danh hiệu suất. Sự đánh đổi là không đáng, và chúng tôi háo hức chờ đợi ngày chúng tôi có thể quay lại các kết nối bình thường mà không có sự náo loạn từ người dùng của chúng tôi.


2
Tôi hy vọng tôi đã đọc câu trả lời này trước khi chạySELECT orders.* FROM orders LEFT JOIN items USING(item_id)
Ast Derek

31
Tôi biết một trang web lớn đã sử dụng các kết nối liên tục trong gần một thập kỷ nay. Thủ thuật là sử dụng một lớp phía trên phần mở rộng DB và để nó nhớ những thứ cần được dọn sạch bằng cách sử dụng register_shutdown_function(). Nếu quá trình chết, kết nối cũng chết. Nếu không, kết nối sẽ được đặt lại về trạng thái sạch (ví dụ: các giao dịch mở được khôi phục). Nếu điều này không thành công, kết nối sẽ bị đóng và một kết nối mới sẽ được mở theo yêu cầu tiếp theo cho cùng một quy trình. Không cần phải hủy bỏ các kết nối liên tục.
Walter Tross

Tôi tò mò @Charles ... vấn đề của bạn đã được giải quyết chưa?
Tschallacka

@MichaelDibbets Chúng tôi đã thay thế máy chủ ứng dụng vài tháng trước và bật pconnect để xem liệu lỗi thứ ba có còn tồn tại không. Không phải vậy. Nó đã được giải quyết bằng proxy, tôi cho rằng. Câu trả lời dưới đây liên quan đến mysqli_change_usercó lẽ vẫn là cách giải quyết tốt nhất cho những người phải thực hiện các kết nối liên tục trong một ứng dụng không được thiết kế để xử lý các vấn đề về trạng thái.
Charles

5
Chúng tôi đã có độ trễ 5 giây khi kết nối, chúng tôi đã cố gắng cách ly như một sự cố DNS + IPv6. Máy chủ đang tìm kiếm một địa chỉ v6, không thành công và sau đó sử dụng địa chỉ IPv4.
Nigel Atkinson

45

Đáp lại vấn đề của Charles ở trên,

Từ: http://www.php.net/manual/en/mysqli.quickstart.connections.php -

Một khiếu nại phổ biến về các kết nối liên tục là trạng thái của chúng không được thiết lập lại trước khi sử dụng lại. Ví dụ: các giao dịch mở và chưa hoàn thành không tự động được khôi phục. Nhưng đồng thời, những thay đổi ủy quyền xảy ra trong thời gian giữa việc đặt kết nối vào nhóm và sử dụng lại không được phản ánh. Điều này có thể được coi là một tác dụng phụ không mong muốn. Trái lại, cái tên dai dẳng có thể được hiểu là một lời hứa rằng nhà nước vẫn tồn tại.

Tiện ích mở rộng mysqli hỗ trợ cả hai cách hiểu về kết nối liên tục: trạng thái tồn tại và thiết lập lại trạng thái trước khi sử dụng lại. Mặc định được đặt lại. Trước khi kết nối liên tục được sử dụng lại, tiện ích mở rộng mysqli gọi ngầm mysqli_change_user()để đặt lại trạng thái. Kết nối liên tục xuất hiện cho người dùng như thể nó vừa được mở. Không có tạo tác từ các tập quán trước đó có thể nhìn thấy.

Các mysqli_change_user()chức năng là một hoạt động đắt tiền. Để có hiệu suất tốt nhất, người dùng có thể muốn biên dịch lại tiện ích mở rộng với cờ biên dịch MYSQLI_NO_CHANGE_USER_ON_PCONNECTđược đặt.

Người dùng có thể lựa chọn giữa hành vi an toàn và hiệu suất tốt nhất. Cả hai đều là mục tiêu tối ưu hóa hợp lệ. Để dễ sử dụng, hành vi an toàn đã được mặc định với chi phí hiệu suất tối đa.


+1, nếu không phải vì thực tế là chúng tôi đã dọn dẹp mớ hỗn độn theo những cách khác, tôi rất muốn xem nếu gọi thủ công Change_user sẽ khắc phục các sự cố không rõ trạng thái kỳ lạ của chúng tôi.
Charles

Tương đương với các kết nối liên tục PDO Postgres là gì? Tôi gặp vấn đề tương tự như @Charles, trong một thời gian, người dùng sẽ gặp lỗi như tìm nạp sql - máy chủ đóng kết nối bất ngờ Điều này có thể có nghĩa là máy chủ bị chấm dứt bất thường Khi chạy truy vấn CHỌN đơn giản (thậm chí không giao dịch).
Carmageddon

1
@Carmageddon, điều đó phù hợp hơn với một câu hỏi mới, nhưng tl; dr là Postgres không thực hiện kết nối và thay vào đó bạn nên sử dụng một trong các nhóm kết nối bên ngoài.
Charles

@ Charles, ý của bạn là gì? đang sử dụng kết nối liên tục của PDO không tương đương với sử dụng "nhóm kết nối bên ngoài"? hoặc bạn có ý gì?
Carmageddon

@Carmageddon, ý tôi là cộng đồng Postgres đã giải quyết việc kết nối như một giải pháp tốt hơn so với kết nối. Kiểm tra pgbouncer hoặc pgpool-II. Tôi không chắc chắn rằng PDO có Postgres kết nối hay không, nhưng tôi có thể hoàn toàn tắt rocker của mình.
Charles

13

Kết nối liên tục là một ý tưởng tốt chỉ khi mất một thời gian (tương đối) để kết nối với cơ sở dữ liệu của bạn. Ngày nay điều đó gần như không bao giờ xảy ra. Hạn chế lớn nhất đối với các kết nối liên tục là nó giới hạn số lượng người dùng bạn có thể duyệt trang web của mình: nếu MySQL được định cấu hình chỉ cho phép 10 kết nối đồng thời cùng một lúc thì khi một người thứ 11 cố gắng duyệt trang web của bạn thì nó sẽ không hoạt động cho họ .

PDO không quản lý sự kiên trì. Trình điều khiển MySQL nào. Nó sử dụng lại các kết nối khi a) chúng có sẵn và máy chủ / người dùng / mật khẩu / cơ sở dữ liệu khớp. Nếu có thay đổi thì nó sẽ không sử dụng lại kết nối. Hiệu ứng mạng tốt nhất là các kết nối bạn có sẽ được bắt đầu và dừng thường xuyên vì bạn có những người dùng khác nhau trên trang web và khiến chúng tồn tại không liên tục.

Điều quan trọng để hiểu về các kết nối liên tục là bạn KHÔNG nên sử dụng chúng trong hầu hết các ứng dụng web. Chúng nghe có vẻ lôi cuốn nhưng chúng nguy hiểm và khá vô dụng.

Tôi chắc chắn có các luồng khác về điều này nhưng một kết nối liên tục là nguy hiểm vì nó vẫn tồn tại giữa các yêu cầu. Ví dụ, nếu bạn khóa một bảng trong khi yêu cầu và sau đó không mở khóa thì bảng đó sẽ bị khóa vô thời hạn. Các kết nối liên tục cũng khá vô dụng đối với 99% ứng dụng của bạn vì bạn không có cách nào để biết liệu cùng một kết nối sẽ được sử dụng giữa các yêu cầu khác nhau. Mỗi luồng web sẽ có tập hợp các kết nối liên tục của riêng nó và bạn không có cách nào kiểm soát luồng nào sẽ xử lý các yêu cầu nào.

Thư viện mysql thủ tục của PHP, có một tính năng theo đó các cuộc gọi tiếp theo tới mysql_connect sẽ trả về cùng một liên kết, thay vì mở một kết nối khác (Như người ta có thể mong đợi). Điều này không có gì để làm với các kết nối liên tục và đặc trưng cho thư viện mysql. PDO không thể hiện hành vi như vậy


Liên kết tài nguyên: liên kết

Nói chung, bạn có thể sử dụng điều này như một "quy tắc" thô:

, sử dụng các kết nối liên tục, nếu:

  • Chỉ có vài ứng dụng / người dùng truy cập cơ sở dữ liệu, tức là bạn sẽ không dẫn đến 200 kết nối mở (nhưng có thể không hoạt động), vì có 200 người dùng khác nhau được chia sẻ trên cùng một máy chủ.
  • Cơ sở dữ liệu đang chạy trên một máy chủ khác mà bạn đang truy cập qua mạng

  • Một (một) ứng dụng truy cập cơ sở dữ liệu rất thường xuyên

KHÔNG , không sử dụng các kết nối liên tục, nếu:

  • Ứng dụng của bạn chỉ cần truy cập cơ sở dữ liệu 100 lần một giờ.

  • Bạn có nhiều, nhiều máy chủ web truy cập vào một máy chủ cơ sở dữ liệu

Sử dụng các kết nối liên tục nhanh hơn đáng kể, đặc biệt nếu bạn đang truy cập cơ sở dữ liệu qua mạng. Sẽ không có quá nhiều khác biệt nếu cơ sở dữ liệu đang chạy trên cùng một máy, nhưng nó vẫn nhanh hơn một chút. Tuy nhiên - như tên gọi - kết nối vẫn tồn tại, tức là nó vẫn mở, ngay cả khi nó không được sử dụng.

Vấn đề với điều đó là, trong "cấu hình mặc định", MySQL chỉ cho phép 1000 "kênh mở" song song. Sau đó, các kết nối mới bị từ chối (Bạn có thể điều chỉnh cài đặt này). Vì vậy, nếu bạn có - giả sử - 20 Máy chủ web với mỗi 100 Khách hàng trên đó và mỗi người trong số họ chỉ có một truy cập mỗi trang, toán học đơn giản sẽ cho bạn thấy rằng bạn sẽ cần 2000 kết nối song song với cơ sở dữ liệu. Điều đó sẽ không làm việc.

Ergo: Chỉ sử dụng nó cho các ứng dụng có nhiều yêu cầu.


4
Sau dòng câu trả lời của bạn là sao chép dán từ stackoverflow.com/a/51583/718224
Tony Stark

1
"CÓ, sử dụng các kết nối liên tục, nếu: [...] Chỉ có vài ứng dụng / người dùng truy cập cơ sở dữ liệu" mâu thuẫn với "Chỉ sử dụng nó cho các ứng dụng có nhiều yêu cầu.". Điều này sau đó là chính xác. Tình huống: hàng ngàn yêu cầu mỗi giây sẽ dẫn đến hàng trăm kết nối cơ sở dữ liệu hoạt động. Khi một hệ thống chia tỷ lệ tuyến tính, nó cũng sẽ quy mô tuyến tính số lượng kết nối đến cơ sở dữ liệu. Vì vậy, nhiều yêu cầu hơn (nhiều người dùng hơn) sẽ dẫn đến nhiều kết nối hơn. Vì vậy, bạn cần giới hạn (!) Nhưng nhiều kết nối hoạt động khi bạn có nhiều yêu cầu (người dùng)
Ken Van Hoeylandt

12

Trong các thử nghiệm của mình, tôi đã có thời gian kết nối hơn một giây với localhost của mình, do đó, giả sử tôi nên sử dụng kết nối liên tục. Các thử nghiệm khác cho thấy đó là một vấn đề với 'localhost':

Kết quả kiểm tra tính bằng giây (được đo bằng php microtime):

  • web được lưu trữ: connectDB: 0,0038912296295166
  • localhost: connectDB: 1.0214691162109 (hơn một giây: không sử dụng localhost!)
  • 127.0.0.1: kết nốiDB: 0,00097203254699707

Thật thú vị: Đoạn mã sau cũng nhanh như sử dụng 127.0.0.1:

$host = gethostbyname('localhost');
// echo "<p>$host</p>";
$db = new PDO("mysql:host=$host;dbname=" . DATABASE . ';charset=utf8', $username, $password,
    array(PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

Có vẻ như PDO gặp khó khăn trong việc dịch tên miền! Cảm ơn bạn, tôi đã tự hỏi tại sao mỗi kết nối mất nhiều thời gian trên máy lõi tứ của tôi!
Mustafa

@Gunnar Bernstein +1 tìm tốt đẹp. "localhost" chắc chắn sẽ mất nhiều thời gian hơn và điều này đã cải thiện tốc độ của ứng dụng web của tôi một chút (nó tạo ra rất nhiều kết nối).
đế chế2335

1
Điều đó thật tuyệt. Có gì đó không ổn với độ phân giải trên máy phát triển của tôi ... sử dụng IP đã lấy tập lệnh của tôi từ 6.1 đến 1.1
Pete

localhostsử dụng kết nối ổ cắm, kết nối ổ cắm nổi tiếng là xấu trên số lượng lớn kết nối
mente

@mente Bất kỳ tài liệu tham khảo, tài nguyên có thể chứng minh thực tế đó? Tôi có xu hướng nghĩ rằng UDS được ưa thích hơn TCP. Cảm ơn.
Nuxwin

6

Các kết nối liên tục sẽ giúp tăng hiệu suất đáng kể. Tôi không đồng ý với khẳng định rằng bạn nên "Tránh" kiên trì ..

Có vẻ như các khiếu nại ở trên được điều khiển bởi ai đó sử dụng bảng MyIASM và hack trong các phiên bản giao dịch của riêng họ bằng cách lấy khóa bảng .. Tất nhiên bạn sẽ gặp bế tắc! Sử dụng startTransaction () của PDO và chuyển các bảng của bạn sang InnoDB ..


2
Một năm cuối, tôi nhận ra, nhưng đối với các bản ghi: câu chuyện của tôi xuất phát từ một cơ sở dữ liệu bao gồm toàn bộ các bảng InnoDB, với ngoại lệ duy nhất của một số ít các máy nhái denormalized mắc kẹt trong vũng lầy của MyISAM hỗ trợ lập chỉ mục toàn văn.
Charles

Pfft, Sphinx đã cũ và bị trả giá, ElasticSearch là độ hot mới. Một ngày đẹp trời, chúng tôi thực sự sẽ sử dụng nó cho các ứng dụng cũ của chúng tôi thay vì chỉ những ứng dụng mới ...
Charles

Tìm kiếm toàn văn bản trong PostgreSQL là người chiến thắng thực sự. Ngạc nhiên. Không yêu cầu một công cụ / máy chủ khác đang chạy để thực hiện công việc của mình. Không phải lo lắng về việc giữ dữ liệu đồng bộ. Điều khiển rất chi tiết. Nhiều từ điển hoặc viết của riêng bạn. Và vì PostgreSQL tự động sử dụng các truy vấn đa chỉ mục, bạn có thể thả nó vào với bất kỳ truy vấn nào khác mà bạn đang chạy.
bóng sáng

2
MySQL 5.6 cung cấp hỗ trợ toàn văn cho các bảng InnoDB.
gian biểu

2

Dường như với tôi một kết nối liên tục sẽ ăn nhiều tài nguyên hệ thống hơn. Có thể là một số tiền không đáng kể, nhưng vẫn ...


Thường là một giao dịch rất nhiều thời gian của con người trong một phần triệu giây của máy tính
Andy Chase

1

Giải thích cho việc sử dụng các kết nối liên tục rõ ràng là giảm số lượng kết nối khá tốn kém, mặc dù thực tế là chúng nhanh hơn đáng kể với MySQL so với các cơ sở dữ liệu khác.

Rắc rối đầu tiên với các kết nối liên tục ...

Nếu bạn đang tạo 1000 kết nối mỗi giây, thông thường bạn không đảm bảo rằng nó vẫn mở trong thời gian rất dài, nhưng Hệ thống hoạt động thì có. Dựa trên giao thức TCP / IP, các cổng không thể được tái chế ngay lập tức và cũng phải đầu tư một thời gian trong giai đoạn FIN FIN chờ đợi trước khi chúng có thể được tái chế.

Vấn đề thứ 2 ... sử dụng rất nhiều kết nối máy chủ MySQL.

Nhiều người chỉ đơn giản là không nhận ra rằng bạn có thể tăng biến * max_connections * và có được hơn 100 kết nối đồng thời với MySQL, những người khác đã bị đánh bại bởi các vấn đề Linux cũ hơn về việc không thể truyền tải hơn 1024 kết nối với MySQL.

Cho phép nói chuyện về lý do tại sao các kết nối liên tục bị vô hiệu hóa trong phần mở rộng mysqli. Mặc dù thực tế là bạn có thể sử dụng sai các kết nối liên tục và có hiệu suất kém không phải là lý do chính. Lý do thực tế là - bạn có thể nhận được nhiều vấn đề hơn với nó.

Các kết nối liên tục được đưa vào PHP trong suốt các thời điểm của MySQL 3.22 / 3.23 khi MySQL không quá khó, điều đó có nghĩa là bạn có thể tái chế các kết nối một cách dễ dàng mà không gặp vấn đề gì. Tuy nhiên, trong các phiên bản sau, số lượng sự cố đã xuất hiện - Nếu bạn tái chế kết nối có giao dịch không được cam kết, bạn sẽ gặp rắc rối. Nếu bạn tái chế các kết nối với các cấu hình bộ ký tự tùy chỉnh, bạn sẽ gặp nguy hiểm một lần nữa, cũng như về khả năng biến đổi trên mỗi biến phiên.

Một rắc rối với việc sử dụng các kết nối liên tục là nó không thực sự mở rộng quy mô. Đối với những người có 5000 người được kết nối, bạn sẽ cần 5000 kết nối liên tục. Để tránh yêu cầu về sự kiên trì, bạn có thể có khả năng phục vụ 10000 người có số lượng kết nối tương tự vì họ có thể chia sẻ các kết nối cá nhân khi họ không ở cùng họ.


0

Tôi chỉ tự hỏi liệu một giải pháp một phần sẽ có một nhóm các kết nối sử dụng một lần. Bạn có thể dành thời gian tạo nhóm kết nối khi hệ thống sử dụng thấp, đến giới hạn, đưa chúng ra và tiêu diệt chúng khi chúng đã hoàn thành hoặc hết thời gian. Trong nền bạn đang tạo kết nối mới khi chúng được thực hiện. Trong trường hợp xấu nhất, điều này chỉ nên chậm như tạo kết nối mà không có nhóm, giả sử rằng việc thiết lập liên kết là yếu tố giới hạn?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.