MySQL 5.6下table_open_cache参数合理配置详解

table_open_cache指定表高速缓存的大小。每当MySQL访问一个表时,如果在表缓冲区中还有空间,该表就被打开并放入其中,这样可以更快地访问表内容。
通过检查峰值时间的状态值Open_tables和Opened_tables,可以决定是否需要增加table_open_cache的值。
如果你发现open_tables等于table_open_cache,并且opened_tables在不断增长,那么你就需要增加table_open_cache的值了(上述状态值可通过SHOW GLOBAL STATUS LIKE ‘Open%tables’获得)。
注意,不能盲目地把table_open_cache设置成很大的值,设置太大超过了shell的文件描述符(通过ulimit -n查看),造成文件描述符不足,从而造成性能不稳定或者连接失败。

测试环境:腾讯云CDB,内存4000M,在控制台查看到table_open_cache=512,监测table_open_cache设置是否合理,是否需要优化。

发现open_tables等于table_open_cache,都是512,说明mysql正在将缓存的表释放以容纳新的表,此时可能需要加大table_open_cache的值,4G内存的机器,建议设置为2048
比较适合的值:
Open_tables / Opened_tables >= 0.85
Open_tables / table_open_cache <= 0.95 如果对此参数的把握不是很准,有个很保守的设置建议:把MySQL数据库放在生产环境中试运行一段时间,然后把参数的值调整得比Opened_tables的数值大一些,并且保证在比较高负载的极端条件下依然比Opened_tables略大。

MySQL 5.6性能调优my.cnf详解

[client]
port = 3306
socket = /tmp/mysql.sock

[mysqld]
port = 3306
socket = /tmp/mysql.sock

basedir = /usr/local/mysql
datadir = /data/mysql
pid-file = /data/mysql/mysql.pid
user = mysql
bind-address = 0.0.0.0
server-id = 1 #表示是本机的序号为1,一般来讲就是master的意思

skip-name-resolve
# 禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项,
# 则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求

#skip-networking

back_log = 600
# MySQL能有的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求,这就起作用,
# 然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。
# 如果期望在一个短时间内有很多连接,你需要增加它。也就是说,如果MySQL的连接数据达到max_connections时,新来的请求将会被存在堆栈中,
# 以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。
# 另外,这值(back_log)限于您的操作系统对到来的TCP/IP连接的侦听队列的大小。
# 你的操作系统在这个队列大小上有它自己的限制(可以检查你的OS文档找出这个变量的最大值),试图设定back_log高于你的操作系统的限制将是无效的。

max_connections = 1000
# MySQL的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。可以过’conn%’通配符查看当前状态的连接数量,以定夺该值的大小。(SHOW GLOBAL STATUS LIKE 'CONN%')

max_connect_errors = 6000
# 对于同一主机,如果有超出该参数值个数的中断错误连接,则该主机将被禁止连接。如需对该主机进行解禁,执行:FLUSH HOST。

open_files_limit = 65535
# MySQL打开的文件描述符限制,默认最小1024;当open_files_limit没有被配置的时候,比较max_connections*5和ulimit -n的值,哪个大用哪个,
# 当open_file_limit被配置的时候,比较open_files_limit和max_connections*5的值,哪个大用哪个。

table_open_cache = 128
# MySQL每打开一个表,都会读入一些数据到table_open_cache缓存中,当MySQL在这个缓存中找不到相应信息时,才会去磁盘上读取。默认值64
# 假定系统有200个并发连接,则需将此参数设置为200*N(N为每个连接所需的文件描述符数目);
# 当把table_open_cache设置为很大时,如果系统处理不了那么多文件描述符,那么就会出现客户端失效,连接不上

max_allowed_packet = 4M
# 接受的数据包大小;增加该变量的值十分安全,这是因为仅当需要时才会分配额外内存。例如,仅当你发出长查询或MySQLd必须返回大的结果行时MySQLd才会分配更多内存。
# 该变量之所以取较小默认值是一种预防措施,以捕获客户端和服务器之间的错误信息包,并确保不会因偶然使用大的信息包而导致内存溢出。

binlog_cache_size = 1M
# 一个事务,在没有提交的时候,产生的日志,记录到Cache中;等到事务提交需要提交的时候,则把日志持久化到磁盘。默认binlog_cache_size大小32K

max_heap_table_size = 8M
# 定义了用户可以创建的内存表(memory table)的大小。这个值用来计算内存表的最大行数值。这个变量支持动态改变

tmp_table_size = 16M
# MySQL的heap(堆积)表缓冲大小。所有联合在一个DML指令内完成,并且大多数联合甚至可以不用临时表即可以完成。
# 大多数临时表是基于内存的(HEAP)表。具有大的记录长度的临时表 (所有列的长度的和)或包含BLOB列的表存储在硬盘上。
# 如果某个内部heap(堆积)表大小超过tmp_table_size,MySQL可以根据需要自动将内存中的heap表改为基于硬盘的MyISAM表。还可以通过设置tmp_table_size选项来增加临时表的大小。也就是说,如果调高该值,MySQL同时将增加heap表的大小,可达到提高联接查询速度的效果

read_buffer_size = 2M
# MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。
# 如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能

read_rnd_buffer_size = 8M
# MySQL的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,
# MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySQL会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大

sort_buffer_size = 8M
# MySQL执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。
# 如果不能,可以尝试增加sort_buffer_size变量的大小

join_buffer_size = 8M
# 联合查询操作所能使用的缓冲区大小,和sort_buffer_size一样,该参数对应的分配内存也是每连接独享

thread_cache_size = 8
# 这个值(默认8)表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中,
# 如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,
# 增加这个值可以改善系统性能.通过比较Connections和Threads_created状态的变量,可以看到这个变量的作用。(–>表示要调整的值)
# 根据物理内存设置规则如下:
# 1G —> 8
# 2G —> 16
# 3G —> 32
# 大于3G —> 64

query_cache_size = 8M
#MySQL的查询缓冲大小(从4.0.1开始,MySQL提供了查询缓冲机制)使用查询缓冲,MySQL将SELECT语句和查询结果存放在缓冲区中,
# 今后对于同样的SELECT语句(区分大小写),将直接从缓冲区中读取结果。根据MySQL用户手册,使用查询缓冲最多可以达到238%的效率。
# 通过检查状态值’Qcache_%’,可以知道query_cache_size设置是否合理:如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲不够的情况,
# 如果Qcache_hits的值也非常大,则表明查询缓冲使用非常频繁,此时需要增加缓冲大小;如果Qcache_hits的值不大,则表明你的查询重复率很低,
# 这种情况下使用查询缓冲反而会影响效率,那么可以考虑不用查询缓冲。此外,在SELECT语句中加入SQL_NO_CACHE可以明确表示不使用查询缓冲

query_cache_limit = 2M
#指定单个查询能够使用的缓冲区大小,默认1M

key_buffer_size = 4M
#指定用于索引的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),到你能负担得起那样多。如果你使它太大,
# 系统将开始换页并且真的变慢了。对于内存在4GB左右的服务器该参数可设置为384M或512M。通过检查状态值Key_read_requests和Key_reads,
# 可以知道key_buffer_size设置是否合理。比例key_reads/key_read_requests应该尽可能的低,
# 至少是1:100,1:1000更好(上述状态值可以使用SHOW STATUS LIKE ‘key_read%’获得)。注意:该参数值设置的过大反而会是服务器整体效率降低

ft_min_word_len = 4
# 分词词汇最小长度,默认4

transaction_isolation = REPEATABLE-READ
# MySQL支持4种事务隔离级别,他们分别是:
# READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
# 如没有指定,MySQL默认采用的是REPEATABLE-READ,ORACLE默认的是READ-COMMITTED

