笔记3.14
进程间通信的几种方式
管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
管道这个词很形象地描述了通信双方的行为:
- 分别处于管道的两方,进行数据传输通信。
- 管道是单向的,如果一个进程既要读又要写,需要建立两根管道。类似于水管的特性。
- 管道的两端分别为”读取端”(read end)和”写入端”(write end)。
管道的局限性
- 生命周期是随进程结束而完结
- 只能用于具有亲缘关系的进程通信
- 管道是匿名的,没有名字
为了克服管道上述的局限性,可以使用命名管道(Named Pipe)。它具有管道所有的功能,并且没有管道的上述局限。
# 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
# 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
# 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。如果服务器与客户端在同一台主机上,则是跨进程通信。如果在不同的主机上,则变成了网络通信。
另:远程通信的几种选择(RPC,Webservice,RMI,JMS的区别)
防止sql注入的方法:
1.(简单又有效的方法)PreparedStatement:
采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。
使用好处:
(1).代码的可读性和可维护性.
(2).PreparedStatement尽最大可能提高性能.
(3).最重要的一点是极大地提高了安全性.
原理:
sql注入只对sql语句的准备(编译)过程有破坏作用
而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,
而不再对sql语句进行解析,准备,因此也就避免了sql注入问题.
2.使用正则表达式过滤传入的参数(看看是不是常用的注入格式)
3.字符串过滤(只能使用指定的字符串集合)
4.不要拼接字符串,mybatis使用 # 而不用 $
数据库连接池
先打开一定数量的数据库连接,当使用的时候分配给调用者,调用完毕后返回给连接池,注意返回给连接池后这些连接并不会关闭,而是
准备给下一个调用者进行分配。由此可以看出连接池节省了大量的数据库连接打开和关闭的动作,对系统性能提升的益处不言而喻。
几个概念:
最小连接--应用启动后随即打开的连接数以及后续最小维持的连接数。
最大连接数--应用能够使用的最多的连接数
连接增长数--应用每次新打开的连接个数
(初始连接数)
当连接大于当前连接,会打开新的连接供使用,直到最大连接,此时若还有需求,则等待;
若长时间不满最大连接数,会释放部分连接,但始终高于最小连接。
一般来说最小连接选取平均连接数量,最大连接选取高峰是的顶峰数量。
几种开源的连接池:
1 dbcp:包含两个包
dbcp可能是使用最多的开源连接池,原因大概是因为配置方便,而且很多开源和tomcat应用例子都是使用的这个连接池吧。
这个连接池可以设置最大和最小连接,连接等待时间等,基本功能都有。这个连接池的配置参见附件压缩包中的:dbcp.xml
使用评价:在具体项目应用中,发现此连接池的持续运行的稳定性还是可以,不过速度稍慢,在大并发量的压力下稳定性
有所下降,此外不提供连接池监控
2 c3p0:包含一个包,并提供缓存功能,缓存一定数量的statement,并且可以自动关闭管理连接,stat,resultset等资源。
c3p0是另外一个开源的连接池,在业界也是比较有名的,这个连接池可以设置最大和最小连接,连接等待时间等,基本功能都有。
这个连接池的配置参见附件压缩包中的:c3p0.xml。
使用评价:在具体项目应用中,发现此连接池的持续运行的稳定性相当不错,在大并发量的压力下稳定性也有一定保证,
此外不提供连接池监控。
3.proxool:有性能问题,但建议开发和测试中使用,因为提供监控功能,可以调优和检查代码。
4.除此之外有许多商用的连接池,如weblogic,websphere等。
两个链表如何判断相交
1.走到尽头看是否一样,因为交了之后只能合二为一。找交点的话,到尽头后用栈回溯到不相等的点。
2.让一个链表首尾相连,判断另一个是否有环。(两个指针一快一慢)
3.用HashSet,两个链表分别往其中放,第一个起冲突的就是交点入口。
redis如何避免key冲突:
实际应用中会有多个项目都要使用redis,如果每一个app都要起一个单独的实例那会比较浪费,如果使用一个实例则必须要避免多个项目之间的key冲突问题。
其实redis2.x以上默认支持了16个数据,0-15,每个数据库相互之间是隔离的,这个比较类似关系型数据,如:mysql的多个数据库之间是互不影响。
redis不同数据库(keyspace 在redis-2.6以后的版本)中,key之间是互不影响的,当然,如果要在同一个数据库中也可以,前提是key能够事先定义好,比如按照项目或者app的名称作为前缀,从而避免key冲突的存在。
如果需要几个数据key相同,可以用key-有序set的结构 ,如ZADD命令
$redis->zAdd('key', 10000, '上海');
$redis->zAdd('key', 20001, '北京');
主体结构:
- Atomic : AtomicInteger
- Locks : Lock, Condition, ReadWriteLock
- Collections : Queue, ConcurrentMap
- Executer : Future, Callable, Executor
- Tools : CountDownLatch, CyclicBarrier, Semaphore
包含要点: 原子性操作,指令重排,Happens-before法则(JVM内存模型,volatile语义),CAS操作,Lock锁,AQS队列同步器。
URL到页面的详细过程
能够详细说出
负载均衡与一致性hash
我们的日常web应用开发当中memcached可以算作是当今的标准开发配置了。相信memcache的基本原理大家也都了解过了,memcache虽然是分布式的应用服务,但分布的原则是由client端的api来决定的,api根据存储用的key以及已知的服务器列表,根据key的hash计算将指定的key存储到对应的服务器列表上。
我们通常使用的方法是根据 key的hash值%服务器数取余数 的方法来决定当前这个key的内容发往哪一个服务器的。(CRC32的改进算法 return (crc >> 16) & 0x7fff;)
hash算法好 各个服务器的负载才能均衡。
然而在分布式集群中,对机器的添加删除,或者机器故障后自动脱离集群这些操作是分布式集群管理最基本的功能。如果采用常用的hash(object)%N算法,那么在有机器添加或者删除后,很多原有的数据就无法找到了,这样严重的违反了单调性原则。
一致性hash:当服务实例本身发生变动的时候(如增加服务器,hash算法要变,很多数据要rehash),导致服务列表变动从而会照成大量的cache数据请求会miss,几乎大部分数据会需要迁移到另外的服务实例上。这样在大型服务在线时,瞬时对后端数据库/硬盘照成的压力很可能导致整个服务的crash。
处理服务器的选择不再仅仅依赖key的hash本身而是将服务实例(节点)的配置也进行hash运算。
- 首先求出每个服务节点的hash,并将其配置到一个0~2^32的圆环(continuum)区间上。
- 其次使用同样的方法求出你所需要存储的key的hash,也将其配置到这个圆环(continuum)上。
- 然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务节点上。如果超过2^32仍然找不到服务节点,就会保存到第一个memcached服务节点上。
这样一来,增加服务器的时候,按照原算法,很多key的hash位置不会有大的改变。
蓄水池算法:从N个元素中随机抽取K个元素,N的个数不确定,要求保证每个数字被抽中的概率相等。
解读:这种应用的场景一般是数据流的情况下,由于数据只能被读取一次,而且数据量很大,并不能全部保存,因此数据量N是无法在抽样开始时确定的;但又要保证概率相等。
解决:解决方案就是蓄水池抽样。主要思想就是保持一个集合(这个集合最终的数字就是被抽中的数字)。依次遍历所有数据的时候以一定的概率替换掉这个蓄水池中的数字。
Init : a reservoir with the size: k //初始化蓄水池为前K个数 for i= k+1 to N M=random(1, i); if( M < k) SWAP the Mth value and ith value end for
程序的开始就是把前K个元素都放到水库中,然后对之后的第i个元素,以k/i的概率替换掉这个水库中的某一个元素。