web,部署,数据库方面知识点点

1. 序列化和反序列化是什么,在代码中是如何实现的?

序列化: 通过某种方式把数据结构或对象写入到磁盘文件中或通过网络传到其他节点的过程。例如Django中把模型类中的对象转化为json格式来存储。

反序列化:把磁盘中对象或者把网络节点中传输的数据恢复为python的数据对象的过程。例如:把前端传来传来的json格式数据转换为django的模型类对象。

在meiduo_mall的商城项目中每个模块通过使用序列化器(serializers)来实现序列化或反序列化。例如下面的购物车序列化器,把SKU模型类中的字段通过fields来指明,然后序列化输出。也可以通过ModelSerializer自带的增加方法实现反序列化。

class
CartSKUSerializer(serializers.ModelSerializer):
    """
    购物车商品数据序列化器
    """
    count = serializers.IntegerField(label='数量')
    class Meta:
        model = SKU
        fields = ('id', 'name', 'default_image_url', 'price', 'count')

2. 多线程在web项目中的应用

多线程一般在使用在进行I0操作时,基于这个结论,提供以下几个使用场景:

  1. 比如一个业务逻辑需要并行的操作几个文件的读写,还得是同步执行,不能异步执行,这时候就可以开启多线程来读写这几个文件。
  2. 视图中需要请求多个第三方接口,仍然也是要求同步的,不能异步,这时候也可以用多线程去并行请求多个第三方接口。
  3. 比如在订单系统中,订单提交后就要修改商品的库存、商品的销量等这样的操作。

二. 服务器以及部署问题

1.说一下TCP的三次握手客户端在访问服务器的什么?在三次握手中服务器内部发生了什么事情?

建立起一个TCP连接需要经过“三次握手”:

1) Client首先发送一个连接试探,ACK=0 表示确认号无效,SYN = 1 表示这是一个连接请求或连接接受报文,同时表示这个数据报不能携带数据,seq = x 表示Client自己的初始序号(seq = 0 就代表这是第0号帧),这时候Client进入syn_sent状态,表示客户端等待服务器的回复

2) Server监听到连接请求报文后,如同意建立连接,则向Client发送确认。TCP报文首部中的SYN 和 ACK都置1 ,ack = x + 1表示期望收到对方下一个报文段的第一个数据字节序号是x+1,同时表明x为止的所有数据都已正确收到(ack=1其实是ack=0+1,也就是期望客户端的第1个帧),seq = y 表示Server 自己的初始序号(seq=0就代表这是服务器这边发出的第0号帧)。这时服务器进入syn_rcvd,表示服务器已经收到Client的连接请求,等待client的确认。

3) Client收到确认后还需再次发送确认,同时携带要发送给Server的数据。ACK 置1 表示确认号ack= y + 1 有效(代表期望收到服务器的第1个帧),Client自己的序号seq= x + 1(表示这就是我的第1个帧,相对于第0个帧来说的),一旦收到Client的确认之后,这个TCP连接就进入Established状态,就可以发起http请求了。

在这里插入图片描述

注意:

  1. 三次握手,并没有传递数据,建立连接后才进入到数据传输的状态。

  2. SYN(synchronous)是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时,客户机首先发出一个SYN消息,服务器使用SYN+ACK应答表示接收到了这个消息,最后客户机再以ACK消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。

2. 不同应用服务器,session怎么共享?

主要可以考虑下面几个方法,每个方法都有优缺点,具体实施时根据业务选择:

1.通过数据库mysql共享session

a.采用一台专门的mysql服务器来存储所有的session信息。

用户访问随机的web服务器时,会去这个专门的数据库服务器check一下session的情况,以达到session同步的目的。
缺点就是:依懒性太强,mysql服务器无法工作,影响整个系统;

b.将存放session的数据表与业务的数据表放在同一个库。如果mysql做了主从,需要每一个库都需要存在这个表,并且需要数据实时同步。