log_bin = mysql-bin
binlog_format = mixed
expire_logs_days = 30 #超过30天的binlog删除

log_error = /data/mysql/mysql-error.log #错误日志路径
slow_query_log = 1
long_query_time = 1 #慢查询时间 超过1秒则为慢查询
slow_query_log_file = /data/mysql/mysql-slow.log

performance_schema = 0
explicit_defaults_for_timestamp

#lower_case_table_names = 1 #不区分大小写

skip-external-locking #MySQL选项以避免外部锁定。该选项默认开启

default-storage-engine = InnoDB #默认存储引擎

innodb_file_per_table = 1
# InnoDB为独立表空间模式,每个数据库的每个表都会生成一个数据空间
# 独立表空间优点:
# 1.每个表都有自已独立的表空间。
# 2.每个表的数据和索引都会存在自已的表空间中。
# 3.可以实现单表在不同的数据库中移动。
# 4.空间可以回收(除drop table操作处,表空不能自已回收)
# 缺点:
# 单表增加过大,如超过100G
# 结论:
# 共享表空间在Insert操作上少有优势。其它都没独立表空间表现好。当启用独立表空间时,请合理调整:innodb_open_files

innodb_open_files = 500
# 限制Innodb能打开的表的数据,如果库里的表特别多的情况,请增加这个。这个值默认是300

innodb_buffer_pool_size = 64M
# InnoDB使用一个缓冲池来保存索引和原始数据, 不像MyISAM.
# 这里你设置越大,你在存取表里面数据时所需要的磁盘I/O越少.
# 在一个独立使用的数据库服务器上,你可以设置这个变量到服务器物理内存大小的80%
# 不要设置过大,否则,由于物理内存的竞争可能导致操作系统的换页颠簸.
# 注意在32位系统上你每个进程可能被限制在 2-3.5G 用户层面内存限制,
# 所以不要设置的太高.

innodb_write_io_threads = 4
innodb_read_io_threads = 4
# innodb使用后台线程处理数据页上的读写 I/O(输入输出)请求,根据你的 CPU 核数来更改,默认是4
# 注:这两个参数不支持动态改变,需要把该参数加入到my.cnf里,修改完后重启MySQL服务,允许值的范围从 1-64

innodb_thread_concurrency = 0
# 默认设置为 0,表示不限制并发数,这里推荐设置为0,更好去发挥CPU多核处理能力,提高并发量

innodb_purge_threads = 1
# InnoDB中的清除操作是一类定期回收无用数据的操作。在之前的几个版本中,清除操作是主线程的一部分,这意味着运行时它可能会堵塞其它的数据库操作。
# 从MySQL5.5.X版本开始,该操作运行于独立的线程中,并支持更多的并发数。用户可通过设置innodb_purge_threads配置参数来选择清除操作是否使用单
# 独线程,默认情况下参数设置为0(不使用单独线程),设置为 1 时表示使用单独的清除线程。建议为1

innodb_flush_log_at_trx_commit = 2
# 0:如果innodb_flush_log_at_trx_commit的值为0,log buffer每秒就会被刷写日志文件到磁盘,提交事务的时候不做任何操作(执行是由mysql的master thread线程来执行的。
# 主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件(REDO LOG)中。不论事务是否已经提交)默认的日志文件是ib_logfile0,ib_logfile1
# 1:当设为默认值1的时候,每次提交事务的时候,都会将log buffer刷写到日志。
# 2:如果设为2,每次提交事务都会写日志,但并不会执行刷的操作。每秒定时会刷到日志文件。要注意的是,并不能保证100%每秒一定都会刷到磁盘,这要取决于进程的调度。
# 每次事务提交的时候将数据写入事务日志,而这里的写入仅是调用了文件系统的写入操作,而文件系统是有 缓存的,所以这个写入并不能保证数据已经写入到物理磁盘
# 默认值1是为了保证完整的ACID。当然,你可以将这个配置项设为1以外的值来换取更高的性能,但是在系统崩溃的时候,你将会丢失1秒的数据。
# 设为0的话,mysqld进程崩溃的时候,就会丢失最后1秒的事务。设为2,只有在操作系统崩溃或者断电的时候才会丢失最后1秒的数据。InnoDB在做恢复的时候会忽略这个值。
# 总结
# 设为1当然是最安全的,但性能页是最差的(相对其他两个参数而言,但不是不能接受)。如果对数据一致性和完整性要求不高,完全可以设为2,如果只最求性能,例如高并发写的日志服务器,设为0来获得更高性能

innodb_log_buffer_size = 2M
# 此参数确定些日志文件所用的内存大小,以M为单位。缓冲区更大能提高性能,但意外的故障将会丢失数据。MySQL开发人员建议设置为1-8M之间

innodb_log_file_size = 32M
# 此参数确定数据日志文件的大小,更大的设置可以提高性能,但也会增加恢复故障数据库所需的时间

innodb_log_files_in_group = 3
# 为提高性能,MySQL可以以循环方式将日志文件写到多个文件。推荐设置为3

innodb_max_dirty_pages_pct = 90
# innodb主线程刷新缓存池中的数据,使脏数据比例小于90%

innodb_lock_wait_timeout = 120
# InnoDB事务在被回滚之前可以等待一个锁定的超时秒数。InnoDB在它自己的锁定表中自动检测事务死锁并且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒

bulk_insert_buffer_size = 8M
# 批量插入缓存大小, 这个参数是针对MyISAM存储引擎来说的。适用于在一次性插入100-1000+条记录时, 提高效率。默认值是8M。可以针对数据量的大小,翻倍增加。

myisam_sort_buffer_size = 8M
# MyISAM设置恢复表之时使用的缓冲区的尺寸,当在REPAIR TABLE或用CREATE INDEX创建索引或ALTER TABLE过程中排序 MyISAM索引分配的缓冲区

myisam_max_sort_file_size = 10G
# 如果临时文件会变得超过索引,不要使用快速排序索引方法来创建一个索引。注释:这个参数以字节的形式给出

myisam_repair_threads = 1
# 如果该值大于1,在Repair by sorting过程中并行创建MyISAM表索引(每个索引在自己的线程内)

interactive_timeout = 28800
# 服务器关闭交互式连接前等待活动的秒数。交互式客户端定义为在mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。默认值:28800秒(8小时)

wait_timeout = 28800
# 服务器关闭非交互连接之前等待活动的秒数。在线程启动时,根据全局wait_timeout值或全局interactive_timeout值初始化会话wait_timeout值,
# 取决于客户端类型(由mysql_real_connect()的连接选项CLIENT_INTERACTIVE定义)。参数默认值:28800秒(8小时)
# MySQL服务器所支持的最大连接数是有上限的,因为每个连接的建立都会消耗内存,因此我们希望客户端在连接到MySQL Server处理完相应的操作后,
# 应该断开连接并释放占用的内存。如果你的MySQL Server有大量的闲置连接,他们不仅会白白消耗内存,而且如果连接一直在累加而不断开,
# 最终肯定会达到MySQL Server的连接上限数,这会报’too many connections’的错误。对于wait_timeout的值设定,应该根据系统的运行情况来判断。
# 在系统运行一段时间后,可以通过show processlist命令查看当前系统的连接状态,如果发现有大量的sleep状态的连接进程,则说明该参数设置的过大,
# 可以进行适当的调整小些。要同时设置interactive_timeout和wait_timeout才会生效。

[mysqldump]
quick
max_allowed_packet = 16M #服务器发送和接受的最大包长度

