MySQL可以使用OpenSSL或yaSSL/wolfSSL进行编译,这两者都支持基于OpenSSL API的加密连接。在5.7版本,我们知道默认情况下MySQL Community Edition用的SSL库是yaSSL,而在8.0版本,MySQL Community Edition用的是OpenSSL。那么SSL加密对性能有什么影响呢?这两个SSL库在性能上又到底有多大差别呢?我们接下来进行一些测试并进行分析。
MySQL有两个功能使用到了SSL库,一个是SSL连接,通过在数据库服务器与客户端应用程序之间强制实施SSL连接,可以加密服务器与应用程序之间的数据流,有助于防止“中间人”攻击;还有一个是透明加密,通过对存储的数据进行加密,来保证数据的安全。因此我们测试采用两个测试组来分别对这两个功能进行测试。测试采用sysbench执行oltp系列场景对应脚本。
2 透明加密测试组
下表是部分场景中TPS性能上面的差别。
在大部分场景中(oltp_delete,oltp_insert,oltp_update_index,oltp_update_non_index, oltp_write_only, select_random_points, select_random_ranges),配置yaSSL与不配置SSL的性能在TPS表现差别不大,性能差别在5%以内,不作为关注的重点;在部分测试场景(oltp_point_select、oltp_read_only、oltp_read_write)配置SSL对性能影响较大,分别有26.03%,43.29%,29.18%的性能下降。
具体原因分析:
对txsql进行perf分析,发现oltp_point_select、oltp_read_only、oltp_read_write这三个场景导致性能下降的热点是加解密过程,以性能下降最为明显的oltp_read_only场景为例,下图所示perf热点分析对比:
带SSL的热点主要在以下两个函数:
TaoCrypt::AES::encrypt(unsigned char const*, unsigned char const*, unsigned char*) const
TaoCrypt::SHA::Transform()
经过对sysbench脚本分析,只有oltp_point_select、oltp_read_only、oltp_read_write这三个场景用到了execute_point_selects() 这个测试模型,而且性能差异明显的oltp_read_only场景中,仅仅跑了oltp_read_only这一个模型。这个模型仅调用”SELECT c FROM sbtest%u WHERE id=?” ,客户端在查询后立即执行,因此数据库对每次查询都是立即返回,不会做batch,数据库返回数据次数增加,增多对小数据的加密,增加加密次数,因此性能差异明显体现。
对比OpenSSL和yaSSL的数据(仅测试3个SSL影响较大的场景),总体上看OpenSSL比yaSSL性能高一点。oltp_select_point场景有点异常,性能低很多。
查看perf对比数据:
很明显加密后出现一个热点。使用pt-pmp工具查看对应的堆栈:
Mon Jul 23 14:24:07 CST 2018
28 pthread_rwlock_rdlock(libpthread.so.0),native_rw_rdlock(thr_rwlock.h:79),inline_mysql_rwlock_rdlock(thr_rwlock.h:79),openssl_lock(thr_rwlock.h:79),openssl_lock_function(thr_rwlock.h:79),int_thread_get_item(libcrypto.so.10),ERR_get_state(libcrypto.so.10),get_error_values(libcrypto.so.10),SSL_get_error(libssl.so.10),ssl_should_retry(viossl.c:133),vio_ssl_read(viossl.c:133),net_read_raw_loop(net_serv.cc:672),net_read_packet_header(net_serv.cc:756),net_read_packet(net_serv.cc:756),my_net_read(net_serv.cc:899),Protocol_classic::read_packet(protocol_classic.cc:808),Protocol_classic::get_command(protocol_classic.cc:965),do_command(sql_parse.cc:965),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
10 __io_getevents_0_4,LinuxAIOHandler::collect(os0file.cc:2500),LinuxAIOHandler::poll(os0file.cc:2646),os_aio_linux_handler(os0file.cc:2702),os_aio_handler(os0file.cc:2702),fil_aio_wait(fil0fil.cc:5906),io_handler_thread(srv0start.cc:311),start_thread(libpthread.so.0),clone(libc.so.6)
8 pread64(libpthread.so.0),execute(os0file.cc:2179),os_file_io(os0file.cc:2179),os_file_pread(os0file.cc:5644),os_file_read_page(os0file.cc:5644),os_file_read_func(os0file.cc:6076),os_aio_func(os0file.cc:6076),pfs_os_aio_func(os0file.ic:261),fil_io(os0file.ic:261),buf_read_page_low(buf0rea.cc:183),buf_read_page(buf0rea.cc:183),buf_page_get_gen(buf0buf.cc:4196),btr_cur_search_to_nth_level(btr0cur.cc:1107),btr_pcur_open_with_no_init_func(btr0pcur.ic:521),row_search_mvcc(row0sel.cc:5091),ha_innobase::index_read(ha_innodb.cc:8770),handler::index_read_idx_map(handler.cc:7503),handler::ha_index_read_idx_map(handler.cc:3082),read_(handler.cc:3082),join_read_const_table(handler.cc:3082),JOIN::extract_func_dependent_tables(sql_optimizer.cc:5579),JOIN::make_join_plan(sql_optimizer.cc:5043),JOIN::optimize(sql_optimizer.cc:368),st_select_lex::optimize(sql_select.cc:1009),handle_query(sql_select.cc:164),execute_sqlcom_select(sql_parse.cc:5247),mysql_execute_command(sql_parse.cc:2851),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
3 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),srv_worker_thread(srv0srv.cc:2528),start_thread(libpthread.so.0),clone(libc.so.6)
3 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),buf_flush_page_cleaner_worker(buf0flu.cc:3496),start_thread(libpthread.so.0),clone(libc.so.6)
2 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),sync_array_wait_event(sync0arr.cc:475),rw_lock_x_lock_func(sync0rw.cc:795),pfs_rw_lock_x_lock_func(sync0rw.ic:705),btr_search_x_lock(sync0rw.ic:705),btr_search_info_update_slow(sync0rw.ic:705),btr_search_info_update(btr0sea.ic:81),btr_cur_search_to_nth_level(btr0sea.ic:81),btr_pcur_open_with_no_init_func(btr0pcur.ic:521),row_search_mvcc(row0sel.cc:5091),ha_innobase::index_read(ha_innodb.cc:8770),handler::index_read_idx_map(handler.cc:7503),handler::ha_index_read_idx_map(handler.cc:3082),read_(handler.cc:3082),join_read_const_table(handler.cc:3082),JOIN::extract_func_dependent_tables(sql_optimizer.cc:5579),JOIN::make_join_plan(sql_optimizer.cc:5043),JOIN::optimize(sql_optimizer.cc:368),st_select_lex::optimize(sql_select.cc:1009),handle_query(sql_select.cc:164),execute_sqlcom_select(sql_parse.cc:5247),mysql_execute_command(sql_parse.cc:2851),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
2 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),sync_array_wait_event(sync0arr.cc:475),rw_lock_s_lock_spin(sync0rw.cc:425),rw_lock_s_lock_func(sync0rw.ic:433),pfs_rw_lock_s_lock_func(sync0rw.ic:433),btr_search_drop_page_hash_index(sync0rw.ic:433),buf_LRU_free_page(buf0lru.cc:2062),buf_LRU_free_from_common_LRU_list(buf0lru.cc:1078),buf_LRU_scan_and_free_block(buf0lru.cc:1078),buf_LRU_get_free_block(buf0lru.cc:1353),buf_page_init_for_read(buf0buf.cc:5145),buf_read_page_low(buf0rea.cc:149),buf_read_page(buf0rea.cc:149),buf_page_get_gen(buf0buf.cc:4196),btr_cur_search_to_nth_level(btr0cur.cc:1107),btr_pcur_open_with_no_init_func(btr0pcur.ic:521),row_search_mvcc(row0sel.cc:5091),ha_innobase::index_read(ha_innodb.cc:8770),handler::index_read_idx_map(handler.cc:7503),handler::ha_index_read_idx_map(handler.cc:3082),read_(handler.cc:3082),join_read_const_table(handler.cc:3082),JOIN::extract_func_dependent_tables(sql_optimizer.cc:5579),JOIN::make_join_plan(sql_optimizer.cc:5043),JOIN::optimize(sql_optimizer.cc:368),st_select_lex::optimize(sql_select.cc:1009),handle_query(sql_select.cc:164),execute_sqlcom_select(sql_parse.cc:5247),mysql_execute_command(sql_parse.cc:2851),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
1 ut_delay(libc.so.6),rw_lock_s_lock_spin(sync0rw.cc:355),rw_lock_s_lock_func(sync0rw.ic:433),pfs_rw_lock_s_lock_func(sync0rw.ic:433),btr_search_drop_page_hash_index(sync0rw.ic:433),buf_LRU_free_page(buf0lru.cc:2062),buf_LRU_free_from_common_LRU_list(buf0lru.cc:1078),buf_LRU_scan_and_free_block(buf0lru.cc:1078),buf_LRU_get_free_block(buf0lru.cc:1353),buf_page_init_for_read(buf0buf.cc:5145),buf_read_page_low(buf0rea.cc:149),buf_read_page(buf0rea.cc:149),buf_page_get_gen(buf0buf.cc:4196),btr_cur_search_to_nth_level(btr0cur.cc:1107),btr_pcur_open_with_no_init_func(btr0pcur.ic:521),row_search_mvcc(row0sel.cc:5091),ha_innobase::index_read(ha_innodb.cc:8770),handler::index_read_idx_map(handler.cc:7503),handler::ha_index_read_idx_map(handler.cc:3082),read_(handler.cc:3082),join_read_const_table(handler.cc:3082),JOIN::extract_func_dependent_tables(sql_optimizer.cc:5579),JOIN::make_join_plan(sql_optimizer.cc:5043),JOIN::optimize(sql_optimizer.cc:368),st_select_lex::optimize(sql_select.cc:1009),handle_query(sql_select.cc:164),execute_sqlcom_select(sql_parse.cc:5247),mysql_execute_command(sql_parse.cc:2851),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
1 trx_commit_low(trx0trx.cc:2095),trx_commit(trx0trx.cc:2199),trx_commit_for_mysql(trx0trx.cc:2418),innobase_commit_low(ha_innodb.cc:4296),innobase_commit(ha_innodb.cc:4296),ha_innobase::external_lock(ha_innodb.cc:15748),handler::ha_external_lock(handler.cc:7892),unlock_external(lock.cc:667),mysql_unlock_tables(lock.cc:416),mysql_unlock_some_tables(lock.cc:431),JOIN::optimize(sql_optimizer.cc:412),st_select_lex::optimize(sql_select.cc:1009),handle_query(sql_select.cc:164),execute_sqlcom_select(sql_parse.cc:5247),mysql_execute_command(sql_parse.cc:2851),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
大部分连接在等待一个读锁,这个锁是openssl1.1.0之前的版本所要求的,由MySQL实现后通过调用api传入。我们使用openssl1.1.0h版本源码重编译一个静态库,并重新编译txsql测试这个场景。此时查看到pt-pmp工具输出堆栈为:
Tue Jul 24 15:49:41 CST 2018
12 pread64(libpthread.so.0),execute(os0file.cc:2179),os_file_io(os0file.cc:2179),os_file_pread(os0file.cc:5644),os_file_read_page(os0file.cc:5644),os_file_read_func(os0file.cc:6076),os_aio_func(os0file.cc:6076),pfs_os_aio_func(os0file.ic:261),fil_io(os0file.ic:261),buf_read_page_low(buf0rea.cc:183),buf_read_page(buf0rea.cc:183),buf_page_get_gen(buf0buf.cc:4196),btr_cur_search_to_nth_level(btr0cur.cc:1107),btr_pcur_open_with_no_init_func(btr0pcur.ic:521),row_search_mvcc(row0sel.cc:5091),ha_innobase::index_read(ha_innodb.cc:8770),handler::index_read_idx_map(handler.cc:7503),handler::ha_index_read_idx_map(handler.cc:3082),read_(handler.cc:3082),join_read_const_table(handler.cc:3082),JOIN::extract_func_dependent_tables(sql_optimizer.cc:5579),JOIN::make_join_plan(sql_optimizer.cc:5043),JOIN::optimize(sql_optimizer.cc:368),st_select_lex::optimize(sql_select.cc:1009),handle_query(sql_select.cc:164),execute_sqlcom_select(sql_parse.cc:5247),mysql_execute_command(sql_parse.cc:2851),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
10 poll(libc.so.6),vio_io_wait(viosocket.c:834),vio_socket_io_wait(viosocket.c:105),vio_ssl_read(viossl.c:196),net_read_raw_loop(net_serv.cc:672),net_read_packet_header(net_serv.cc:756),net_read_packet(net_serv.cc:756),my_net_read(net_serv.cc:899),Protocol_classic::read_packet(protocol_classic.cc:808),Protocol_classic::get_command(protocol_classic.cc:965),do_command(sql_parse.cc:965),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
10 __io_getevents_0_4,LinuxAIOHandler::collect(os0file.cc:2500),LinuxAIOHandler::poll(os0file.cc:2646),os_aio_linux_handler(os0file.cc:2702),os_aio_handler(os0file.cc:2702),fil_aio_wait(fil0fil.cc:5906),io_handler_thread(srv0start.cc:311),start_thread(libpthread.so.0),clone(libc.so.6)
3 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),srv_worker_thread(srv0srv.cc:2528),start_thread(libpthread.so.0),clone(libc.so.6)
3 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),buf_flush_page_cleaner_worker(buf0flu.cc:3496),start_thread(libpthread.so.0),clone(libc.so.6)
2 read(libpthread.so.0),sock_read,BIO_read,ssl3_read_n,ssl3_get_record,ssl3_read_bytes,ssl3_read,SSL_read,vio_ssl_read(viossl.c:186),net_read_raw_loop(net_serv.cc:672),net_read_packet_header(net_serv.cc:756),net_read_packet(net_serv.cc:756),my_net_read(net_serv.cc:899),Protocol_classic::read_packet(protocol_classic.cc:808),Protocol_classic::get_command(protocol_classic.cc:965),do_command(sql_parse.cc:965),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
2 rand_bytes,tls1_enc,do_ssl3_write,ssl3_write_bytes,SSL_write,vio_ssl_write(viossl.c:225),net_write_raw_loop(net_serv.cc:500),net_write_packet(net_serv.cc:500),net_flush(net_serv.cc:222),net_send_ok(protocol_classic.cc:369),Protocol_classic::send_eof(protocol_classic.cc:668),THD::send_statement_status(sql_class.cc:4714),dispatch_command(sql_parse.cc:1925),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
2 pthread_rwlock_unlock(libpthread.so.0),CRYPTO_THREAD_unlock,rand_bytes,tls1_enc,do_ssl3_write,ssl3_write_bytes,SSL_write,vio_ssl_write(viossl.c:225),net_write_raw_loop(net_serv.cc:500),net_write_packet(net_serv.cc:500),net_flush(net_serv.cc:222),net_send_ok(protocol_classic.cc:369),Protocol_classic::send_eof(protocol_classic.cc:668),THD::send_statement_status(sql_class.cc:4714),dispatch_command(sql_parse.cc:1925),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
1 write(libpthread.so.0),sock_write,BIO_write,ssl3_write_pending,do_ssl3_write,ssl3_write_bytes,SSL_write,vio_ssl_write(viossl.c:225),net_write_raw_loop(net_serv.cc:500),net_write_packet(net_serv.cc:500),net_flush(net_serv.cc:222),net_send_ok(protocol_classic.cc:369),Protocol_classic::send_eof(protocol_classic.cc:668),THD::send_statement_status(sql_class.cc:4714),dispatch_command(sql_parse.cc:1925),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
此时大部分线程都在读写过程中,perf数据:
可见之前的瓶颈已经降低很多了。测试得到oltp_point_select的TPS为336229.14,性能下降30.95%,与yaSSL的性能下降值26.03%相比略高。下表是短连接测试数据:
不启用SSL大约为用OpenSSL库启用SSL每秒访问数的4.5倍,而yaSSL这个数字则为7.6倍,显然OpenSSL的性能在这种场景下比yaSSL有很大提高。
下表为透明加密测试数据:
总体看,启用yaSSL透明加密时TPS都会下降。oltp_delete、oltp_insert、oltp_update_index、oltp_update_non_index、oltp_write_only场景比不加密情况性能大约低40%,oltp_point_select、oltp_read_only场景比不加密情况性能大约低20%。其中oltp_read_write场景、select_random_points场、select_random_ranges场景与bulk_insert场景加密与不加密相比差距不大。需要具体分析原因。
首先查看oltp_read_write场景的CPU利用率和IO情况,如下图:
从CPU利用率看,加密比不加密使用率有大幅提高,但依然没到100%。从IO看两者速度虽有差异,但利用率都接近100%,IO应该处于压满状态,变化不大。执行命令pt-pmp -p得到数据:
Tue Jul 3 12:48:48 CST 2018
7 __io_getevents_0_4,LinuxAIOHandler::collect(os0file.cc:2500),LinuxAIOHandler::poll(os0file.cc:2646),os_aio_linux_handler(os0file.cc:2702),os_aio_handler(os0file.cc:2702),fil_aio_wait(fil0fil.cc:5906),io_handler_thread(srv0start.cc:311),start_thread(libpthread.so.0),clone(libc.so.6)
6 pthread_cond_wait,native_cond_wait(thr_cond.h:140),my_cond_wait(thr_cond.h:140),inline_mysql_cond_wait(thr_cond.h:140),Stage_manager::enroll_for(thr_cond.h:140),MYSQL_BIN_LOG::change_stage(binlog.cc:8655),MYSQL_BIN_LOG::ordered_commit(binlog.cc:9056),MYSQL_BIN_LOG::commit(binlog.cc:8330),ha_commit_trans(handler.cc:1795),trans_commit(transaction.cc:239),mysql_execute_command(sql_parse.cc:4354),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
5 pthread_cond_wait,native_cond_wait(thr_cond.h:140),my_cond_wait(thr_cond.h:140),inline_mysql_cond_wait(thr_cond.h:140),Stage_manager::enroll_for(thr_cond.h:140),MYSQL_BIN_LOG::change_stage(binlog.cc:8655),MYSQL_BIN_LOG::ordered_commit(binlog.cc:9125),MYSQL_BIN_LOG::commit(binlog.cc:8330),ha_commit_trans(handler.cc:1795),trans_commit(transaction.cc:239),mysql_execute_command(sql_parse.cc:4354),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
4 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),sync_array_wait_event(sync0arr.cc:475),wait(ut0mutex.ic:89),spin_and_try_lock(ut0mutex.ic:89),enter(ut0mutex.ic:89),enter(ut0mutex.ic:89),buf_LRU_buf_pool_running_out(ut0mutex.ic:89),row_ins_sec_index_entry_low(row0ins.cc:3168),row_ins_sec_index_entry(row0ins.cc:3420),row_ins_index_entry(row0ins.cc:3451),row_ins_index_entry_step(row0ins.cc:3451),row_ins(row0ins.cc:3451),row_ins_step(row0ins.cc:3451),row_insert_for_mysql_using_ins_graph(row0mysql.cc:1749),row_insert_for_mysql(row0mysql.cc:1873),ha_innobase::write_row(ha_innodb.cc:7630),handler::ha_write_row(handler.cc:7976),write_record(sql_insert.cc:1871),Sql_cmd_insert::mysql_insert(sql_insert.cc:769),Sql_cmd_insert::execute(sql_insert.cc:3103),mysql_execute_command(sql_parse.cc:4945),Prepared_statement::execute(sql_prepare.cc:3935),Prepared_statement::execute_loop(sql_prepare.cc:3543),mysqld_stmt_execute(sql_prepare.cc:2549),dispatch_command(sql_parse.cc:1437),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
3 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),sync_array_wait_event(sync0arr.cc:475),TTASEventMutex::wait(ut0mutex.ic:89),spin_and_try_lock(ib0mutex.h:850),enter(ib0mutex.h:850),PolicyMutex<TTASEventMutex<GenericPolicy>(ib0mutex.h:850),buf_page_io_complete(buf0buf.cc:5831),fil_aio_wait(fil0fil.cc:5940),io_handler_thread(srv0start.cc:311),start_thread(libpthread.so.0),clone(libc.so.6)
显然瓶颈在提交binlog上,将binglog日志关闭(注释掉log-bin),重启mysqld测试发现TPS提升约10%。再执行pt-pmp -p察看数据,此时瓶颈在执行读写操作时涉及到的insert buffer页面锁。设置innodb_change_buffering=none,关闭此功能,重启mysqld再次执行发现性能下降25%左右。此时发现瓶颈都是IO了。总体来看这个场景瓶颈在于IO,不加密状态CPU本身使用率并不高,加密后只是将CPU利用率提高了,并没有改变瓶颈,所以加密状态的TPS变化不大。
其次分析select_random_points场景的CPU利用率和IO情况,如下图:
从IO可以看出,主要执行过程中基本没有IO进行,怀疑操作过程中可能一直使用的buffer中的数据,在执行过程中使用命令查看buffer命中情况:
$ mysql> show engine innobase status;
查看到具体信息:
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 8795455488
Dictionary memory allocated 315349
Buffer pool size 524224
Free buffers 2969
Database pages 515364
Old database pages 190077
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 5433583, not young 935378889
0.00 youngs/s, 0.00 non-youngs/s
Pages read 70941635, created 32975923, written 55885804
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 515364, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
确认了该场景使用的buffer数据,没有进行IO读取。CPU使用率基本没有变化,一直是压满了。根据透明加密设计原理,这个场景不会有加解密的操作。总体上应该不会对TPS有影响。
select_random_ranges这个场景与select_random_points的情况一样,总体上应该不会对TPS有影响。
bulk_insert这个场景的CPU利用率和IO情况,如下图:
这个场景CPU是压满的,io在加密和不加密都基本一样,也是满负荷了。察看perf数据:
执行pt-pmp -p命令数据如下:
Mon Jul 2 17:33:00 CST 2018
17 ut_delay(libc.so.6),rw_lock_x_lock_func(sync0rw.cc:751),pfs_rw_lock_x_lock_func(sync0rw.ic:705),btr_search_x_lock(sync0rw.ic:705),btr_search_update_hash_on_insert(sync0rw.ic:705),btr_cur_optimistic_insert(btr0cur.cc:3272),row_ins_clust_index_entry_low(row0ins.cc:2604),row_ins_clust_index_entry(row0ins.cc:3319),row_ins_index_entry(row0ins.cc:3449),row_ins_index_entry_step(row0ins.cc:3449),row_ins(row0ins.cc:3449),row_ins_step(row0ins.cc:3449),row_insert_for_mysql_using_ins_graph(row0mysql.cc:1749),row_insert_for_mysql(row0mysql.cc:1873),ha_innobase::write_row(ha_innodb.cc:7630),handler::ha_write_row(handler.cc:7976),write_record(sql_insert.cc:1871),Sql_cmd_insert::mysql_insert(sql_insert.cc:769),Sql_cmd_insert::execute(sql_insert.cc:3103),mysql_execute_command(sql_parse.cc:4945),mysql_parse(sql_parse.cc:5740),dispatch_command(sql_parse.cc:1503),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
10 __io_getevents_0_4,LinuxAIOHandler::collect(os0file.cc:2500),LinuxAIOHandler::poll(os0file.cc:2646),os_aio_linux_handler(os0file.cc:2702),os_aio_handler(os0file.cc:2702),fil_aio_wait(fil0fil.cc:5906),io_handler_thread(srv0start.cc:311),start_thread(libpthread.so.0),clone(libc.so.6)
7 ut_delay(libc.so.6),rw_lock_x_lock_func(sync0rw.cc:751),pfs_rw_lock_x_lock_func(sync0rw.ic:705),btr_search_x_lock(sync0rw.ic:705),btr_search_update_hash_node_on_insert(sync0rw.ic:705),btr_cur_optimistic_insert(btr0cur.cc:3270),row_ins_clust_index_entry_low(row0ins.cc:2604),row_ins_clust_index_entry(row0ins.cc:3319),row_ins_index_entry(row0ins.cc:3449),row_ins_index_entry_step(row0ins.cc:3449),row_ins(row0ins.cc:3449),row_ins_step(row0ins.cc:3449),row_insert_for_mysql_using_ins_graph(row0mysql.cc:1749),row_insert_for_mysql(row0mysql.cc:1873),ha_innobase::write_row(ha_innodb.cc:7630),handler::ha_write_row(handler.cc:7976),write_record(sql_insert.cc:1871),Sql_cmd_insert::mysql_insert(sql_insert.cc:769),Sql_cmd_insert::execute(sql_insert.cc:3103),mysql_execute_command(sql_parse.cc:4945),mysql_parse(sql_parse.cc:5740),dispatch_command(sql_parse.cc:1503),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
5 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),sync_array_wait_event(sync0arr.cc:475),rw_lock_x_lock_func(sync0rw.cc:795),pfs_rw_lock_x_lock_func(sync0rw.ic:705),btr_search_x_lock(sync0rw.ic:705),btr_search_update_hash_on_insert(sync0rw.ic:705),btr_cur_optimistic_insert(btr0cur.cc:3272),row_ins_clust_index_entry_low(row0ins.cc:2604),row_ins_clust_index_entry(row0ins.cc:3319),row_ins_index_entry(row0ins.cc:3449),row_ins_index_entry_step(row0ins.cc:3449),row_ins(row0ins.cc:3449),row_ins_step(row0ins.cc:3449),row_insert_for_mysql_using_ins_graph(row0mysql.cc:1749),row_insert_for_mysql(row0mysql.cc:1873),ha_innobase::write_row(ha_innodb.cc:7630),handler::ha_write_row(handler.cc:7976),write_record(sql_insert.cc:1871),Sql_cmd_insert::mysql_insert(sql_insert.cc:769),Sql_cmd_insert::execute(sql_insert.cc:3103),mysql_execute_command(sql_parse.cc:4945),mysql_parse(sql_parse.cc:5740),dispatch_command(sql_parse.cc:1503),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
5 pthread_cond_wait,wait(os0event.cc:165),wait_low(os0event.cc:165),os_event_wait_low(os0event.cc:165),sync_array_wait_event(sync0arr.cc:475),rw_lock_x_lock_func(sync0rw.cc:795),pfs_rw_lock_x_lock_func(sync0rw.ic:705),btr_search_x_lock(sync0rw.ic:705),btr_search_update_hash_node_on_insert(sync0rw.ic:705),btr_cur_optimistic_insert(btr0cur.cc:3270),row_ins_clust_index_entry_low(row0ins.cc:2604),row_ins_clust_index_entry(row0ins.cc:3319),row_ins_index_entry(row0ins.cc:3449),row_ins_index_entry_step(row0ins.cc:3449),row_ins(row0ins.cc:3449),row_ins_step(row0ins.cc:3449),row_insert_for_mysql_using_ins_graph(row0mysql.cc:1749),row_insert_for_mysql(row0mysql.cc:1873),ha_innobase::write_row(ha_innodb.cc:7630),handler::ha_write_row(handler.cc:7976),write_record(sql_insert.cc:1871),Sql_cmd_insert::mysql_insert(sql_insert.cc:769),Sql_cmd_insert::execute(sql_insert.cc:3103),mysql_execute_command(sql_parse.cc:4945),mysql_parse(sql_parse.cc:5740),dispatch_command(sql_parse.cc:1503),do_command(sql_parse.cc:1023),handle_connection(connection_handler_per_thread.cc:309),pfs_spawn_thread(pfs.cc:2188),start_thread(libpthread.so.0),clone(libc.so.6)
发现场景的瓶颈主要是在锁上。这个锁是innodb的一个功能Adaptive Hash Index。关闭innodb_adaptive_hash_index参数或者设置innodb_adaptive_hash_index_parts=64,测试可以发现TPS增长到685541.92。此时可以发现瓶颈为将小事务日志写入重做日志缓冲区时的加锁(log_sys->mutex)过程。加密过程引起的降低不是主要瓶颈,所以最后表现为加密和不加密在这个场景的TPS变化不大。
对比OpenSSL与yaSSL的情况,总体上OpenSSL相对yaSSL来说都有较大幅度的性能提升。oltp_delete、oltp_insert、oltp_update_index、oltp_update_non_index、oltp_write_only场景OpenSSL加密相比yaSSL加密性能大约能提升40%,oltp_point_select、oltp_read_only、oltp_read_write场景OpenSSl加密相比yaSSL大约能提升20%性能,其他场景则差别不大。
select_random_points、select_random_ranges、bulk_insert场景已分析过,使用OpenSSL或者yaSSL都跟不使用加密TPS相差不大;oltp_read_write场景之前分析的瓶颈主要是在binlog、insert buffer页面锁以及io上,加解密应该影响不大,但数据显示使用OpenSSL加密的性能明显比使用yaSSL以及不使用加密的情况高,需要再分析下。
通过pt-pmp工具输出堆栈,可以确认两者在堆栈上没有明显区别,基本上都在读取数据页面。查看perf数据,不加密情况:
OpenSSL加密情况:
显然,OpenSSL加密情况下,降低了锁冲突,最后性能反而有所提升。
总体上看SSL加密会导致性能损失,使用yaSSL库会导致性能有较大下降,而使用OpenSSL库性能下降幅度远低于yaSSL,与不使用SSL的性能差别不大,同时使用OpenSSL 1.1版本的库又比使用OpenSSL 1.0版本的库性能要高一些。
在SSL连接测试组中,大部分场景中,配置yaSSL或OpenSSL进行SSL连接与不配置SSL的性能在TPS表现差别不大;在部分测试场景(oltp_point_select、oltp_read_only、oltp_read_write、短连接)中,配置yaSSL或OpenSSL进行SSL连接性能下降较大。大多数情况(oltp_read_only、oltp_read_write、短连接)OpenSSL优于yaSSL;oltp_point_select场景下OpenSSL1.0版本性能明显低于yaSSL,但OpenSSL1.0版本性能与yaSSL相差不大。
在透明加密测试组中,大部分场景(oltp_delete、oltp_insert、oltp_update_index、oltp_update_non_index、oltp_write_only)配置yaSSL加密比不加密情况性能大约低40%,oltp_point_select、oltp_read_only场景yaSSL加密比不加密情况性能大约低20%;少部分场景(oltp_read_write、select_random_points、select_random_ranges、bulk_insert)yaSSL加密与不加密相比差距不大;配置OpenSSL加密比不加密情况总体差别不大,甚至还略有上升,尤其是oltp_read_write场景;总体上看配置OpenSSL加密比配置yaSSL加密性能有大幅提升。