缺点:用数据库来同步session,会加大数据库的负担,数据库本来就是容易产生瓶颈的地方,如果把session还放到数据库里面,无疑是雪上加霜。上面的二种方法,第一点方法较好,把放session的表独立开来,减轻了真正数据库的负担 。但是session一般的查询频率较高,放在数据库中查询性能也不是很好,不推荐使用这种方式。

2.通过cookie共享session

把用户访问页面产生的session放到cookie里面,就是以cookie为中转站。

当访问服务器A时,登录成功之后将产生的session信息存放在cookie中;当访问请求分配到服务器B时,服务器B先判断服务器有没有这个session,如果没有,在去看看客户端的cookie里面有没有这个session,如果cookie里面有,就把cookie里面的sessoin同步到web服务器B,这样就可以实现session的同步了。

缺点:cookie的安全性不高,容易伪造、客户端禁止使用cookie等都可能造成无法共享session。

3.通过服务器之间的数据同步session

使用一台作为用户的登录服务器,当用户登录成功之后,会将session写到当前服务器上,我们通过脚本或者守护进程将session同步到其他服务器上,这时当用户跳转到其他服务器,session一致,也就不用再次登录。

缺陷:速度慢,同步session有延迟性,可能导致跳转服务器之后,session未同步。而且单向同步时,登录服务器宕机,整个系统都不能正常运行。

4.通过redis共享session

redis与memcache一样,都是将数据放在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

根据实际开发应用,一般选择使用memcache或redis方式来共享session.

3.你们部署服务器是几台,并发量是多大;怎么进行模拟抢购的同一时间请求量是多少; 怎么防止带刷(黄牛) 如果说部署两台服务器 不同的进程 怎么实现乐观锁 ?

Django项目用到5台服务器。部署在一台上面,因为用户量比较少。

模拟抢购主要解决2个问题:

  1. 高并发对数据库产生的压力

  2. 竞争状态下如何解决库存的正确减少("超卖"问题)

对于第一个问题可以使用redis解决,避免对数据库的直接操作较少数据防护的查询压力。

对于“超卖”项目中使用的是“乐观锁”解决的:

防止黄牛代刷是个开放题目,下面提供几种思路:

  1. 对于一个账号,一次发起多个请求。

    在程序入口处,一个账号只允许接受1个请求,其他请求过滤。实现方案,可以通过Redis这种内存缓存服务,写入一个标志位(只允许1个请求写成功,结合watch的乐观锁的特性),成功写入的则可以继续参加。

  2. 对于账号一次发送多个请求

    可以检测机器的ip发送请求的频率,假如某个固定ip的频率特别高,就弹出验证码来减少请求的频率。

乐观锁的实现原理:

每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。

实现方式:可以在数据表中添加一个冗余字段,比如时间戳,在更新提交的时候检查当前数据库中数据的时间戳和自己更新前取到的时间戳进行对比,如果一致则OK,否则就是版本冲突 。

4.高并发实际应用的经验,分布式实际经验

高并发:系统同时并行处理的请求数量。

web网站都是追求在同时尽可能多的处理请求,我们可以从以下几个方面考虑尽可能提高网站的并发量:

  1. 减少数据库访问次数,

  2. 文件和数据库分离(比如页面静态化),

  3. 大数据分布式存储(比如:Mysql的主从配置读写分离),

  4. 服务器的集群负载均衡,

  5. 页面缓存的使用(对于页面使用局部页面缓存或数据缓存),

  6. nosql内存数据库代替关系型数据库等

高并发项目中的例子:

  1. 省市区的三级联动的数据,这些我们经常使用却不经常变化的数据,我们一般是一次全部读取出来缓存到web服务器的本地进行保存,假如有更新就重新读取;

  2. 对于首页商品经常变化的数据使用redis进行缓存,比如说广告,可以使用缓存把广告查询出来的数据进行缓存,对于首页展示广告的部位使用局部缓存。来提高页面响应的速度。

