Uploaded image for project: 'Python Driver'
  1. Python Driver
  2. PYTHON-906

Prefer localhost to remote mongos servers regardless of latency

    XMLWordPrintable

    Details

    • Type: New Feature
    • Status: Closed
    • Priority: Major - P3
    • Resolution: Won't Fix
    • Affects Version/s: 3.0
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None
    • Environment:
      pymongo==3.0.1-3-70185ff

      Description

      Summary: In the reporter's network, an "ismaster" call to a remote mongos is actually lower latency than to a mongos running on localhost, but the local mongos has higher throughput. PyMongo does not measure throughput, only latency, and it prefers the lowest-latency mongos. This is a feature request to work around this issue by especially preferring "localhost" and its synonyms, regardless of latency measurements.

      We've updated the Server Selection Spec to mandate all drivers prefer localhost if the Topology Type is sharded.

      Original report

      It looks like pymongo 3.0.1.dev0 is consistently slower than 2.6.3 for find:

      3.0.1.dev0

      In [42]: %timeit -n10 list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
      10 loops, best of 3: 293 ms per loop
      In [43]: %timeit -n10 list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
      10 loops, best of 3: 241 ms per loop
      In [44]: %timeit -n10 list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
      10 loops, best of 3: 291 ms per loop
      In [45]: %timeit -n10 list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
      10 loops, best of 3: 309 ms per loop
      

      Avg: 283.5 ms

      2.6.3

      In [13]: coll = m['oneminute.STITCHED']._collection
      2015-04-21 08:59:07,673 INFO  14654 Connecting to mongo: research (cn15-ib:27119,cn16-ib:27119,localhost:27119)
      In [14]: %timeit -n10 list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
      10 loops, best of 3: 196 ms per loop
      In [15]: %timeit -n10 list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
      10 loops, best of 3: 214 ms per loop
      In [16]: %timeit -n10 list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
      10 loops, best of 3: 184 ms per loop
      In [17]: %timeit -n10 list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
      10 loops, best of 3: 216 ms per loop
      

      Avg: 202.5

      With prun, I see that pymongo 3.0 is performing 346 socket recv's vs 81 for 2.6.3. Has something changed with the socket recv buffer size, or similar? I haven't been able to find anything in the docs.

      3.0.1.dev0

      %prun x= list(coll.find({'symbol': 'FUT_FTL', 'parent': ObjectId('5535d898cdc41bd41e2a60be')}))
               7763 function calls (7747 primitive calls) in 0.689 seconds
       
         Ordered by: internal time
       
         ncalls  tottime  percall  cumtime  percall filename:lineno(function)
            346    0.633    0.002    0.633    0.002 {method 'recv' of '_socket.socket' objects}
             16    0.024    0.001    0.657    0.041 network.py:73(_receive_data_on_socket)
              8    0.009    0.001    0.020    0.003 {bson._cbson.decode_all}
            696    0.006    0.000    0.006    0.000 {built-in method __new__ of type object at 0x2b63d125b880}
              8    0.005    0.001    0.025    0.003 helpers.py:87(_unpack_response)
            696    0.003    0.000    0.009    0.000 binary.py:141(__new__)
            697    0.001    0.000    0.002    0.000 objectid.py:68(__init__)
            233    0.001    0.000    0.689    0.003 cursor.py:972(__next__)
            232    0.001    0.000    0.001    0.000 database.py:339(_fix_outgoing)
           2099    0.001    0.000    0.001    0.000 {isinstance}
           1321    0.001    0.000    0.001    0.000 {len}
              1    0.000    0.000    0.689    0.689 <string>:1(<module>)
              8    0.000    0.000    0.660    0.082 server.py:66(send_message_with_response)
              8    0.000    0.000    0.687    0.086 cursor.py:792(__send_message)
              8    0.000    0.000    0.000    0.000 {method 'sendall' of '_socket.socket' objects}
              8    0.000    0.000    0.661    0.083 mongo_client.py:692(_send_message_with_response)
              8    0.000    0.000    0.000    0.000 topology.py:61(select_servers)
            241    0.000    0.000    0.000    0.000 collection.py:249(database)
           16/8    0.000    0.000    0.001    0.000 contextlib.py:21(__exit__)
              8    0.000    0.000    0.000    0.000 pool.py:521(_get_socket_no_auth)
              8    0.000    0.000    0.000    0.000 pool.py:556(return_socket)
              9    0.000    0.000    0.687    0.076 cursor.py:884(_refresh)
              1    0.000    0.000    0.000    0.000 {select.select}
              8    0.000    0.000    0.657    0.082 network.py:58(receive_message)
             16    0.000    0.000    0.001    0.000 pool.py:484(get_socket)
             16    0.000    0.000    0.001    0.000 server.py:100(get_socket)
              8    0.000    0.000    0.000    0.000 topology.py:306(_apply_selector)
             32    0.000    0.000    0.000    0.000 periodic_executor.py:46(open)
              8    0.000    0.000    0.000    0.000 pool.py:257(check_auth)
             32    0.000    0.000    0.000    0.000 threading.py:696(isAlive)
              8    0.000    0.000    0.000    0.000 topology.py:265(_ensure_opened)
              7    0.000    0.000    0.000    0.000 {pymongo._cmessage._get_more_message}
      
      

      2.6.3

               9032 function calls in 0.206 seconds
       
         Ordered by: internal time
       
         ncalls  tottime  percall  cumtime  percall filename:lineno(function)
             83    0.145    0.002    0.145    0.002 {method 'recv' of '_socket.socket' objects}
             16    0.017    0.001    0.162    0.010 mongo_client.py:983(__receive_data_on_socket)
              8    0.011    0.001    0.036    0.004 helpers.py:74(_unpack_response)
              8    0.010    0.001    0.025    0.003 {bson._cbson.decode_all}
            696    0.007    0.000    0.007    0.000 {built-in method __new__ of type object at 0x2ab756479880}
            696    0.003    0.000    0.011    0.000 binary.py:130(__new__)
            697    0.002    0.000    0.003    0.000 objectid.py:169(__validate)
              1    0.002    0.002    0.206    0.206 <string>:1(<module>)
           3492    0.001    0.000    0.001    0.000 {isinstance}
              9    0.001    0.000    0.202    0.022 cursor.py:826(_refresh)
            233    0.001    0.000    0.204    0.001 cursor.py:900(next)
            697    0.001    0.000    0.004    0.000 objectid.py:68(__init__)
            232    0.001    0.000    0.001    0.000 database.py:259(_fix_outgoing)
           1058    0.000    0.000    0.000    0.000 {len}
              8    0.000    0.000    0.201    0.025 cursor.py:761(__send_message)
              8    0.000    0.000    0.163    0.020 mongo_client.py:998(__receive_message_on_socket)
              8    0.000    0.000    0.000    0.000 {method 'sendall' of '_socket.socket' objects}
              8    0.000    0.000    0.001    0.000 pool.py:286(get_socket)
             40    0.000    0.000    0.000    0.000 {method 'acquire' of 'thread.lock' objects}
              8    0.000    0.000    0.001    0.000 pool.py:393(maybe_return_socket)
              8    0.000    0.000    0.165    0.021 mongo_client.py:1027(_send_message_with_response)
             16    0.000    0.000    0.000    0.000 thread_util.py:90(_make_vigil)
             24    0.000    0.000    0.000    0.000 {hasattr}
              8    0.000    0.000    0.163    0.020 mongo_client.py:1014(__send_and_receive)
            245    0.000    0.000    0.000    0.000 collection.py:174(database)
              7    0.000    0.000    0.000    0.000 {pymongo._cmessage._get_more_message}
              8    0.000    0.000    0.001    0.000 mongo_client.py:752(__socket)
              8    0.000    0.000    0.000    0.000 mongo_client.py:454(__check_auth)
             16    0.000    0.000    0.000    0.000 pool.py:517(_get_request_state)
              8    0.000    0.000    0.000    0.000 pool.py:414(_return_socket)
              1    0.000    0.000    0.000    0.000 cursor.py:66(__init__)
             56    0.000    0.000    0.000    0.000 {_struct.unpack}
      

        Attachments

        1. 2.6.3.log
          4 kB
        2. 3.0.1.log
          4 kB
        3. all-latencies.txt
          26 kB
        4. cn15.png
          cn15.png
          60 kB
        5. cn15-vs-localhost.txt
          20 kB
        6. cn16.png
          cn16.png
          67 kB
        7. example_for_jira.py
          2 kB
        8. sanitized_docs.json.gz
          78 kB

          Issue Links

            Activity

              People

              Assignee:
              jesse A. Jesse Jiryu Davis
              Reporter:
              jblackburn James Blackburn
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: