发表于: 2017-08-22 19:30:20
2 1037
一.今天完成的事情
1.配置nginx负载均衡
在nginx.conf文件中配置,如图:用两个服务器做负载均衡,采用的策略是轮询策略
2.测试两个服务器做负载均衡时的并发数据
首先是查看性能.
单独测试服务器一的json接口,并发数为200线程
单独测试服务器二的json接口
测试两个服务器做负载均衡结果:
说明使用负载均衡在并发数不是很大的情况下效率还要略低于没有负载均衡的情况
接下来增大并发数量,分别测试了300,400,500,550,600线程时的情况,这里只贴出能够说明情况的
负载均衡情况下500线程并发测试结果:
响应时间不断上升,但是基本上没有出错,服务器也一切正常
负载均衡情况下550线程并发测试结果:
此时开始出现错误,当测试600线程并发时,服务器宕机,说明有负载均衡时能够支持的并发数大概在550线程左右,在请假之前测试过无负载均衡无缓存的json接口的极限大概是280线程,从数据看说明负载均衡大大减轻了单台服务器的压力,使整个项目能够承受更多的线程并发.
3.尝试用负载均衡 + memcached缓存测试接口
依然测试的是json接口
首先是200线程的测试结果
结果TPS的数据比单纯用负载均衡还要小一些
接着分别尝试500线程
以及600线程测试
结果是TPS进一步下降,接着测试650线程时出错率开始上升,说明负载均衡+memcached缓存的极限大概在600线程至650线程之间.但是通过查看项目日志,发现整个controller的执行时间都和少,一般是几毫秒,最大是几十毫秒,说明通过负载均衡降低了缓存的压力,至于TPS值一直不高应该是nginx服务器的性能导致的,因为整个服务器的配置都不高.
4.将memcached换成redis缓存,并使用注解式配置(这一部分实际上是在请假时抽空完成的)
在application-context中配置redis缓存的相关对象
//redis的配置和jdbc的配置相似.该段代码是配置jedis连接池,从上到下依次是最大活动连接数,最大空闲连接数,最小空闲连接数,最大等待时间,使用链接和返回连接时检测是否链接成功
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.pool.maxTotal}"/>
<property name="maxIdle" value="${redis.pool.maxIdle}"/>
<property name="minIdle" value="${redis.pool.minIdle}"/>
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}"/>
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>
<property name="testOnReturn" value="${redis.pool.testOnReturn}"/>
</bean>
//该段代码是配置Jedis链接工厂,通过setter注入的方式实现.从上到下依次是redis服务段ip,端口号,超时时间,验证密码(也可以不设置)
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg index="0" ref="jedisPoolConfig"/>
<property name="hostName" value="${redis.host}"/>
<property name="port" value="${redis.port}"/>
<property name="timeout" value="${redis.timeout}"/>
<property name="password" value="${redis.password}"/>
</bean>
<!-- 生成redis实例 -->
//该段代码是通过Jedis链接工厂生成redis实例,默认采用StringRedisSerializer序列化对象,因为要使用redis必须要将java对象序列化为字节流,所以需要配置序列化类
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"></bean>
</property>
</bean>
//该段代码通过redis实例创建redis缓存管理
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg ref="redisTemplate" />
<property name="defaultExpiration" value="${redis.expiration}"/>
</bean>
//该段代码通过以上的几个对象生成redis缓存配置类
<bean id="redisCacheConfig" class="com.putaoteng.task6.utils.RedisCacheConfig">
<constructor-arg index="0" ref="jedisConnectionFactory"/>
<constructor-arg index="1" ref="redisTemplate"/>
<constructor-arg index="2" ref="cacheManager"/>
</bean>
redis缓存配置类的代码如下:
@Configuration
//标注可以使用注解
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport{
private volatile JedisConnectionFactory jedisConnectionFactory;
private volatile RedisTemplate<String, Object> redisTemplate;
private volatile RedisCacheManager redisCacheManager;
//两个构造方法,一个无参数,一个有参数
public RedisCacheConfig() {
super();
}
public RedisCacheConfig(JedisConnectionFactory jedisConnectionFactory, RedisTemplate<String, Object> redisTemplate,
RedisCacheManager redisCacheManager) {
super();
this.jedisConnectionFactory = jedisConnectionFactory;
this.redisTemplate = redisTemplate;
this.redisCacheManager = redisCacheManager;
}
//这几段代码都是直接返回在xml文件中生成的对象
public JedisConnectionFactory redisConnectionFactory(){
return jedisConnectionFactory;
}
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory cf) {
return redisTemplate;
}
public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate) {
return redisCacheManager;
}
//自定义key生成器
//当使用缓存注解时,使用自定义的key生成器以防混淆
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
然后就可以在需要缓存的方法上面用缓存注解,如:
value属性代表存进redis中的key值.
5.通过测试比较memcached和redis缓存
分别测试200线程,400线程,500线程的数据比较
200线程
memcached
redis
400线程
memcached
redis
500线程
memcached
redis
通过比较可以看到:在并发数和硬件环境相同的情况下,redis的总体响应时间要略优于memcached,但是memcached的TPS性能要更强一些,两者支持的并发数也大致相同,在并发数比较高的情况下,redis的稳定性更强一些.
二.明天计划完成的事情
1.了解缓存穿透,在代码中模拟缓存穿透
2.完成任务中要求的性能测试报告.目前对照报告还没有系统在500ms内返回时的相关数据,明天对此进行测试记录
3.如果有时间,完成任务之后的深度思考
4.重新拆分禅道
三.遇到的问题
暂无
四.收获
对nginx负载均衡以及缓存的理解更加深入.特别是今天发现nginx的性能也会影响到整个项目的性能,说明优化系统不能至追求某个环节的高性能,更要从全局进行考虑,项目的整体性能就像是各个模块拼起来的水桶,决定项目性能的不是最快的那部分,而是最慢的那个部分.
比如之前没有采取负载均衡时,查看日志发现主要耗时是在代码的controller层中,耗时的原因主要是缓存的效率,而今天采用了负载均衡,发现也没有带来很大的性能提升,一开始还以为是负载均衡没有起作用,后来查看日志才发现消耗在controller中的时间很少,最多也就是几十毫秒,再去查看nginx的日志,发现nginx有时转发一个请求竟然会用时近7秒钟,说明此时拖累整个项目性能的不是项目本身,而是nginx服务器的性能.思考背后的原因还是因为服务器的硬件性能太差,没能体现出nginx的强大.这也是今天最大的一个收获吧.
五.进度情况
前面因为个人原因请了10天假,肯定是要延期了.争取在两天内结束任务六
评论