[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M
read_buffer = 4M
write_buffer = 4M

MySQL 5.6 my.cnf配置优化

系统

4核 16G Centos6.5 x64

优化后测试结果如下

#mysqlslap   
#--concurrency=2 
#--iterations=1 
#--number-int-cols=10 
#--number-char-cols=10 
#-a 
#--auto-generate-sql-guid-primary 
#--auto-generate-sql-secondary-indexes=2 
#--number-of-queries=10000 
#--auto-generate-sql-load-type=write 
#--engine=myisam,innodb -uroot -proot --debug-info

` 结果:

Benchmark  
#        Running for engine myisam
#        Average number of seconds to run all queries: 1.064 seconds
#        Minimum number of seconds to run all queries: 1.064 seconds
#        Maximum number of seconds to run all queries: 1.064 seconds
#        Number of clients running queries: 2
#        Average number of queries per client: 5000
#
Benchmark  
#        Running for engine innodb
#        Average number of seconds to run all queries: 2.650 seconds
#        Minimum number of seconds to run all queries: 2.650 seconds
#        Maximum number of seconds to run all queries: 2.650 seconds
#        Number of clients running queries: 2
#        Average number of queries per client: 5000

配置及说明

[client]
port = 3306  
socket = /var/lib/mysql/mysql.sock

[mysql]
#这个配置段设置启动MySQL服务的条件;在这种情况下,no-auto-rehash确保这个服务启动得比较快。
no-auto-rehash

[mysqld]
user = mysql  
port = 3306  
socket = /var/lib/mysql/mysql.sock  
basedir = /usr/local/mysql  
datadir = /data/mysql/data/  
open_files_limit = 10240

back_log = 600  
#在MYSQL暂时停止响应新请求之前,短时间内的多少个请求可以被存在堆栈中。如果系统在短时间内有很多连接,则需要增大该参数的值,该参数值指定到来的TCP/IP连接的监听队列的大小。默认值80。

max_connections = 3000  
#MySQL允许最大的进程连接数,如果经常出现Too Many Connections的错误提示,则需要增大此值。默认151

max_connect_errors = 6000  
#设置每个主机的连接请求异常中断的最大次数,当超过该次数,MYSQL服务器将禁止host的连接请求,直到mysql服务器重启或通过flush hosts命令清空此host的相关信息。默认100

external-locking = FALSE  
#使用–skip-external-locking MySQL选项以避免外部锁定。该选项默认开启

max_allowed_packet = 32M  
#设置在网络传输中一次消息传输量的最大值。系统默认值 为4MB,最大值是1GB,必须设置1024的倍数。

#sort_buffer_size = 2M  
# Sort_Buffer_Size 是一个connection级参数,在每个connection(session)第一次需要使用这个buffer的时候,一次性分配设置的内存。
#Sort_Buffer_Size 并不是越大越好,由于是connection级的参数,过大的设置+高并发可能会耗尽系统内存资源。例如:500个连接将会消耗 500*sort_buffer_size(8M)=4G内存
#Sort_Buffer_Size 超过2KB的时候,就会使用mmap() 而不是 malloc() 来进行内存分配,导致效率降低。 系统默认2M,使用默认值即可

#join_buffer_size = 2M  
#用于表间关联缓存的大小,和sort_buffer_size一样,该参数对应的分配内存也是每个连接独享。系统默认2M,使用默认值即可

thread_cache_size = 300  
#默认38
# 服务器线程缓存这个值表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中,如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,增加这个值可以改善系统性能.通过比较 Connections 和 Threads_created 状态的变量,可以看到这个变量的作用。设置规则如下:1GB 内存配置为8,2GB配置为16,3GB配置为32,4GB或更高内存,可配置更大。

#thread_concurrency = 8  
#系统默认为10,使用10先观察
# 设置thread_concurrency的值的正确与否, 对mysql的性能影响很大, 在多个cpu(或多核)的情况下,错误设置了thread_concurrency的值, 会导致mysql不能充分利用多cpu(或多核), 出现同一时刻只能一个cpu(或核)在工作的情况。thread_concurrency应设为CPU核数的2倍. 比如有一个双核的CPU, 那么thread_concurrency的应该为4; 2个双核的cpu, thread_concurrency的值应为8

query_cache_size = 64M  
#在MyISAM引擎优化中,这个参数也是一个重要的优化参数。但也爆露出来一些问题。机器的内存越来越大,习惯性把参数分配的值越来越大。这个参数加大后也引发了一系列问题。我们首先分析一下 query_cache_size的工作原理:一个SELECT查询在DB中工作后,DB会把该语句缓存下来,当同样的一个SQL再次来到DB里调用时,DB在该表没发生变化的情况下把结果从缓存中返回给Client。这里有一个关建点,就是DB在利用Query_cache工作时,要求该语句涉及的表在这段时间内没有发生变更。那如果该表在发生变更时,Query_cache里的数据又怎么处理呢?首先要把Query_cache和该表相关的语句全部置为失效,然后在写入更新。那么如果Query_cache非常大,该表的查询结构又比较多,查询语句失效也慢,一个更新或是Insert就会很慢,这样看到的就是Update或是Insert怎么这么慢了。所以在数据库写入量或是更新量也比较大的系统,该参数不适合分配过大。而且在高并发,写入量大的系统,建议把该功能禁掉。

query_cache_limit = 4M  
#指定单个查询能够使用的缓冲区大小,缺省为1M

query_cache_min_res_unit = 2k  
#默认是4KB,设置值大对大数据查询有好处,但如果你的查询都是小数据查询,就容易造成内存碎片和浪费
#查询缓存碎片率 = Qcache_free_blocks / Qcache_total_blocks * 100%
#如果查询缓存碎片率超过20%,可以用FLUSH QUERY CACHE整理缓存碎片,或者试试减小query_cache_min_res_unit,如果你的查询都是小数据量的话。
#查询缓存利用率 = (query_cache_size – Qcache_free_memory) / query_cache_size * 100%
#查询缓存利用率在25%以下的话说明query_cache_size设置的过大,可适当减小;查询缓存利用率在80%以上而且Qcache_lowmem_prunes > 50的话说明query_cache_size可能有点小,要不就是碎片太多。
#查询缓存命中率 = (Qcache_hits – Qcache_inserts) / Qcache_hits * 100%

#default-storage-engine = MyISAM
#default_table_type = InnoDB #开启失败

#thread_stack = 192K  
#设置MYSQL每个线程的堆栈大小,默认值足够大,可满足普通操作。可设置范围为128K至4GB,默认为256KB,使用默认观察

transaction_isolation = READ-COMMITTED  
# 设定默认的事务隔离级别.可用的级别如下:READ UNCOMMITTED-读未提交 READ COMMITTE-读已提交 REPEATABLE READ -可重复读 SERIALIZABLE -串行

tmp_table_size = 256M  
# tmp_table_size 的默认大小是 32M。如果一张临时表超出该大小,MySQL产生一个 The table tbl_name is full 形式的错误,如果你做很多高级 GROUP BY 查询,增加 tmp_table_size 值。如果超过该值,则会将临时表写入磁盘。
max_heap_table_size = 256M

expire_logs_days = 7  
key_buffer_size = 2048M  
#批定用于索引的缓冲区大小,增加它可以得到更好的索引处理性能,对于内存在4GB左右的服务器来说,该参数可设置为256MB或384MB。

read_buffer_size = 1M  
#默认128K
# MySql读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySql会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。和sort_buffer_size一样,该参数对应的分配内存也是每个连接独享。

read_rnd_buffer_size = 16M  
# MySql的随机读(查询操作)缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,MySql会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySql会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大。

bulk_insert_buffer_size = 64M  
#批量插入数据缓存大小,可以有效提高插入效率,默认为8M

myisam_sort_buffer_size = 128M  
# MyISAM表发生变化时重新排序所需的缓冲 默认8M

myisam_max_sort_file_size = 10G  
# MySQL重建索引时所允许的最大临时文件的大小 (当 REPAIR, ALTER TABLE 或者 LOAD DATA INFILE).
# 如果文件大小比此值更大,索引会通过键值缓冲创建(更慢)

#myisam_max_extra_sort_file_size = 10G 5.6无此值设置
#myisam_repair_threads = 1   默认为1
# 如果一个表拥有超过一个索引, MyISAM 可以通过并行排序使用超过一个线程去修复他们.
# 这对于拥有多个CPU以及大量内存情况的用户,是一个很好的选择.

myisam_recover  
#自动检查和修复没有适当关闭的 MyISAM 表
skip-name-resolve  
lower_case_table_names = 1  
server-id = 1

innodb_additional_mem_pool_size = 16M  
#这个参数用来设置 InnoDB 存储的数据目录信息和其它内部数据结构的内存池大小,类似于Oracle的library cache。这不是一个强制参数,可以被突破。

innodb_buffer_pool_size = 2048M  
# 这对Innodb表来说非常重要。Innodb相比MyISAM表对缓冲更为敏感。MyISAM可以在默认的 key_buffer_size 设置下运行的可以,然而Innodb在默认的 innodb_buffer_pool_size 设置下却跟蜗牛似的。由于Innodb把数据和索引都缓存起来,无需留给操作系统太多的内存,因此如果只需要用Innodb的话则可以设置它高达 70-80% 的可用内存。一些应用于 key_buffer 的规则有 — 如果你的数据量不大,并且不会暴增,那么无需把 innodb_buffer_pool_size 设置的太大了

#innodb_data_file_path = ibdata1:1024M:autoextend 设置过大导致报错,默认12M观察
#表空间文件 重要数据

#innodb_file_io_threads = 4   不明确,使用默认值
#文件IO的线程数,一般为 4,但是在 Windows 下,可以设置得较大。


innodb_thread_concurrency = 8  
#服务器有几个CPU就设置为几,建议用默认设置,一般为8.

innodb_flush_log_at_trx_commit = 2  
# 如果将此参数设置为1,将在每次提交事务后将日志写入磁盘。为提供性能,可以设置为0或2,但要承担在发生故障时丢失数据的风险。设置为0表示事务日志写入日志文件,而日志文件每秒刷新到磁盘一次。设置为2表示事务日志将在提交时写入日志,但日志文件每次刷新到磁盘一次。

#innodb_log_buffer_size = 16M   使用默认8M
#此参数确定些日志文件所用的内存大小,以M为单位。缓冲区更大能提高性能,但意外的故障将会丢失数据.MySQL开发人员建议设置为1-8M之间

#innodb_log_file_size = 128M  使用默认48M
#此参数确定数据日志文件的大小,以M为单位,更大的设置可以提高性能,但也会增加恢复故障数据库所需的时间

#innodb_log_files_in_group = 3   使用默认2
#为提高性能,MySQL可以以循环方式将日志文件写到多个文件。推荐设置为3M

#innodb_max_dirty_pages_pct = 90  使用默认75观察
#推荐阅读 http://www.taobaodba.com/html/221_innodb_max_dirty_pages_pct_checkpoint.html
# Buffer_Pool中Dirty_Page所占的数量,直接影响InnoDB的关闭时间。参数innodb_max_dirty_pages_pct 可以直接控制了Dirty_Page在Buffer_Pool中所占的比率,而且幸运的是innodb_max_dirty_pages_pct是可以动态改变的。所以,在关闭InnoDB之前先将innodb_max_dirty_pages_pct调小,强制数据块Flush一段时间,则能够大大缩短 MySQL关闭的时间。

innodb_lock_wait_timeout = 120  
#默认为50秒 
# InnoDB 有其内置的死锁检测机制,能导致未完成的事务回滚。但是,如果结合InnoDB使用MyISAM的lock tables 语句或第三方事务引擎,则InnoDB无法识别死锁。为消除这种可能性,可以将innodb_lock_wait_timeout设置为一个整数值,指示 MySQL在允许其他事务修改那些最终受事务回滚的数据之前要等待多长时间(秒数)

innodb_file_per_table = 0  
#默认为No
#独享表空间(关闭)

[mysqldump]
quick  
# max_allowed_packet = 32M

[mysqld_safe]
log-error=/data/mysql/mysql_oldboy.err  
pid-file=/data/mysql/mysqld.pid

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES  

深入学习Redis集群搭建方案及实现原理

前言

作为一名后台开发,对数据库进行基准测试,以掌握数据库的性能情况是非常必要的。本文介绍了MySQL基准测试的基本概念,以及使用sysbench对MySQL进行基准测试的详细方法。

文章有疏漏之处,欢迎批评指正。

目录

一、基准测试简介

1、什么是基准测试

2、基准测试的作用

3、基准测试的指标

4、基准测试的分类

二、sysbench

1、sysbench简介

2、sysbench安装

3、sysbench语法

4、sysbench使用举例

5、测试结果

三、建议

一、基准测试简介

1、什么是基准测试

数据库的基准测试是对数据库的性能指标进行定量的、可复现的、可对比的测试。

基准测试与压力测试

基准测试可以理解为针对系统的一种压力测试。但基准测试不关心业务逻辑,更加简单、直接、易于测试,数据可以由工具生成,不要求真实;而压力测试一般考虑业务逻辑(如购物车业务),要求真实的数据。

2、基准测试的作用

对于多数Web应用,整个系统的瓶颈在于数据库;原因很简单:Web应用中的其他因素,例如网络带宽、负载均衡节点、应用服务器(包括CPU、内存、硬盘灯、连接数等)、缓存,都很容易通过水平的扩展(俗称加机器)来实现性能的提高。而对于MySQL,由于数据一致性的要求,无法通过增加机器来分散向数据库写数据带来的压力;虽然可以通过前置缓存(Redis等)、读写分离、分库分表来减轻压力,但是与系统其它组件的水平扩展相比,受到了太多的限制。

而对数据库的基准测试的作用,就是分析在当前的配置下(包括硬件配置、OS、数据库设置等),数据库的性能表现,从而找出MySQL的性能阈值,并根据实际系统的要求调整配置。

3、基准测试的指标

常见的数据库指标包括:

  • TPS/QPS:衡量吞吐量。
  • 响应时间:包括平均响应时间、最小响应时间、最大响应时间、时间百分比等,其中时间百分比参考意义较大,如前95%的请求的最大响应时间。。
  • 并发量:同时处理的查询请求的数量。

4、基准测试的分类

对MySQL的基准测试,有如下两种思路:

(1)针对整个系统的基准测试:通过http请求进行测试,如通过浏览器、APP或postman等测试工具。该方案的优点是能够更好的针对整个系统,测试结果更加准确;缺点是设计复杂实现困难。

(2)只针对MySQL的基准测试:优点和缺点与针对整个系统的测试恰好相反。

在针对MySQL进行基准测试时,一般使用专门的工具进行,例如mysqlslap、sysbench等。其中,sysbench比mysqlslap更通用、更强大,且更适合Innodb(因为模拟了许多Innodb的IO特性),下面介绍使用sysbench进行基准测试的方法。

二、sysbench

1、sysbench简介

sysbench是跨平台的基准测试工具,支持多线程,支持多种数据库;主要包括以下几种测试:

  • cpu性能
  • 磁盘io性能
  • 调度程序性能
  • 内存分配及传输速度
  • POSIX线程性能
  • 数据库性能(OLTP基准测试)

本文主要介绍对数据库性能的测试。

2、sysbench安装

本文使用的环境时CentOS 6.5;在其他Linux系统上的安装方法大同小异。MySQL版本是5.6。

(1)下载解压

wget https://github.com/akopytov/sysbench/archive/1.0.zip -O "sysbench-1.0.zip"
unzip sysbench-1.0.zip
cd sysbench-1.0

(2)安装依赖

yum install automake libtool –y

(3)安装

安装之前,确保位于之前解压的sysbench目录中。

./autogen.sh
./configure
export LD_LIBRARY_PATH=/usr/local/mysql/include #这里换成机器中mysql路径下的include
make
make install

(4)安装成功

[root@test sysbench-1.0]# sysbench --version
sysbench 1.0.9

3、sysbench语法

执行sysbench –help,可以看到sysbench的详细使用方法。

sysbench的基本语法如下:

sysbench [options]… [testname] [command]

下面说明实际使用中,常用的参数和命令。

(1)command

command是sysbench要执行的命令,包括prepare、run和cleanup,顾名思义,prepare是为测试提前准备数据,run是执行正式的测试,cleanup是在测试完成后对数据库进行清理。

(2)testname

testname指定了要进行的测试,在老版本的sysbench中,可以通过–test参数指定测试的脚本;而在新版本中,–test参数已经声明为废弃,可以不使用–test,而是直接指定脚本。

例如,如下两种方法效果是一样的:

sysbench --test=./tests/include/oltp_legacy/oltp.lua
sysbench ./tests/include/oltp_legacy/oltp.lua

测试时使用的脚本为lua脚本,可以使用sysbench自带脚本,也可以自己开发。对于大多数应用,使用sysbench自带的脚本就足够了。不同版本的sysbench中,lua脚本的位置可能不同,可以自己在sysbench路径下使用find命令搜索oltp.lua。P.S.:大多数数据服务都是oltp类型的,如果你不了解什么是oltp,那么大概率你的数据服务就是oltp类型的。

(3)options

sysbench的参数有很多,其中比较常用的包括:

MySQL连接信息参数

  • –mysql-host:MySQL服务器主机名,默认localhost;如果在本机上使用localhost报错,提示无法连接MySQL服务器,改成本机的IP地址应该就可以了。
  • –mysql-port:MySQL服务器端口,默认3306
  • –mysql-user:用户名
  • –mysql-password:密码

MySQL执行参数

  • –oltp-test-mode:执行模式,包括simple、nontrx和complex,默认是complex。simple模式下只测试简单的查询;nontrx不仅测试查询,还测试插入更新等,但是不使用事务;complex模式下测试最全面,会测试增删改查,而且会使用事务。可以根据自己的需要选择测试模式。
  • –oltp-tables-count:测试的表数量,根据实际情况选择
  • –oltp-table-size:测试的表的大小,根据实际情况选择
  • –threads:客户端的并发连接数
  • –time:测试执行的时间,单位是秒,该值不要太短,可以选择120
  • –report-interval:生成报告的时间间隔,单位是秒,如10

4、sysbench使用举例

在执行sysbench时,应该注意:

(1)尽量不要在MySQL服务器运行的机器上进行测试,一方面可能无法体现网络(哪怕是局域网)的影响,另一方面,sysbench的运行(尤其是设置的并发数较高时)会影响MySQL服务器的表现。

(2)可以逐步增加客户端的并发连接数(–thread参数),观察在连接数不同情况下,MySQL服务器的表现;如分别设置为10,20,50,100等。

(3)一般执行模式选择complex即可,如果需要特别测试服务器只读性能,或不使用事务时的性能,可以选择simple模式或nontrx模式。

(4)如果连续进行多次测试,注意确保之前测试的数据已经被清理干净。

下面是sysbench使用的一个例子:

(1)准备数据

sysbench ./tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.10.10
--mysql-port=3306 --mysql-user=root --mysql-password=123456
--oltp-test-mode=complex --oltp-tables-count=10 --oltp-table-size=100000
--threads=10 --time=120 --report-interval=10 prepare

其中,执行模式为complex,使用了10个表,每个表有10万条数据,客户端的并发线程数为10,执行时间为120秒,每10秒生成一次报告。

(2)执行测试

将测试结果导出到文件中,便于后续分析。

sysbench ./tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.10.10
--mysql-port=3306 --mysql-user=root --mysql-password=123456
--oltp-test-mode=complex --oltp-tables-count=10 --oltp-table-size=100000
--threads=10 --time=120 --report-interval=10 run >>
/home/test/mysysbench.log

(3)清理数据

执行完测试后,清理数据,否则后面的测试会受到影响。

sysbench ./tests/include/oltp_legacy/oltp.lua --mysql-host=192.168.10.10 --mysql-port=3306 --mysql-user=root --mysql-password=123456 cleanup

5、测试结果

测试结束后,查看输出文件,如下所示: 

其中,对于我们比较重要的信息包括:

queries:查询总数及qps

transactions:事务总数及tps

Latency-95th percentile:前95%的请求的最大响应时间,本例中是344毫秒,这个延迟非常大,是因为我用的MySQL服务器性能很差;在正式环境中这个数值是绝对不能接受的。

三、建议

下面是使用sysbench的一些建议。

1、在开始测试之前,应该首先明确:应采用针对整个系统的基准测试,还是针对MySQL的基准测试,还是二者都需要。

2、如果需要针对MySQL的基准测试,那么还需要明确精度方面的要求:是否需要使用生产环境的真实数据,还是使用工具生成也可以;前者实施起来更加繁琐。如果要使用真实数据,尽量使用全部数据,而不是部分数据。

3、基准测试要进行多次才有意义。

4、测试时需要注意主从同步的状态。

5、测试必须模拟多线程的情况,单线程情况不但无法模拟真实的效率,也无法模拟阻塞甚至死锁情况。

本文转自:https://www.cnblogs.com/kismetv/p/7615738.html

查询手机号的归属地及运营商接口(验证可用)

淘宝接口接口地址:

http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=18519101034

返回内容:

__GetZoneResult_ = {
    mts:'1851910',
    province:'北京',
    catName:'中国联通',
    telString:'18519101034',
    areaVid:'29400',
    ispVid:'137815084',
    carrier:'北京联通'
}

注意:接口返回的内容不是json,可以把“_GetZoneResult =”删掉后,转换成json

360接口接口地址:

https://cx.shouji.360.cn/phonearea.php?number=18519101034

返回内容:

{
  "code": 0,
  "data": {
    "province": "北京",
    "city": "",
    "sp": "联通"
  }
}

ITEBLOG接口接口地址:

https://www.iteblog.com/api/mobile.php?mobile=18519101034

返回内容:

{
  "ID": "280889",
  "prefix": "1851910",
  "province": "北京",
  "city": "北京",
  "operator": "中国联通",
  "areaCode": "010",
  "zip": "100000",
  "ret": 0,
  "searchStr": "18519101034",
  "from": "https://www.iteblog.com/api/mobile.php",
  "ip": "114.243.220.66",
  "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"

redis应用场景

毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作,为不同的大象构建不同的冰箱。希望你喜欢这个比喻。

一、Redis常用数据类型

Redis最为常用的数据类型主要有以下五种:

  • String
  • Hash
  • List
  • Set
  • Sorted set

在具体描述这几种数据类型之前,我们先通过一张图了解下Redis内部内存管理中是如何描述这些不同数据类型的:

首先Redis内部使用一个redisObject对象来表示所有的key和value,redisObject最主要的信息如上图所示:type代表一个value对象具体是何种数据类型,encoding是不同数据类型在redis内部的存储方式,比如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:”123″ “456”这样的字符串。

这里需要特殊说明一下vm字段,只有打开了Redis的虚拟内存功能,此字段才会真正的分配内存,该功能默认是关闭状态的。通过上图我们可以发现Redis使用redisObject来表示所有的key/value数据是比较浪费内存的,当然这些内存管理成本的付出主要也是为了给Redis不同数据类型提供一个统一的管理接口,实际作者也提供了多种方法帮助我们尽量节省内存使用,我们随后会具体讨论。

二、各种数据类型应用和实现方式

下面我们先来逐一的分析下这五种数据类型的使用和内部实现方式:

1、String

String 数据结构是简单的key-value类型,value其实不仅是String,也可以是数字。

常用命令:get、set、incr、decr、mget等。

应用场景:String是最常用的一种数据类型,普通的key/ value 存储都可以归为此类,即可以完全实现目前 Memcached 的功能,并且效率更高。还可以享受Redis的定时持久化,操作日志及 Replication等功能。除了提供与 Memcached 一样的get、set、incr、decr 等操作外,Redis还提供了下面一些操作: 

  • 获取字符串长度
  • 往字符串append内容
  • 设置和获取字符串的某一段内容
  • 设置及获取字符串的某一位(bit)
  • 批量设置一系列字符串的内容

使用场景:常规key-value缓存应用。常规计数: 微博数, 粉丝数。

实现方式:String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。

2、Hash

常用命令:hget,hset,hgetall 等。

应用场景:

我们简单举个实例来描述下Hash的应用场景,比如我们要存储一个用户信息对象数据,包含以下信息:

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储,主要有以下2种存储方式:

第一种方式将用户ID作为查找key,把其他信息封装成一个对象以序列化的方式存储,这种方式的缺点是,增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入CAS等复杂问题。

第二种方法是这个用户信息对象有多少成员就存成多少个key-value对儿,用用户ID+对应属性的名称作为唯一标识来取得对应属性的值,虽然省去了序列化开销和并发问题,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。

那么Redis提供的Hash很好的解决了这个问题,Redis的Hash实际是内部存储的Value为一个HashMap,并提供了直接存取这个Map成员的接口,如下图:

也就是说,Key仍然是用户ID, value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。很好的解决了问题。

这里同时需要注意,Redis提供了接口(hgetall)可以直接取到全部的属性数据,但是如果内部Map的成员很多,那么涉及到遍历整个内部Map的操作,由于Redis单线程模型的缘故,这个遍历操作可能会比较耗时,而另其它客户端的请求完全不响应,这点需要格外注意。

使用场景:存储部分变更数据,如用户信息等。

实现方式:

上面已经说到Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。

3、List

常用命令:lpush,rpush,lpop,rpop,lrange等。

应用场景:

Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表,粉丝列表等都可以用Redis的list结构来实现。

List 就是链表,相信略有数据结构知识的人都应该能理解其结构。使用List结构,我们可以轻松地实现最新消息排行等功能。List的另一个应用就是消息队列,
可以利用List的PUSH操作,将任务存在List中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作List中某一段的api,你可以直接查询,删除List中某一段的元素。

实现方式:

Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部添加或者删除元素,这样List即可以作为栈,也可以作为队列。

使用场景:

消息队列系统

使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。

比如:将Redis用作日志收集器

实际上还是一个队列,多个端点将日志信息写入Redis,然后一个worker统一将所有日志写到磁盘。

取最新N个数据的操作

记录前N个最新登陆的用户Id列表,超出的范围可以从数据库中获得。

//把当前登录人添加到链表里
ret = r.lpush("login:last_login_times", uid)

//保持链表只有N位
ret = redis.ltrim("login:last_login_times", 0, N-1)

//获得前N个最新登陆的用户Id列表
last_login_list = r.lrange("login:last_login_times", 0, N-1)

比如sina微博:

在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。但是我们做了限制不能超过5000个ID,因此我们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。

我们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。

4、Set

常用命令:

sadd,spop,smembers,sunion 等。

应用场景:

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

Set 就是一个集合,集合的概念就是一堆不重复值的组合。利用Redis提供的Set数据结构,可以存储一些集合性的数据。

案例:

在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。

Set是集合,是String类型的无序集合,set是通过hashtable实现的,概念和数学中个的集合基本类似,可以交集,并集,差集等等,set中的元素是没有顺序的。

实现方式:

set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

使用场景:

交集,并集,差集:(Set)

//book表存储book名称

set book:1:name    ”The Ruby Programming Language”

set book:2:name     ”Ruby on rail”

set book:3:name     ”Programming Erlang”

//tag表使用集合来存储数据,因为集合擅长求交集、并集

sadd tag:ruby 1

sadd tag:ruby 2

sadd tag:web 2

sadd tag:erlang 3

//即属于ruby又属于web的书?

 inter_list = redis.sinter("tag.web", "tag:ruby") 

//即属于ruby,但不属于web的书?

 inter_list = redis.sdiff("tag.ruby", "tag:web") 

//属于ruby和属于web的书的合集?

 inter_list = redis.sunion("tag.ruby", "tag:web")

获取某段时间所有数据去重值

这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。

5、Sorted Set

常用命令:

zadd,zrange,zrem,zcard等

使用场景:

Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。

和Set相比,Sorted Set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列,比如一个存储全班同学成绩的Sorted Set,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。另外还可以用Sorted Set来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。

实现方式:

Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

三、Redis实际应用场景

1、显示最新的项目列表

下面这个语句常用来显示最新项目,随着数据多了,查询毫无疑问会越来越慢。

SELECT * FROM foo WHERE ... ORDER BY time DESC LIMIT 10

      在Web应用中,“列出最新的回复”之类的查询非常普遍,这通常会带来可扩展性问题。这令人沮丧,因为项目本来就是按这个顺序被创建的,但要输出这个顺序却不得不进行排序操作。类似的问题就可以用Redis来解决。比如说,我们的一个Web应用想要列出用户贴出的最新20条评论。在最新的评论边上我们有一个“显示全部”的链接,点击后就可以获得更多的评论。我们假设数据库中的每条评论都有一个唯一的递增的ID字段。我们可以使用分页来制作主页和评论页,使用Redis的模板,每次新评论发表时,我们会将它的ID添加到一个Redis列表:

LPUSH latest.comments <ID>

我们将列表裁剪为指定长度,因此Redis只需要保存最新的5000条评论:

LTRIM latest.comments 0 5000

每次我们需要获取最新评论的项目范围时,我们调用一个函数来完成(使用伪代码):

FUNCTION get_latest_comments(start, num_items):  
    id_list = redis.lrange("latest.comments",start,start+num_items - 1)  
    IF id_list.length < num_items  
        id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")  
    END  
    RETURN id_list  
END

       这里我们做的很简单。在Redis中我们的最新ID使用了常驻缓存,这是一直更新的。但是我们做了限制不能超过5000个ID,因此我们的获取ID函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。

       我们的系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。

2、排行榜应用,取TOP N操作

     这个需求与上面需求的不同之处在于,取最新N个数据的操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。

热门,排行榜应用:

//将登录次数和用户统一存储在一个sorted set里
zadd login:login_times 5 1
zadd login:login_times 1 2
zadd login:login_times 2 3
//当用户登录时,对该用户的登录次数自增1
ret = r.zincrby("login:login_times", 1, uid)
//那么如何获得登录次数最多的用户呢,逆序排列取得排名前N的用户
ret = r.zrevrange("login:login_times", 0, N-1)

     另一个很普遍的需求是各种数据库的数据并非存储在内存中,因此在按得分排序以及实时更新这些几乎每秒钟都需要更新的功能上数据库的性能不够理想。典型的比如那些在线游戏的排行榜,比如一个Facebook的游戏,根据得分你通常想要:

– 列出前100名高分选手

– 列出某用户当前的全球排名

这些操作对于Redis来说小菜一碟,即使你有几百万个用户,每分钟都会有几百万个新的得分。模式是这样的,每次获得新得分时,我们用这样的代码:

ZADD leaderboard  <score>  <username>

你可能用userID来取代username,这取决于你是怎么设计的。得到前100名高分用户很简单:

ZREVRANGE leaderboard 0 99

 用户的全球排名也相似,只需要:

ZRANK leaderboard <username>

3、删除与过滤

      我们可以使用LREM来删除评论。如果删除操作非常少,另一个选择是直接跳过评论条目的入口,报告说该评论已经不存在。 有些时候你想要给不同的列表附加上不同的过滤器。如果过滤器的数量受到限制,你可以简单的为每个不同的过滤器使用不同的Redis列表。毕竟每个列表只有5000条项目,但Redis却能够使用非常少的内存来处理几百万条项目。

4、按照用户投票和时间排序

     排行榜的一种常见变体模式就像Reddit或Hacker News用的那样,新闻按照类似下面的公式根据得分来排序:score = points / time^alpha 因此用户的投票会相应的把新闻挖出来,但时间会按照一定的指数将新闻埋下去。下面是我们的模式,当然算法由你决定。模式是这样的,开始时先观察那些可能是最新的项目,例如首页上的1000条新闻都是候选者,因此我们先忽视掉其他的,这实现起来很简单。每次新的新闻贴上来后,我们将ID添加到列表中,使用LPUSH + LTRIM,确保只取出最新的1000条项目。有一项后台任务获取这个列表,并且持续的计算这1000条新闻中每条新闻的最终得分。计算结果由ZADD命令按照新的顺序填充生成列表,老新闻则被清除。这里的关键思路是排序工作是由后台任务来完成的。

5、处理过期项目

另一种常用的项目排序是按照时间排序。我们使用unix时间作为得分即可。 模式如下:

– 每次有新项目添加到我们的非Redis数据库时,我们把它加入到排序集合中。这时我们用的是时间属性,current_time和time_to_live。

– 另一项后台任务使用ZRANGE…SCORES查询排序集合,取出最新的10个项目。如果发现unix时间已经过期,则在数据库中删除条目。

6、计数

      Redis是一个很好的计数器,这要感谢INCRBY和其他相似命令。我相信你曾许多次想要给数据库加上新的计数器,用来获取统计或显示新信息,但是最后却由于写入敏感而不得不放弃它们。好了,现在使用Redis就不需要再担心了。有了原子递增(atomic increment),你可以放心的加上各种计数,用GETSET重置,或者是让它们过期。例如这样操作:

INCR user:<id> EXPIRE

你可以计算出最近用户在页面间停顿不超过60秒的页面浏览量,当计数达到比如20时,就可以显示出某些条幅提示,或是其它你想显示的东西。

7、特定时间内的特定项目

        另一项对于其他数据库很难,但Redis做起来却轻而易举的事就是统计在某段特点时间里有多少特定用户访问了某个特定资源。比如我想要知道某些特定的注册用户或IP地址,他们到底有多少访问了某篇文章。每次我获得一次新的页面浏览时我只需要这样做:

SADD page:day1:<page_id> <user_id>

当然你可能想用unix时间替换day1,比如time()-(time()%3600*24)等等。 想知道特定用户的数量吗?只需要使用

SCARD page:day1:<page_id>

需要测试某个特定用户是否访问了这个页面?

SISMEMBER page:day1:<page_id>

8、查找某个值所在的区间(区间无重合) :(Sorted Set)

例如有下面两个范围,10-20和30-40

  • A_start 10, A_end 20
  • B_start 30, B_end 40

我们将这两个范围的起始位置存在Redis的Sorted Sets数据结构中,基本范围起始值作为score,范围名加start和end为其value值:

redis 127.0.0.1:6379> zadd ranges 10 A_start
(integer) 1
redis 127.0.0.1:6379> zadd ranges 20 A_end
(integer) 1
redis 127.0.0.1:6379> zadd ranges 30 B_start
(integer) 1
redis 127.0.0.1:6379> zadd ranges 40 B_end
(integer) 1

这样数据在插入Sorted Sets后,相当于是将这些起始位置按顺序排列好了。现在我需要查找15这个值在哪一个范围中,只需要进行如下的zrangbyscore查找:

redis 127.0.0.1:6379> zrangebyscore ranges (15 +inf LIMIT 0 1
1) "A_end"

这个命令的意思是在Sorted Sets中查找大于15的第一个值。(+inf在Redis中表示正无穷大,15前面的括号表示>15而非>=15)查找的结果是A_end,由于所有值是按顺序排列的,所以可以判定15是在A_start到A_end区间上,也就是说15是在A这个范围里。至此大功告成。

9、交集,并集,差集:(Set)

//book表存储book名称
set book:1:name    ”The Ruby Programming Language”
set book:2:name     ”Ruby on rail”
set book:3:name     ”Programming Erlang”

//tag表使用集合来存储数据,因为集合擅长求交集、并集
sadd tag:ruby 1
sadd tag:ruby 2
sadd tag:web 2
sadd tag:erlang 3

//即属于ruby又属于web的书?
 inter_list = redis.sinter("tag.web", "tag:ruby") 
//即属于ruby,但不属于web的书?
 inter_list = redis.sdiff("tag.ruby", "tag:web") 
//属于ruby和属于web的书的合集?
 inter_list = redis.sunion("tag.ruby", "tag:web")

本文来自网络:https://www.cnblogs.com/xiaoxi/p/7007695.html

Ajax跨域请求COOKIE无法带上 怎么搞?

jquery的ajax的post方法请求:

$.ajax({
type: “POST”,
url: “http://xxx.com/api/test”,
dataType: ‘jsonp’,
xhrFields: {
withCredentials: true
},
crossDomain: true,
success:function(){
},
error:function(){
}
})

服务器端设置:

header(“Access-Control-Allow-Credentials: true”);

header(“Access-Control-Allow-Origin: http://www.xxx.com”);

redis监控

 

  • 摘要:redis-cli提供原生的监控视图1、redis-cli–stat查看当前连接的客户端数,连接数等2、redis-cli–bigkeys对当前占用内存最大的键值和平均的键值数据,也可以通过指定-i参数定时查看当前的视图情况。下图中为测试库,只对键值c做了操作,因此如下图中最大的键值为c3、redis-cli–scan提供和keys*相似的功能,查看当前的键值情况,可以通过正则表达如–pattern’user:*’进行键值的分析,并且配合shell命令进行相关的统计分
  • redis-cli提供原生的监控视图
    1、redis-cli –stat查看当前连接的客户端数,连接数等

    redis监控_Python

    2、redis-cli –bigkeys对当前占用内存最大的键值和平均的键值数据,也可以通过指定-i参数定时查看当前的视图情况。下图中为测试库,只对键值c做了操作,因此如下图中最大的键值为c

    redis监控_Python

    3、redis-cli –scan提供和keys *相似的功能,查看当前的键值情况,可以通过正则表达如

    –pattern ‘user:*’
    进行键值的分析,并且配合shell命令进行相关的统计分析

    redis-cli提供原生的Monitor监控命令以及基于该命令的扩展监控框架

    1、redis-cli monitor打印出所有sever接收到的命令以及其对应的客户端地址

    redis监控_Python

    2、RedisLive是基于python3实现的可视化监控界面

    https://github.com/nkrode/RedisLive

    http://www.nkrode.com/article/real-time-dashboard-for-redis

    3、redis-stat是基于ruby实现的可视化监控界面

    https://github.com/junegunn/redis-stat

    4、redis-faina是基于python2实现的可视化监控界面,监控100行命令

    redis监控_Python

    https://github.com/facebookarchive/redis-faina

本文来自网络:https://www.aliyun.com/jiaocheng/452905.html

 

phpredis中的connect和pconnect

本文转自网络:https://blog.csdn.net/u013474436/article/details/53118475

现在不管是在缓存方面,还是NoSQL方面,Redis很火也很流行,但是使用方面的经验不是很多,包括Redis的一些优化配置,还有使用Redis的一些技巧和经验都没有一个官方的指导,所以在网上能搜索到很多相关的东西,但是发现不一定完全匹配自己遇到的一些问题,而且有的文章只是告诉你要这么做,但是没有深究到底是为什么?

最近碰到一个项目的优化,该项目其实逻辑很简单,大的结构就是处理用户的请求,然后读Redis,返回对应的数据。而问题的所在在于该项目有个特点,就是存在整点效应——平时访问量比较低,服务器压力不大,但是整点的时候并发能够达到平时的4-5倍,服务器完全抗不住。所以我们就慢慢梳理整个项目的架构,还有流程,想从中发现问题的所在。

为了先解决并发高服务器负载过高的问题,我们首先分析了…(话扯远了,背景就介绍到这里,呵呵。。)

首先先介绍下connectpconnect的区别。
connect:脚本结束之后连接就释放了。
pconnect:脚本结束之后连接不释放,连接保持在php-fpm进程中。
为了验证这点,我们可以写个脚本测试一下。
其中服务器是nginxphp-fpm采用静态方式,因为动态方式下php-fpm的进程数量可能会变化,所以为了简单我们采用静态方式启动。
其中php-fpm的数量我们设置成5个。

下面的脚本测试使用connect的情况,我们让脚本连接到redis,然后休眠10s。

<?php
$app = new App ();
$app->get ( '/', function () {
    $redis = new Redis ();
    $redis->connect ( '127.0.0.1' );
    sleep(10);
    echo 'Hello World';
    // $redis->close ();
} );

return $app;

然后我们运行5个请求:

curl http://localhost:8081

这时候我们可以看下redis中的connect_clients:

$ redis-cli info | grep connected_clients
connected_clients:14

等脚本运行完毕之后我们再看一下connect_clients:

$ redis-cli info | grep connected_clients
connected_clients:9

之前建立的redis连接资源被释放了。
我们修改上面的代码,把connect改成pconnect

<?php
$app = new App ();
$app->get ( '/', function () {
    $redis = new Redis ();
    $redis->pconnect ( '127.0.0.1' );
    sleep(10);
    echo 'Hello World';
    // $redis->close ();
} );

return $app;

和上面同样的操作,发现脚本脚本运行结束后connected_clients还是14:

$ redis-cli info | grep connected_clients
connected_clients:14

这说明脚本运行结束后,redis连接资源并没有释放,而是由php-fpm进程保持(可以通过 kill php-fpm看到,当脚本停止运行后连接释放)

所以使用pconnect代替connect,可以减少频繁建立redis连接的消耗。

另外,使用pconnect还可以减少同一个进程(php-fpm)频繁建立连接的消耗,可以通过以下代码验证:

使用connect的情况:

<?php
$redis1 = new Redis();
$redis1->connect('127.0.0.1');
sleep(5);
$redis2 = new Redis();
$redis2->connect('127.0.0.1');
sleep(5);
//$redis->close();
//$redis2->close();

运行上述脚本,会发现connect_clients会增加2个。

使用pconnect的情况:

<?php
$redis1 = new Redis();
$redis1->pconnect('127.0.0.1');
sleep(5);
$redis2 = new Redis();
$redis2->pconnect('127.0.0.1');
sleep(5);
//$redis->close();
//$redis2->close();

而运行上述代码,connect_clients只会增加1个,这说明在一个进程中,pconnect是可以保持redis连接状态提供复用的。

Nginx中使用htpasswd配置Http认证

监控Nginx服务器运行情况的模块。只要用户在浏览器输入http://your_ip/status,就可以访问监控页面。这样很不安全,因为任何人都可以访问这个页面。是否可以再添加一个授权模块呢?

答案是肯定的,Nginx的源码提供了ngx_http_auth_basic_module这个模块,它可以来解决这个问题。这个模块是默认就编译进nginx的,可以直接拿来使用。

ngx_http_auth_basic_module它提供了最基本的http认证,这是http协议支持的,它会弹出一个框让你输入用户名和密码,只有用户名和密码输入正确了才能访问,这样就能防止http://your_ip/status被任何人访问了。

ngx_http_auth_basic_module是使用文件作为存储介质的,用户名是明文存储,而密码是加密之后再存储,这样在认证框输入的用户名和密码必须和文件的信息匹配才能认证成功。这里使用htpasswd这个命令来生成存放用户名和密码的文件。
什么是 htpasswd ?

htpasswd 是开源 http 服务器 apache httpd 的一个命令工具,用于生成 http 基本认证的密码文件。
安装

ubuntu

sudo apt-get install apache2-utils

1

centos

yum -y install httpd

1

使用
语法

htpasswd(选项)(参数)

1

htpasswd使用帮助

htpasswd 选项说明

-c 创建passwdfile.如果passwdfile 已经存在,那么它会重新写入并删去原有内容.
-n 不更新passwordfile,只将加密后的用户名密码显示在屏幕上;
-m 默认采用MD5算法对密码进行加密
-d 采用CRYPT算法对密码进行加密
-p 不对密码进行进行加密,即使用普通文本格式的密码
-s 采用SHA算法对密码进行加密
-b 命令行中一并输入用户名和密码而不是根据提示输入密码,可以看见明文,不需要交互
-D 删除指定的用户

htpasswd 参数说明

用户:用户名
密码:用户的密码

实例

利用htpasswd命令添加用户

shell> htpasswd -c /usr/local/nginx/.htpasswd Javen
New password:
Re-type new password:
Adding password for user Javen

或者不用交互的模式

shell> htpasswd -bc /usr/local/nginx/.htpasswd Javen javen205

在/usr/local/nginx/目录下生成一个.htpasswd文件,用户名Javen,密码javen205,默认采用MD5加密方式。

在原有密码文件中增加下一个用户

去掉-c选项即可在第一个用户之后添加第二个用户

shell> htpasswd -b /usr/local/nginx/.htpasswd JJ jj

不更新密码文件,只显示加密后的用户名和密码

不更新.passwd文件,只在屏幕上输出用户名和经过加密后的密码。

shell> htpasswd -nb Javen Javen205

利用htpasswd命令删除用户名和密码

shell> htpasswd -D /usr/local/nginx/.htpasswd Javen
Deleting password for user Javen

利用htpasswd命令修改密码

htpasswd 并没有直接修改密码的函数,需要先使用htpasswd删除命令删除指定用户,再利用htpasswd添加用户命令创建用户即可实现修改密码的功能。

htpasswd -D .htpasswd Javen
htpasswd -b .htpasswd Javen javen205

Nginx中使用htpasswd

在配置文件中打开http basic auth认证。

location /status {
auth_basic “Restricted”;
auth_basic_user_file /usr/local/nginx/.htpasswd;
vhost_traffic_status_display;
vhost_traffic_status_display_format html;
}

效果图

访问时提示密码框

本文来自网络:https://blog.csdn.net/zyw_java/article/details/80561316

如果设置好,访问的时候提示500错误,查看nginx错误日志,基本是htpasswd访问权限问题