一.内存屏障与volatile
1. 由于现代操作系统都是多处理器操作系统,每个处理器都会有??的缓存,可能存再不同处理器缓存不?致的问题,?且由于操作系统可能存在重排序,导致读取到错误的数据,因此,操作系统提供了?些内存屏障以解决这种问题。
LoadLoad屏障
对于Load1; LoadLoad; Load2 ,操作系统保证在Load2及后续的读操作读取之前,Load1已经读取。
StoreStore屏障
对于Store1; StoreStore; Store2 ,操作系统保证在Store2及后续的写操作写?之前,Store1已经写?。
LoadStore屏障
对于Load1; LoadStore; Store2,操作系统保证在Store2及后续写?操作执?前,Load1已经读取。
StoreLoad屏障
对于Store1; StoreLoad; Load2 ,操作系统保证在Load2及后续读取操作执?前,Store1已经写?,开销较?,但是同时具备其他三种屏障的效果。
2. 当我们声明某个变量为volatile时,这个变量便具有了线程可?性。volatile通过在读写操作前后添加内存屏障,完成了数据的及时可?性。
3.当写??个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。
当读?个volatile变量时,JMM会把该线程对应的本地内存置为?效,从主内存中读取所有的共享变量。
4.
- volatile读之前,会添加LoadLoad内存屏障。
- volatile读之后,会添加LoadStore内存屏障。
- volatile写之前,会添加StoreStore内存屏障。
- volatile写之后,会添加StoreLoad型内存屏障。
二.java 域的概念
field,域是?种属性,可以是?个类变量,?个对象变量,?个对象?法变量或者是?个函数的参数。
三.分布式设计领域的概念
1、分布式系统设计的两?思路:中?化和去中?化
中?化:中?化的设计思想在?然界和?类?活中是如此的普遍和?然,它的设计思想也很简单,分布式集群中的节点按照??分?,可以分为两种??--“领导”和“?活的”,中?化的?个思路就是“领导”通常分发任务并监督“?活的”,谁空闲了就给它安排任务,谁病倒了就?脚踢出去,然后把它的任务分给其他?;中?化的另?个思路是领导只负责?成任务?不再指派任务,由每个“?活的”?发去领任务。
去中?化:全球IP互联?就是?个典型的去中?化的分布式控制架构,联?的任意设备宕机都只会影响很?范围的功能。去中?化设计通常没有“领导”和“?活的”,???样,地位平等,因此不存在单点故障。实际上,完全意义的去中?化分布式系统并不多?,很多看起来是去中?化但?作机制采?了中?化设计思想的分布式系统正在不断涌现,在这种架构下,集群中的领导是动态选择出来的,?不是?为预先指定的,?且在集群发?故障的情况下,集群的成员会?发举?会议选举新的领导。典型案例
如:zookeeper、以及Go语?实现的Etcd。
2、分布式系统的?致性原理
在说明?致性原理之前,可以先了解?下cap理论和base理论,具体?《事务与柔性事务》中的说明。
对于多副本的?致性处理,通常有?种?法:同步更新--即写操作需要等待两个节点都更新成功才返回,这样的话如果?旦发??络分区故障,写操作便不可?,牺牲了A。异步更新--即写操作直接返回,不需要等待节点更新成功,节点异步地去更新数据,这种?式,牺牲了C来保证A。折衷--只要保证集群中超过半数的节点正常并达到?致性即可满?要求,此时读操作只要?较副本集数据的修改时间或者版本号即可选出最新的,所以系统是强?致性的。如果允许“数据?致性存在延迟时间”,则是最终?致性。
如Cassandra中的折衷型?案QUORUM,只要超过半数的节点更新成功便返回,读取时返回多数副本的?致的值。然后,对于不?致的副本,可以通过read repair的?式解决。read repair:读取某条数据时,查询所有副本中的这条数据,?较数据与?多数副本的最新数据是否?致,若否,则进??致性修复。此种情况是强?致性的。
?如Redis的master-slave模式,更新成功?个节点即返回,其他节点异步地去备份数据。这种?式只保证了最终?致性。最终?致性:相?于数据时刻保持?致的强?致性,最终?致性允许某段时间内数据不?致。但是随着时间的增?,数据最终会到达?致的状态。此种情况只能保证最终?致性。著名的DNS也是最终?致性的成功例?。
强?致性算法:1989年就诞?了著名的Paxos经典算法(zookeeper就采?了Paxos算法的近亲兄弟Zab算法),但由于Paxos算法难以理解、实现和排错,所以不断有?尝试优化算法,2013年终于有了重?突破:Raft算法的出现,其中Go语?实现的Raft算法就是Etcd,功能类似于zookeeper。
Base的思想:基本可?、柔性状态、最终?致性,主要针对数据库领域的数据拆分,通过数据分?(如Mycat、Amodeba等)来提升系统的可?性。由于分?拆分后会涉及分布式事务,所以接下来看?下如何?最终?致性的思路来实现分布式事务,也就是柔性事务。
3、分布式系统的关键Zookeeper
?标是解决分布式系统的?个问题:集群集中化配置,集群节点动态发现机制,简单可靠的节点Leader选举机制,分布式锁。
ZNode有?个ACL访问权限控制列表,提供对节点增删改查的API,提供监听ZNode变化的实时通知接?--Watch接?。
ZNode类型:持久节点(可以实现配置中?)、临时节点(和创建这个节点的客户端会话绑定,可实现集群节点动态发现,可以实现服务注册中?)、时序节点(创建节点时会加上数字后缀,通过选择编号最?的ZNode可以实现Leader选举机制)、临时性时序节点(同时具备临时节点和时序节点的特性,主要?于分布式锁的实现)。
四.如何实现双11的购物限流(redis实现?案)
1、限流策略:
Nginx接?层限流
按照?定的规则如帐号、IP、系统调?逻辑等在Nginx层?做限流
业务应?系统限流
通过业务代码控制流量这个流量可以被称为信号量,可以理解成是?种锁,它可以限制?项资源最多能同时被多少进程访问。
2、lua脚本:
1 local key = KEYS[1] --限流KEY(?秒?个) 2 local limit = tonumber(ARGV[1]) --限流?? 3 local current = tonumber(redis.call('get', key) or "0") 4 if current + 1 > limit then --如果超出限流?? 5 return 0 6 else --请求数+1,并设置2秒过期 7 redis.call("INCRBY", key,"1") 8 redis.call("expire", key,"2") 9 end 10 return 1
减少?络开销: 不使? Lua 的代码需要向 Redis 发送多次请求, ?脚本只需?次即可, 减少?络传输;
原?操作: Redis 将整个脚本作为?个原?执?, ?需担?并发, 也就?需事务;
复?: 脚本会永久保存 Redis 中, 其他客户端可继续使?.
五.mysql调优
1、选择最合适的字段属性:类型、?度、是否允许NULL等;尽量把字段设为not null,??查询时对?是否为null;
2.要尽量避免全表扫描,?先应考虑在 where 及 order by 涉及的列上建?索引。
3.应尽量避免在 where ?句中对字段进? null 值判断、使?!= 或 <> 操作符,否则将导致引擎放弃使?索引?进?全表扫描
4.应尽量避免在 where ?句中使? or 来连接条件,如果?个字段有索引,?个字段没有索引,将导致引擎放弃使?索引?进?全表扫描
5.in 和 not in 也要慎?,否则会导致全表扫描
6.模糊查询也将导致全表扫描,若要提?效率,可以考虑字段建?前置索引或?全?检索;
7.如果在 where ?句中使?参数,也会导致全表扫描。因为SQL只有在运?时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运?时;它必须在编译时进?选择。然 ?,如果在编译时建?访问计划,变量的值还是未知的,因??法作为索引选择的输?项。
9.应尽量避免在where?句中对字段进?函数操作,这将导致引擎放弃使?索引?进?全表扫描。
10.不要在 where ?句中的“=”左边进?函数、算术运算或其他表达式运算,否则系统将可能?法正确使?索引。
11.在使?索引字段作为条件时,如果该索引是复合索引,那么必须使?到该索引中的第?个字段作为条件时才能保证系统使?该索引,否则该索引将不会被使?,并且应尽可能的让字段顺序与索引顺序相?致。
12.不要写?些没有意义的查询,如需要?成?个空表结构:
13.Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调?会引起明显的性能消耗,同时带来?量?志。
14.对于多张?数据量(这??百条就算?了)的表JOIN,要先分?再JOIN,否则逻辑读会很?,性能很差。
15.select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是?定要杜绝的。
16.索引并不是越多越好,索引固然可以提?相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况?定。?个表的索引数最好不要超过6个,若太多则应考虑?些不常使?到的列上建的索引是否有 必要。
17.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,?旦该列值改变将导致整个表记录的顺序的调整,会耗费相当?的资源。若应?系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为
clustered 索引。
18.尽量使?数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个?较字符串中每?个字符,?对于数字型??只需要?较?次就够了。
19.尽可能的使? varchar/nvarchar 代替 char/nchar ,因为?先变?字段存储空间?,可以节省存储空间,其次对于查询来说,在?个相对较?的字段内搜索效率显然要?些。
20.任何地?都不要使? select * from t ,?具体的字段列表代替“*”,不要返回?不到的任何字段。
21.尽量使?表变量来代替临时表。如果表变量包含?量数据,请注意索引?常有限(只有主键索引)。
22. 避免频繁创建和删除临时表,以减少系统表资源的消耗。临时表并不是不可使?,适当地使?它们可以使某些例程更有效,例如,当需要重复引??型表或常?表中的某个数据集时。但是,对于?次性事件, 最好使?导出表。
23.在新建临时表时,如果?次性插?数据量很?,那么可以使? select into 代替 create table,避免造成?量 log ,以提?速度;如果数据量不?,为了缓和系统表的资源,应先create table,然后insert。
24.如果使?到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较?时间锁定。
25.尽量避免使?游标,因为游标的效率较差,如果游标操作的数据超过1万?,那么就应该考虑改写。
26.使?基于游标的?法或临时表?法之前,应先寻找基于集的解决?案来解决问题,基于集的?法通常更有效。
27.与临时表?样,游标并不是不可使?。对?型数据集使? FAST_FORWARD 游标通常要优于其他逐?处理?法,尤其是在必须引??个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要?使?游标执?的速度快。如果开发时 间允许,基于游标的?法和基于集的?法都可以尝试?下,看哪?种?法的效果更好。
28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。?需在执?存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
29.尽量避免?事务操作,提?系统并发能?。
30.尽量避免向客户端返回?数据量,若数据量过?,应该考虑相应需求是否合理。