本章内容
- paramiko基本使用
- MySQL基础语法
- pymysql模块使用
- Python操作memcached
- Python操作redis
一、paramiko模块基本使用
paramiko是Python的一个模块,如果电脑没有装这个模块的话需要使用pip3 install paramiko。paramiko模块的主要功能是连接服务器并在远端服务器执行命令并把结果返回到本地。目前很多自动化工具也用的是该模块,比如ansible。
- 基于SSH密码登陆
import paramiko #创建一个ssh socket对象 ssh_client = paramiko.SSHClient() #允许连接不在know_hosts文件中的主机 ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #连接到ssh服务器 ssh_client.connect(hostname=‘95.163.199.239‘,port=端口,username=‘root‘,password=‘passwd‘,timeout=56) #执行命令, stdin,stdout,stderr = ssh_client.exec_command(‘df‘) #获取结果,结果是bytes类型 result = stdout.read() result_str = result.decode(‘utf-8‘) print(result_str) #关闭连接 ssh_client.close()
transport = paramiko.Transport((‘95.163.199.239‘,端口)) transport.connect(username=‘用户‘,password=‘密码‘) ssh = paramiko.SSHClient() ssh._transport = transport stdin,stdout,stderr = ssh.exec_command(‘df‘) print(stdout.read().decode(‘utf-8‘)) transport.close()
- 基于RSA秘钥登陆
#创建秘钥的文件对象 key_file = open(r‘E:\filename\filename\id_rsa_2048‘) #服务器的秘钥 rsa_key = paramiko.RSAKey.from_private_key(key_file,‘rsa_password‘) #连接ssh服务器 ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #登陆服务器携带秘钥 ssh.connect(hostname=‘95.163.199.239‘,port=端口,username=‘root‘,pkey=rsa_key) stdin,stdout,stderr = ssh.exec_command(‘df‘) print(stdout.read().decode(‘utf-8‘)) ssh.close()
key_file = open(r‘E:\filename\filename\id_rsa_2048‘) rsa_key = paramiko.RSAKey.from_private_key(key_file,‘rsa_password‘) transport = paramiko.Transport((‘95.163.199.239‘,port)) transport.connect(username=‘root‘,pkey=rsa_key) ssh = paramiko.SSHClient() ssh._transport = transport stdin,stdout,stderr = ssh.exec_command(‘df‘) print(stdout.read().decode(‘utf-8‘)) transport.close()
- 使用paramiko对文件进行上传和下载
import paramiko transport = paramiko.Transport((‘hostname‘,22)) transport.connect(username=‘leon‘,password=‘123‘) sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put(‘/tmp/location.py‘, ‘/tmp/test.py‘) # 将remove_path 下载到本地 local_path sftp.get(‘remove_path‘, ‘local_path‘)
- 基于秘钥的上传下载
import paramiko private_key = paramiko.RSAKey.from_private_key_file(‘/home/auto/.ssh/id_rsa‘) transport = paramiko.Transport((‘hostname‘, 22)) transport.connect(username=‘leon‘, pkey=private_key ) sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put(‘/tmp/location.py‘, ‘/tmp/test.py‘) # 将remove_path 下载到本地 local_path sftp.get(‘remove_path‘, ‘local_path‘)
class SSH_Client(object): def __init__(self,host=None,port=None,username=None,password=None): self.host = host self.port = port self.username = username self.password = password self._transport = None def run(self): self.conn() def conn(self): transport = paramiko.Transport((self.host,self.port)) transport.connect(username=self.username,password=self.password) self._transport = transport def close(self): self._transport.close() def command(self): ssh = paramiko.SSHClient() ssh._transport = self._transport while True: command = input(‘[localhost~]#:‘).strip() if command: if command == "exit": self.close() exit() else: stdin,stdout,stderr = ssh.exec_command(command) print(stdout.read().decode(‘utf-8‘)) else: continue ssh = SSH_Client() ssh.run()
二、MySQL的基本语法
-用户管理
创建用户- create user ‘username‘@‘ipaddr‘ identified by ‘password‘;
- 删除用户 drop user ‘username‘@‘ipaddr‘;
- 修改用户 rename user ‘username‘@‘ipaddr‘ to ‘new_username‘@‘ipaddr‘;
- 修改密码 set password for ‘username‘@‘ipaddr‘ = Password(‘new_password‘);
- 查看目前所有用户 select host,user from mysql.user;
授权管理:
show grants for ‘username‘@‘ipaddr‘; - 查看权限
grant 权限 on 数据库.表 to ‘用户名‘@‘密码‘ 授权管理:
revoke 权限 on 数据库.表 from ‘用户名‘@‘密码‘ 移除权限
all privileges 除grant外的所有权限 select 仅查权限 select,insert 查和插入权限 ... usage 无访问权限 alter 使用alter table alter routine 使用alter procedure和drop procedure create 使用create table create routine 使用create procedure create temporary tables 使用create temporary tables create user 使用create user、drop user、rename user和revoke all privileges create view 使用create view delete 使用delete drop 使用drop table execute 使用call和存储过程 file 使用select into outfile 和 load data infile grant option 使用grant 和 revoke index 使用index insert 使用insert lock tables 使用lock table process 使用show full processlist select 使用select show databases 使用show databases show view 使用show view update 使用update reload 使用flush shutdown 使用mysqladmin shutdown(关闭MySQL) super ????使用change master、kill、logs、purge、master和set global。还允许mysqladmin????????调试登陆 replication client 服务器位置的访问 replication slave 由复制从属使用
用户名@IP地址 用户只能在改IP下才能访问 用户名@192.168.1.% 用户只能在改IP段下才能访问(通配符%表示任意) 用户名@% 用户可以再任意IP下访问(默认IP地址为%)
grant all privileges on db1.tb1 TO ‘用户名‘@‘IP‘ grant select on db1.* TO ‘用户名‘@‘IP‘ grant select,insert on *.* TO ‘用户名‘@‘IP‘ revoke select on db1.tb1 from ‘用户名‘@‘IP‘ 示例
PS:在每句MySQL语句后面都会有一个;(分号)
基本操作
create database db1; - 创建一个数据库 drop database db1: - 删除一个数据库 show databases - 查看所有库 use db1; - 进入数据库 create table tb1(id int not null auto_increment primary key,name char(20) null,age int not null)engine=innodb; -创建一个表,engine=innodb支持事务性操作 insert into tb1(name,age) values (‘leon‘,‘20‘); -插入输入 select * from db1.tb1; -查询特定表的数据 select name from db1.tb1 ; -查询特定表的数据 update tb1 set age=68; - 所有表中的age列都是68 update tb1 set age=68 where id=2;- 更新指定数据 delete from tb1; - 删除表里面的所有数据 delete from tb1 where id >1; -删除特定数据 alter table 表名 add 列明 类型: -添加列 alter table 表名 drop column 列名; -删除列 alter table 表名 modify column 列名 类型; --修改列 alter table 表名 change 源列名 新列名 类型 -修改列
foreign key 一对多 create table deparment(id int not null,title char(32) null,); create table tb1(id int not null primary key,username char(32) null,deparment_id int not null,constraint fk_cc foreign key (deparment_id) references deparment(id)); - constraint:约束 - fk_cc:外键的名字可以任意 - (deparment_id)需要外键的列 - references deparment(id):外键到department表的ID列
多对多 create table deparment(id int not null auto_increment primary key,title char(32) null,) create table host(id int not null auto_increment primary key,ip char(32) null,port int null,) create table deparment_to_host(id int not null auto_increment primary key,did int not null,hid int not null,constraint fk_did_deparment foreign key (did) references deparment(id),constraint fk_hid_host foreign key (hid) references host(id))
bit[(M)] 二进制位(101001),m表示二进制位的长度(1-64),默认m=1 tinyint[(m)] [unsigned] [zerofill] 小整数,数据类型用于保存一些范围的整数数值范围: 有符号: -128 ~ 127. 无符号: ~ 255 特别的: MySQL中无布尔值,使用tinyint(1)构造。 int[(m)][unsigned][zerofill] 整数,数据类型用于保存一些范围的整数数值范围: 有符号: -2147483648 ~ 2147483647 无符号: ~ 4294967295 特别的:整数类型中的m仅用于显示,对存储范围无限制。例如: int(5),当插入数据2时,select 时数据显示为: 00002 bigint[(m)][unsigned][zerofill] 大整数,数据类型用于保存一些范围的整数数值范围: 有符号: -9223372036854775808 ~ 9223372036854775807 无符号: ~ 18446744073709551615 decimal[(m[,d])] [unsigned] [zerofill] 准确的小数值,m是数字总个数(负号不算),d是小数点后个数。 m最大值为65,d最大值为30。 特别的:对于精确数值计算时需要用此类型 decaimal能够存储精确值的原因在于其内部按照字符串存储。 FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] 单精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。 无符号: -3.402823466E+38 to -1.175494351E-38, 1.175494351E-38 to 3.402823466E+38 有符号: 1.175494351E-38 to 3.402823466E+38 **** 数值越大,越不准确 **** DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] 双精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。 无符号: -1.7976931348623157E+308 to -2.2250738585072014E-308 2.2250738585072014E-308 to 1.7976931348623157E+308 有符号: 2.2250738585072014E-308 to 1.7976931348623157E+308 **** 数值越大,越不准确 **** char (m) char数据类型用于表示固定长度的字符串,可以包含最多达255个字符。其中m代表字符串的长度。 PS: 即使数据小于m长度,也会占用m长度 varchar(m) varchars数据类型用于变长的字符串,可以包含最多达255个字符。其中m代表该数据类型所允许保存的字符串的最大长度,只要长度小于该最大值的字符串都可以被保存在该数据类型中。 注:虽然varchar使用起来较为灵活,但是从整个系统的性能角度来说,char数据类型的处理速度更快,有时甚至可以超出varchar处理速度的50%。因此,用户在设计数据库时应当综合考虑各方面的因素,以求达到最佳的平衡 text text数据类型用于保存变长的大字符串,可以组多到65535 (2**16 ? 1)个字符。 mediumtext A TEXT column with a maximum length of 16,777,215 (2**24 ? 1) characters. longtext A TEXT column with a maximum length of 4,294,967,295 or 4GB (2**32 ? 1) characters. enum 枚举类型, An ENUM column can have a maximum of 65,535 distinct elements. (The practical limit is less than 3000.) 示例: CREATE TABLE shirts ( name VARCHAR(40), size ENUM(‘x-small‘, ‘small‘, ‘medium‘, ‘large‘, ‘x-large‘) ); INSERT INTO shirts (name, size) VALUES (‘dress shirt‘,‘large‘), (‘t-shirt‘,‘medium‘),(‘polo shirt‘,‘small‘); set 集合类型 A SET column can have a maximum of 64 distinct members. 示例: CREATE TABLE myset (col SET(‘a‘, ‘b‘, ‘c‘, ‘d‘)); INSERT INTO myset (col) VALUES (‘a,d‘), (‘d,a‘), (‘a,d,a‘), (‘a,d,d‘), (‘d,a,d‘); DATE YYYY-MM-DD(1000-01-01/9999-12-31) TIME HH:MM:SS(‘-838:59:59‘/‘838:59:59‘) YEAR YYYY(1901/2155) DATETIME YYYY-MM-DD HH:MM:SS(1000-01-01 00:00:00/9999-12-31 23:59:59 Y) TIMESTAMP YYYYMMDD HHMMSS(1970-01-01 00:00:00/2037 年某时)
a、条件 select * from 表 where id > 1 and name != ‘alex‘ and num = 12; select * from 表 where id between 5 and 16; select * from 表 where id in (11,22,33) select * from 表 where id not in (11,22,33) select * from 表 where id in (select nid from 表) b、通配符 select * from 表 where name like ‘ale%‘ - ale开头的所有(多个字符串) select * from 表 where name like ‘ale_‘ - ale开头的所有(一个字符) c、限制 select * from 表 limit 5; - 前5行 select * from 表 limit 4,5; - 从第4行开始的5行 select * from 表 limit 5 offset 4 - 从第4行开始的5行 d、排序 select * from 表 order by 列 asc - 根据 “列” 从小到大排列 select * from 表 order by 列 desc - 根据 “列” 从大到小排列 select * from 表 order by 列1 desc,列2 asc - 根据 “列1” 从大到小排列,如果相同则按列2从小到大排序 e、分组 select num from 表 group by num select num,nid from 表 group by num,nid select num,nid from 表 where nid > 10 group by num,nid order nid desc select num,nid,count(*),sum(score),max(score),min(score) from 表 group by num,nid select num from 表 group by num having max(id) > 10 特别的:group by 必须在where之后,order by之前 f、连表 无对应关系则不显示 select A.num, A.name, B.name from A,B Where A.nid = B.nid 无对应关系则不显示 select A.num, A.name, B.name from A inner join B on A.nid = B.nid A表所有显示,如果B中无对应关系,则值为null select A.num, A.name, B.name from A left join B on A.nid = B.nid B表所有显示,如果B中无对应关系,则值为null select A.num, A.name, B.name from A right join B on A.nid = B.nid g、组合 组合,自动处理重合 select nickname from A union select name from B 组合,不处理重合 select nickname from A union all select name from B
关于分组和连表操作的说明
-- show tables; -- create TABLE nothing(id int not NULL auto_increment PRIMARY KEY,name CHAR(20) null); -- show tables; -- create student(sid INT not null auto_increment PRIMARY key,name char(20) not null, -- student_cid) -- create table tearcher(tid int not NULL auto_increment PRIMARY KEY,tearcher_name char(20) null) -- create table class(cid int not null auto_increment PRIMARY key, -- class_name char(20), -- class_tid int not null, -- CONSTRAINT fk_class_tid_to_tearcher FOREIGN KEY (class_tid) REFERENCES tearcher(tid)); -- CREATE TABLE student( -- id int not null auto_increment PRIMARY KEY, -- student_name CHAR(20), -- student_cid int not NULL, -- CONSTRAINT student_cid_to_class FOREIGN KEY (student_cid) REFERENCES class(cid) -- ); -- create table course( -- cid int not null auto_increment PRIMARY key, -- course_name char(20), -- course_tid INT not NULL, -- CONSTRAINT student_cid_to_tearcher FOREIGN KEY (course_tid) REFERENCES tearcher(tid) -- ); -- create table score(sid int not null auto_increment PRIMARY KEY, -- number int, -- score_sid int not NULL, -- score_cid int not NULL, -- CONSTRAINT score_sid_to_student FOREIGN KEY (score_sid) REFERENCES student(id), -- CONSTRAINT score_cid_to_course FOREIGN KEY (score_cid) REFERENCES course(cid) -- ); -- INSERT INTO tearcher(tearcher_name) VALUES("张三"); -- INSERT INTO tearcher(tearcher_name) VALUES("李四"); -- INSERT INTO tearcher(tearcher_name) VALUES("王二"); -- INSERT INTO tearcher(tearcher_name) VALUES("天道"); -- INSERT INTO class(class_name,class_tid) VALUES (‘四年三班‘,‘1‘); -- INSERT INTO class(class_name,class_tid) VALUES (‘四年四班‘,‘2‘); -- INSERT INTO class(class_name,class_tid) VALUES (‘四年五班‘,‘3‘); -- INSERT INTO class(class_name,class_tid) VALUES (‘四年六班‘,‘4‘); -- INSERT INTO class(class_name,class_tid) VALUES (‘五年一班‘,‘1‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘Leon‘,‘1‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘麻子‘,‘1‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘胡志虎‘,‘1‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘乔jj‘,‘1‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘老毛‘,‘1‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘张累‘,‘1‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘张耀‘,‘1‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘瑶瑶‘,‘2‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘小明‘,‘2‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘小王‘,‘2‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘小花‘,‘2‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘陈丹丹‘,‘3‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘老魏‘,‘3‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘天机‘,‘3‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘大师‘,‘4‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘若尘‘,‘4‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘明镜‘,‘4‘); -- INSERT INTO student(student_name,student_cid) VALUES (‘明堂‘,‘4‘); -- INSERT INTO course(course_name,course_tid) VALUES (‘生物‘,‘1‘); -- INSERT INTO course(course_name,course_tid) VALUES (‘语文‘,‘2‘); -- INSERT INTO course(course_name,course_tid) VALUES (‘数学‘,‘3‘); -- INSERT INTO course(course_name,course_tid) VALUES (‘英文‘,‘4‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘20‘,‘1‘,‘1‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘30‘,‘1‘,‘2‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘40‘,‘1‘,‘3‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘50‘,‘1‘,‘4‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘50‘,‘2‘,‘1‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘40‘,‘2‘,‘2‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘30‘,‘2‘,‘3‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘20‘,‘2‘,‘4‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘25‘,‘3‘,‘1‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘15‘,‘3‘,‘2‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘35‘,‘3‘,‘3‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘45‘,‘3‘,‘4‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘45‘,‘4‘,‘1‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘35‘,‘4‘,‘2‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘25‘,‘4‘,‘3‘); -- INSERT INTO score(number,score_sid,score_cid) VALUES (‘15‘,‘4‘,‘4‘);
- 各表之间的关系(PRIMARY KEY)
- 查看每个班级有哪些学生
所涉及到连表查询,(left join、right join,inter join)首先前面两者没有什么区别,而后面的inter join在连表的时候会把列中有null的字眼的那一行给去掉
select * from class LEFT JOIN student on class.class_tid = student.student_cid; --普通连表查询 SELECT cid,class_name,student_name from class LEFT JOIN student on class.class_tid = student.student_cid; --过滤指定列连表 SELECT CS.cid,CS.class_name,ST.student_name from class as CS LEFT JOIN student as ST on CS.class_tid = ST.student_cid; -- 给表起一个别名 SELECT CS.cid as ‘班级id‘,CS.class_name as ‘班级名称‘,ST.student_name as ‘学生名称‘ from class as CS LEFT JOIN student as ST on CS.class_tid = ST.student_cid; -- 给列起一个别名
- 查看每个班级里面有多少学生
这面会用到group by 也就是分组的操作。而在分组的时候加条件语句的时候就不是where而是having
SELECT count(CS.cid) as ‘班级人数‘,CS.class_name as ‘班级名称‘ from class as CS LEFT JOIN student as ST on CS.class_tid = ST.student_cid GROUP BY CS.cid; --分组实际上也就是去重,在这里cid的不同代表着一个班级的不同,二count是一个函数,像这样的函数还有max,min,sum等 SELECT count(CS.cid) as ‘班级人数‘,CS.class_name as ‘班级名称‘ from class as CS LEFT JOIN student as ST on CS.class_tid = ST.student_cid GROUP BY CS.cid HAVING count(CS.cid) > 4;--查询班级人数大于4的班级
- python 操作mysql的模块pymysql
pymysql是Python3用来操作MySQL的模块,使用该模块的时候也需要相对的sql功底。基本原理也是创建一个socket连接对端的mysql服务器上面,通过自己写的sql语言在远端执行。
import pymysql #创建一个连接到mysql上面 conn = pymysql.connect(host=‘95.163.199.239‘,port=3306,user=‘leon‘,passwd=‘abc123‘,db=‘test‘) #创建一个游标,来操作sql语句 cursor = conn.cursor() #执行SQL语句,并返回受到影响的行数 effect_row = cursor.execute(‘show tables‘) #res是返回结果,数据类型是元组, #PS fetchall()是返回所有的结果,fetchmant(3)是返回三个结果,fetchone()是返回第一个结果 res = cursor.fetchall() print(res) #提交刚刚执行的SQL语句,如果不执行,刚刚执行的不生效 conn.commit() #关闭游标 cursor.close() #关闭结果 conn.close()
有时候返回的数据类型是元组并不是我们想要的,通过在游标出添加一下东西我们可以是返回的数据类型为字典
import pymysql #创建一个连接到mysql上面 conn = pymysql.connect(host=‘95.163.199.239‘,port=3306,user=‘leon‘,passwd=‘abc123‘,db=‘test‘) #创建一个游标,来操作sql语句,返回的数据类型是字典类型 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) #执行SQL语句,并返回受到影响的行数 effect_row = cursor.execute(‘show tables‘) #res是返回结果,数据类型是元组, #PS fetchall()是返回所有的结果,fetchmant(3)是返回三个结果,fetchone()是返回第一个结果 res = cursor.fetchall() print(res) #提交刚刚执行的SQL语句,如果不执行,刚刚执行的不生效 conn.commit() #关闭游标 cursor.close() #关闭结果 conn.close()
4.Python操作memcached
- memcached基础:
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
memcached安装、启动
wget http://memcached.org/latest tar -zxvf memcached-1.x.x.tar.gz cd memcached-1.x.x ./configure && make && make test && sudo make install PS:依赖libevent yum install libevent-devel apt-get install libevent-dev
启动memcached
memcached -d -m 10 -u root -l 192.168.1.5 -p 12000 -c 256 -P /tmp/memcached.pid 参数说明: -d 是启动一个守护进程 -m 是分配给Memcache使用的内存数量,单位是MB -u 是运行Memcache的用户 -l 是监听的服务器IP地址 -p 是设置Memcache监听的端口,最好是1024以上的端口 -c 选项是最大运行的并发连接数,默认是1024,按照你服务器的负载量来设定
-
P 是设置保存Memcache的pid文件
Python操作memcached的模块需要在网上下载
下载地址是:https:
/
/
pypi.python.org
/
pypi
/
python
-
memcached
安装:进入到下载完成的目录,并在此目录下面打开命令行窗口:使用python setup.py install 进行安装
基本操作: #更加详细的版本
import memcache conn = memcache.Client([‘192.168.1.8:12000‘],debug=True) conn.set(‘k1‘,‘v1‘) print(conn.get(‘k1‘)) #conn = .....创建了一个socket连接到memcached服务器 #conn.set 是往memcached中插入一条数据,在memcached中值支持一种数据类型——字典 #conn.get是获取键为**的值 #debug=True:是否在服务器上显示错误消息,当无法联系。--->这个是源码中注释的时候解释
memcached支持集群
python-memcached模块原生支持集群操作,其原理是在内存维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比。
- 根据算法将 k1 转换成一个数字
- 这个主机的权重是多少就会在这个列表中出现多少次
- 将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 )
- 在主机列表中根据 第2步得到的值为索引获取主机,例如:host_list[N]
- 连接 将第3步中获取的主机,将 k1 = "v1" 放置在该服务器的内存中
- 源码中截图
-
conn= memcache.Client([(‘1.1.1.1:12000‘, 1), (‘1.1.1.2:12000‘, 2), (‘1.1.1.3:12000‘, 1)], debug=True) conn.set(‘k1‘,‘v1‘)
python-memcached的一大堆操作:
add
添加一条键值对,如果已经存在的 key,重复执行add操作异常
import memcache mc = memcache.Client([‘10.211.55.4:12000‘], debug=True) mc.add(‘k1‘, ‘v1‘) # mc.add(‘k1‘, ‘v2‘) # 报错,对已经存在的key重复添加,失败!!!
replace
replace 修改某个key的值,如果key不存在,则异常
import memcache mc = memcache.Client([‘10.211.55.4:12000‘], debug=True) # 如果memcache中存在kkkk,则替换成功,否则一场 mc.replace(‘kkkk‘,‘999‘)
set 和 set_multi
set 设置一个键值对,如果key不存在,则创建,如果key存在,则修改
set_multi 设置多个键值对,如果key不存在,则创建,如果key存在,则修改
import memcache mc = memcache.Client([‘10.211.55.4:12000‘], debug=True) mc.set(‘key0‘, ‘value0‘) mc.set_multi({‘key1‘: ‘val1‘, ‘key2‘: ‘val2‘})
delete 和 delete_multi
delete 在Memcached中删除指定的一个键值对
delete_multi 在Memcached中删除指定的多个键值对
import memcache mc = memcache.Client([‘10.211.55.4:12000‘], debug=True) mc.delete(‘key0‘) mc.delete_multi([‘key1‘, ‘key2‘])
get 和 get_multi
get 获取一个键值对
get_multi 获取多一个键值对
import memcache mc = memcache.Client([‘10.211.55.4:12000‘], debug=True) val = mc.get(‘key0‘) item_dict = mc.get_multi(["key1", "key2", "key3"])
append 和 prepend
append 修改指定key的值,在该值 后面 追加内容
prepend 修改指定key的值,在该值 前面 插入内容
import memcache mc = memcache.Client([‘10.211.55.4:12000‘], debug=True) # k1 = "v1" mc.append(‘k1‘, ‘after‘) # k1 = "v1after" mc.prepend(‘k1‘, ‘before‘) # k1 = "beforev1after"
decr 和 incr
incr 自增,将Memcached中的某一个值增加 N ( N默认为1 )
decr 自减,将Memcached中的某一个值减少 N ( N默认为1 )
import memcache mc = memcache.Client([‘10.211.55.4:12000‘], debug=True) mc.set(‘k1‘, ‘777‘) mc.incr(‘k1‘) # k1 = 778 mc.incr(‘k1‘, 10) # k1 = 788 mc.decr(‘k1‘) # k1 = 787 mc.decr(‘k1‘, 10) # k1 = 777
gets 和 cas
如商城商品剩余个数,假设改值保存在memcache中,product_count = 900
A用户刷新页面从memcache中读取到product_count = 900
B用户刷新页面从memcache中读取到product_count = 900
如果A、B用户均购买商品
A用户修改商品剩余个数 product_count=899
B用户修改商品剩余个数 product_count=899
如此一来缓存内的数据便不在正确,两个用户购买商品后,商品剩余还是 899
如果使用python的set和get来操作以上过程,那么程序就会如上述所示情况!
如果想要避免此情况的发生,只要使用 gets 和 cas 即可,如:
import memcache mc = memcache.Client([‘10.211.55.4:12000‘], debug=True, cache_cas=True) v = mc.gets(‘product_count‘) # ... # 如果有人在gets之后和cas之前修改了product_count,那么,下面的设置将会执行失败,剖出异常,从而避免非正常数据的产生 mc.cas(‘product_count‘, "899")
Ps:本质上每次执行gets时,会从memcache中获取一个自增的数字,通过cas去修改gets的值时,会携带之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交,如果不想等,那表示在gets和cas执行之间,又有其他人执行了gets(获取了缓冲的指定值), 如此一来有可能出现非正常数据,则不允许修改。
Redis
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
1. 使用Redis有哪些好处? (1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) (2) 支持丰富数据类型,支持string,list,set,sorted set,hash (3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行 (4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除 2. redis相比memcached有哪些优势? (1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 (2) redis的速度比memcached快很多 (3) redis可以持久化其数据 3. redis常见性能问题和解决方案: (1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件 (2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次 (3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内 (4) 尽量避免在压力很大的主库上增加从库 (5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3... 这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。 4. MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据 相关知识:redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略: voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰 volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰 volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰 allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰 allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰 no-enviction(驱逐):禁止驱逐数据 5. Memcache与Redis的区别都有哪些? 1)、存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,这样能保证数据的持久性。 2)、数据支持类型 Memcache对数据类型支持相对简单。 Redis有复杂的数据类型。 3),value大小 redis最大可以达到1GB,而memcache只有1MB 6. Redis 常见的性能问题都有哪些?如何解决? 1).Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。 2).Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。 3).Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。 4). Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内 7, redis 最适合的场景 Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差别,那么可能大家就会有疑问,似乎Redis更像一个加强版的Memcached,那么何时使用Memcached,何时使用Redis呢? 如果简单地比较Redis与Memcached的区别,大多数都会得到以下观点: 、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。 、Redis支持数据的备份,即master-slave模式的数据备份。 、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。 (1)、会话缓存(Session Cache) 最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗? 幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。 (2)、全页缓存(FPC) 除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。 再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。 此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。 (3)、队列 Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。 如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。 (4),排行榜/计数器 Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可: 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行: ZRANGE user_scores 0 10 WITHSCORES Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。 (5)、发布/订阅 最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。 Redis提供的所有特性中,我感觉这个是喜欢的人最少的一个,虽然它为用户提供如果此多功能。
redis的下载和安装
wget http:
/
/
download.redis.io
/
releases
/
redis
-
3.0
.
6.tar
.gz
tar xzf redis
-
3.0
.
6.tar
.gz
cd redis
-
3.0
.
6
make
src
/
redis
-
server -->启动
src
/
redis
-
cli
redis>
set
foo bar
OK
redis> get foo
"bar"
API使用
redis-py 的API的使用可以分类为:
- 连接方式
- 连接池
- 操作
- String 操作
- Hash 操作
- List 操作
- Set 操作
- Sort Set 操作
- 管道
- 发布订阅
基本连接
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
import redis #连接redis 服务器 conn = redis.Redis(host=‘192.168.1.8‘,port=6379) #插入一个值 conn.set(‘k1‘,‘v1‘) #获取这个值 print(conn.get(‘k1‘))
连接池
redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。
import redis pool = redis.ConnectionPool(host=‘192.168.1.8‘,port=6379,max_connections=10) conn = redis.Redis(connection_pool=pool) conn.set(‘k1‘,‘CHEN‘) print(conn.get(‘k1‘))