2014-11-16 12 views
8

Gần đây tôi đã nâng cấp từ Django 1,4 đến Django 1,7 và kể từ khi tôi tiếp tục nhận được thông báo lỗi sau đối với một số kịch bản, đôi khi:Django, sau khi nâng cấp: máy chủ MySQL đã đi xa

OperationalError: (2006, 'MySQL server has gone away')

Các kịch bản rất nhiệm vụ chạy dài hoặc liên tục có thể liên quan đến các giai đoạn không giao tiếp với db trong vài phút, do đó kết nối sẽ hết. Tuy nhiên, trước khi tôi nâng cấp, đó là không có vấn đề, như Django dường như tự động thiết lập lại một kết nối. Bây giờ nó không có nghĩa là các nhiệm vụ thường dừng lại và thất bại ở giữa.

Có ai biết điều gì đã thay đổi không và cách tôi có thể khắc phục sự cố?

Có lẽ liên quan đến mà vé/sửa chữa: https://code.djangoproject.com/ticket/21463

Cảm ơn rất nhiều!

+0

Kiểm tra [này] (https://code.djangoproject.com/ticket/21597 # bình luận: 29) và [this] (http://piwik.org/faq/troubleshooting/faq_183/). –

Trả lời

16

Lý do của hành vi như vậy là liên tục kết nối với cơ sở dữ liệu, được giới thiệu trong Django 1.6.

Để tránh lỗi hết thời gian chờ kết nối, bạn nên đặt CONN_MAX_AGE trong settings.py thành giá trị nhỏ hơn wait_timeout trong cấu hình MySQL (my.cnf). Trong trường hợp đó Django phát hiện rằng kết nối cần phải được mở lại sớm hơn so với MySQL ném nó. Giá trị mặc định cho MySQL 5.7 là 28800 giây.

settings.py:

DATABASES = { 
    'default': { 
     'ENGINE': 'django.db.backends.mysql', 
     'CONN_MAX_AGE': 3600, 
     <other params here> 
    } 
} 

Tài liệu: https://docs.djangoproject.com/en/1.7/ref/settings/#conn-max-age

my.cnf:

wait_timeout = 28800 

Tài liệu: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_wait_timeout

3

Trong django 1.6, khi wait_timeout được truyền (của mysql), thì truy cập DB gây ra lỗi (2006, 'máy chủ MySQL đã biến mất'). Đây không phải là trường hợp trong django 1.5.1

tôi đã nhận thấy lỗi này khi sử dụng người lao động chạy mã django (sử dụng gearman).

Để tái sản xuất:

Đặt thời gian chờ để có giá trị thấp bằng cách chỉnh sửa /etc/mysql/my.cnf thêm dòng sau dưới [mysqld]

wait_timeout = 10 
interactive_timeout = 10 

Sau đó

% python manage.py shell

>>> # access DB 
>>> import django.contrib.auth.models 
>>> print list(django.contrib.auth.models.User.objects.all()) 
>>> import time 
>>> time.sleep(15) 
>>> print list(django.contrib.auth.models.User.objects.all()) 

Bây giờ bạn nhận được lỗi.

giải pháp đơn giản tôi thấy trên web là để gọi django.db.close_connection() trước khi truy cập

>>> import django.db 
>>> django.db.close_connection() 
>>> print list(django.contrib.auth.models.User.objects.all()) 

hoạt động ok.

7

Tôi có một quá trình nền chạy rqworker wh ich thực hiện các công việc riêng biệt để làm mới một số dữ liệu sau một số hành động của người dùng.

Tôi luôn nhận được OperationalError: (2006, 'MySQL server has gone away') nếu không có hành động người dùng nào trong hơn wait_timeout giây. Ngay cả khi tôi đặt CONN_MAX_AGE nhỏ hơn MySQL wait_timeout.

Theo tôi hiểu, việc thay đổi CONN_MAX_AGE có thể giúp nếu Django tự động kiểm tra và tự động kết nối các kết nối của nó trước thời gian chờ này. Nhưng Django 1.7.x kiểm tra nó trước và sau mỗi yêu cầu chỉ (xem django/db/init.py#L101-L112).

Như được mô tả trong Django ticket 15119, chúng ta có thể thấy rằng Django đang thực hiện lệnh ping để xác thực xem kết nối có còn hoạt động hay không trước khi thực hiện mọi truy vấn. Hành vi này đã được khắc phục trong commit 282b2f4.

phát triển Django đã cho một câu trả lời ngắn cho tất cả những câu hỏi như thế này trong https://code.djangoproject.com/ticket/21597#comment:29

Do đó quá trình rqworker tôi có để xác nhận kết nối riêng của mình cho từng công việc mới. (Lưu ý: nếu chúng ta đóng một kết nối thì Django sẽ tạo một kết nối mới).

Tôi sẽ sử dụng Django theo cách tiếp cận yêu cầu cho công việc và gọi django.db.close_old_connections() trước và sau mỗi công việc. Và có, CONN_MAX_AGE phải nhỏ hơn MySQL wait_timeout, bởi vì Django không kiểm tra xem MySQL server has gone away trong phương thức django.db.close_old_connections() hay không.

1

Có lẽ thời gian chờ là một vấn đề đối với một số nhưng tôi gặp sự cố này khi cố gắng viết một trường BLOB rất lớn. Tôi giải quyết nó bằng cách tăng tối đa được phép kích thước gói tin trong file cấu hình mysql ...

max_allowed_packet = 4M

Đừng quên khởi động lại mysql sau khi thay đổi để /etc/my.cnf. Trang này đã giúp ...

http://dev.mysql.com/doc/refman/5.5/en/packet-too-large.html

0

Chúng tôi cũng nhận thấy điều này. Câu trả lời ở trên của việc thiết lập CONN_MAX_AGE thành một cái gì đó ít hơn công việc wait_timeout của MySQL/MariaDB - cho web.

Tuy nhiên, đối với các tác vụ lâu dài, điều này có vẻ không hoạt động. Thay vào đó, chúng ta gói nó lại và đóng kết nối mỗi khi một trong các nhiệm vụ chạy dài của chúng ta được thực thi.

Chúng tôi kết hợp điều này với hồ bơi tùy chỉnh của riêng mình. Mang nó hoặc để lại nó - một Django mặc định có kiểm soát không - không phải cái gì chúng tôi thích trong sản xuất. Chúng tôi thiết lập một hồ bơi tối đa để giết máy chủ trước khi nó giết chết DB với quá nhiều kết nối.Sử dụng nó như là một trang trí cho các nhiệm vụ của bạn:

@close_db_connection() def task_do_something(): in 'Hello'

''' 
Created on Dec 23, 2017 

@author: Kevin 
''' 
from functools import wraps 

def close_db_connection(ExceptionToCheck=Exception, raise_exception=False, notify=False): 
    """Close the database connection when we're finished, django will have to get a new one...""" 
    def deco_wrap(f): 
     @wraps(f) 
     def f_wrap(*args, **kwargs): 
      try: 
       return f(*args, **kwargs) 
      except Exception as e: 
       raise e 
      finally: 
       from django.db import connection; 
       connection.close(); 

     return f_wrap 
    return deco_wrap 
Các vấn đề liên quan