分布式的案例

  1. Django项目中MySQL主从配置读写分离

    在Django项目中为了提高数据库的查询速度,我们使用主从配置来实现MySQL的读写分离。但是虽然我们这么做能提高一部分的性能,假如用户的请求依旧很多,还是有访问的瓶颈,所以建议使用基于内存的非关系型数据库,比如Mongo或Redis.

  2. 爬虫中的分布式爬虫这两个角度来说。

    爬虫项目使用scrapy-redis来实现分布式,由于scrapy本身的调度器(scheduler)并不支持分布式,所以使用第三方插件scrapy-redis来实现。scrapy-redis是把所有请求的url通过调度器存入redis的有序集合(zset)中同时基于fingerpoint(或者BloomFilter)来实现去重,而spider只要启动多个线程或进程从redis的集合中取url进行解析数据就可以。

数据库

1. Mysql数据库中如何实现更快速度的查找 ?

Mysql实现快速查找可以从下面几个角度考虑实现,具体方法有很多要配合使用:

  1. 硬件和网络方面:这要公司前期投入很多金钱。

  2. 给相应的字段添加索引,避免全文的扫描;

  3. 缓存查询的结果,减少数据库的查询次数;

  4. 等价谓词的重写。比如between and 更改为>=、<= 等,查询的速度提升

  5. 将外连接转化成内连接,减少IO的操作。

  6. 避免在where语句中使用!= 、<、>等操作符

  7. 联接优化器,使用不同连接顺序的表,查到相同的结果。

2. 对SQL有哪些优化

SQL优化一般理解是让SQL运行更快。实现MySQL优化可以从下面这些角度实现:

  1. 在查询频率高的字段建立索引和缓存,对于经常查询的数据建立索引会提升查询速度,同时把经常用的数据进行缓存,避免对数据库的多次查询减少磁盘的IO,节约时间。

  2. 在where查询子语句上尽量避免对字段的NULL值判断,否则数据库引擎将会放弃索引而使用全表扫描. 如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:select id from t where num=0

  3. 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

  4. 应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

select id from t where num=10 or num=20       

可以这样查询:       

select id from t where num=10     

union all      

select id from t where num=20     
      
  1. in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)   

对于连续的数值,能用 between 就不要用 in 了: 

select id from t where num between 1 and 3   
  1. 下面的查询也将导致全表扫描:
select id from t where name like '%abc%'  
  1. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2=100      

应改为: 

select id from t where num=100*2      
  1. 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where
substring(name,1,3)='abc'--name以abc开头的id
应改为: 
select id from t where name
like 'abc%'
  1. 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

  2. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,
    否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

  3. 不要写一些没有意义的查询,如需要生成一个空表结构:

select col1,col2 into #t from t where 1=0   

这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:  

create table #t(...)     
  1. 很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num
from b)    

用下面的语句替换:      

select num from a where exists(select 1
from b where num=a.num)
  1. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,
    如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

  2. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

  3. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。
    这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

  4. 尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间, 其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

  5. 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

  6. 避免频繁创建和删除临时表,以减少系统表资源的消耗。

3、Redis有哪些特点?如何向Redis中存储数据?

Redis特点:

  1. 速度快。Redis是用C语言实现的,所有数据存储在内存中以键值对形式保存。

  2. 持久化
    Redis的所有数据存储在内存中,对数据的更新将异步地保存到磁盘上。

  3. 支持多种数据结构
    Redis支持五种数据结构:String、List、Set、Hash、Zset

  4. 支持多种编程语言。Java、php、Python、Ruby、Lua、Node.js

  5. 功能丰富。除了支持五种数据结构之外,还支持事务、流水线、发布/订阅、消息队列等功能。

  6. 源码简单,约23000行C语言源代码。

  7. 主从复制
    主服务器(master)执行添加、修改、删除,从服务器执行查询。

  8. 高可用及分布式 支持高可用和分布式

如何存储数据,使用python操作数据库
在这里插入图片描述
今天就先到这里,后面再慢慢总结吧。

发布了9 篇原创文章 · 获赞 1 · 访问量 450

猜你喜欢

转载自blog.csdn.net/qq_45785397/article/details/104335439
今日推荐