nosql,大規模分佈式緩存遍天下,Internet的時代在中國由其走得前沿,這一切歸功於我國特點的電商。所以nosql、大數據技術在中國應用的比國外還要前沿。從這一章開始咱們將開始進入到真正的SOA、PAAS、SAAS、互聯網的領域,所以每一篇我都會加入一小段業務的基礎知識,讓你們在學習技術的同時也能夠了解一些業務,這邊的業務不是指的business logic不是讓你們去作業務人員,而是爲你們帶來IDEA,」沒有作不到只有想不到「,阿里支付寶爲何發了。。。不是技術,而是它的IDEA。html
14年1月時在上海蔘加過一個MagentoCom召集的電商峯會。會上一羣LAO WAI在那邊大談本身的電商經驗,有LV,有ADIDAS,bla...bla...bla...聽着聽着,真是以爲可笑。休息時隨便問一個LAO WAI一個問題:java
」大家知道什麼叫一元秒殺嗎?「mysql
」大家知道什麼7天無理由退貨嗎?「linux
」大家知道什麼叫0體驗嗎?「git
」大家有沒有雙11,雙12,有沒有交易量過億。。。「程序員
LAO WAI 」張嘴,流哈喇子,billions of transaction? billions「github
看着他這個樣子,我是硬忍住後來到WC一邊抽菸一邊笑,笑得連手上的菸頭都抖了,唉。。。。。。web
不是說國外的電商不這麼幹,而是經濟體制決定了電商的發展道路不一樣,由於國外的電商是基於他們的」信任「式經濟的模式下的,所以國外的電商基本都是信用卡、預先衝款、預售卡、充值卡這些,這也決定了國外沒有什麼1元秒殺。。。這些哄人氣的東東。redis
另一點就是國外人口也少,呵呵,這算是一個理由。spring
還有就是國外基本無」不是名牌「這一說,記得去法國onsite交流學習時,若是你穿的一件ADIDAS或者是NIKE或者是阿瑪尼若是不是正宗名牌,是仿的話也會被警察抓住罰款,所以國外是個商品基本都有牌子。這是一種」互信「機制。
中國的電商雖然也是走線上、線下可是它多了一個」第三方資金委託「即支付寶、易寶、微信(微信是後起之秀)這種東東,所以這樣的體制決定了」先驗貨,後付錢「的這種遊戲規則。
加上中國人多,這下大數據、NOSQL、分佈式這些技術固然成爲了通向internet的重中之重了。
Redis是一個NOSQL,NOSQL有許多種,它們分爲:
光知道這些NOSQL的名詞是沒有用的,關鍵在於要知道在哪一種場景下選用哪一種NOSQL纔是咱們真正要去掌握的。
咱們這邊說Redis就拿Redis說事吧,它能幹什麼呢?
docker@boot2docker:~$ docker run hello-world
Hello from Docker. This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the 「hello-world」 image from the Docker Hub. (Assuming it was not already locally available.) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash For more examples and ideas, visit: http://docs.docker.com/userguide/
cat ubuntu-14.04-x86_64.tar.gz |docker import - ubuntu:ubuntu14
這個過程會很快,完成後查看本身的image:
成功導入了ubuntu,這樣咱們就能夠在docker中運行出一個本身的ubuntu了。
docker run -i -t ubuntu:ubuntu14 /bin/bash
以上運行後,進入了該ubuntu的bash環境。
注:若是上述命令出錯,可使用下面這條命令:
docker run -i -t ubuntu:ubuntu14 //bin/bash
兩個 「/」 哈
若是你能看到相似於root@ubuntu14_這樣的命令行界面說明你的ubuntu14也已經安裝成功了,下面咱們就要在這個docker->ubuntu14中安裝和佈署咱們的Redis了,這個過程和在linux下同樣。
在ubuntu14下先安裝SSHD,以便於咱們使用WINSCP這樣的SFTP工具來管理咱們的ubuntu14中的文件系統
docker run -t -i ubuntu/mk:v1 /bin/bash
第二步:
升級一下你的apt-get,它就是一個命令行IE下載工具,若是你不update,那麼你apt-get的源、內核都爲舊的,所以爲了升級apt-get請鍵入下面的命令
apt-get update
第三步:
下載和安裝openssh組件
apt-get install openssh-server openssh-client
修改你的root密碼
passwd
第五步:
退出容器,並保存以上修改,若是docker在退出後你接着退出docker環境或者是關機那麼剛纔的4步所有不生效,你必定要commit它才能生效,爲此:
docker ps -a來查到你latest的一次容器的ID,它是一組16進制同樣的編碼如:1edfb9aabde8890,有了這個container id咱們就能夠commit咱們剛纔裝的openssh的環境了
docker commit 1edfb9aabde8890 ubuntu:ssh
運行帶有openssh的ubuntu14以便於咱們使用winscp這樣的SFTP工具連入咱們的ubuntu14中去,依次輸入下面的命令:
docker kill $(docker ps -q)
docker rm $(docker ps -a -q)
Docker是這樣的機制的,它能夠開啓多個容器,每一個容器帶着一堆的image(鏡像),要刪一個鏡像必須先中止這個鏡像所在的容器,再把這個鏡像刪除,所以咱們使用上面這兩條命令對於Docker來一個大掃除。
接着咱們先查一下咱們目前手頭有的鏡像
docker images你會看到一個images列表,裏面有咱們的ubuntu:14,有咱們的ubuntu:ssh也有一個hello-world,咱們把ubuntu:14這個鏡像刪了吧(爲了保持乾淨哈)
每一個image也它本身的id,即image id,所以你用docker images命令查到該鏡像的id後可使用:
docker rmi imageid這條命令把一個不用的鏡像給刪了。
接下去咱們要啓動咱們的ubuntu14:ssh了,可使用下面這條命令:
docker -d -p 122:22 ubuntu:ssh //usr/sbin/sshd -D
網上不少在ubuntu14下安裝redis的教程都不對的,你們看了要上當的,緣由在於以下,請各位看完:
就是用的這個redis-stable.tar.gz包,這是我在寫博客時目前最新最穩定版本,修復了大量的BUG和完善了功能。
第二步:
下載後咱們把該包上傳到咱們的docker中的ubuntu14中,咱們把它放在/opt目錄下
而後咱們使用tar -zxvf redis-stable.tar.gz對它進行解壓
解壓後它就會生成一個redis-stable目錄,進入該目錄 cd redis-stable
別急,咱們先一會編譯和安裝它
第三步:編譯安裝redis
咱們先輸入gcc -v 這個命令來查看咱們的gcc版本,若是它低於4.2如下那麼你在編譯redis3.0.7時必定會碰到大量的出錯信息,如前面所述,redis爲gcc寫成,最新的redis須要gcc4.2-5這個版本才能進行編譯,而通常去年或者以前裝的linux/unix 的 gcc都爲4.0如下或者甚至是3.x版。
升級GCC先
apt-get install build-essential
升級後咱們開始編譯redis3.0.7了,爲此咱們須要在redis-stable目錄下
鍵入以下命令:
make PREFIX=/usr/local/redis1 install
咱們告知咱們的GCC把redis-stable編譯並同時安裝在/usr/local/redis1目錄下
這個過程很快,可能只有10秒鐘時間(依據你的機器來講,建議使用>=8gb, 4核CPU的PC機),而後咱們就能夠看到everything ok了。咱們進入/usr/local/redis1就能夠看到咱們剛纔安裝的redis3.0.7穩定版了。
咱們進入咱們的redis目錄 cd /usr/local/redis1/bin
在此目錄下咱們便可以運行咱們的redis server了,不過請別急,在啓動前咱們須要對redis進行一些配置。
個人博客面對的是「全棧式」工程師的,架構師只是成爲全棧式工程師中的一個起點,若是你不會搭環境那麼你就不能接觸到最新的技術,所以這就是許多程序員工做了近5年,7年結果發覺也只會一個SSH的主要緣由。
daemonize yes # When running daemonized, Redis writes a pid file in /var/run/redis.pid by # default. You can specify a custom pid file location here. pidfile "/var/run/redis/redis1.pid" # Accept connections on the specified port, default is 6379. # If port 0 is specified Redis will not listen on a TCP socket. port 7001咱們把:
save 900 1 save 300 10 save 60 10000中的300 10 和60 10000註釋掉。這邊表明的是:
docker -d -p 122:22 -p 7001:7001 redis:basic //usr/sbin/sshd -D
好了,用putty連入這個image的進程並啓動redis服務,而後咱們拿windows中的redis-cli命令來連。
若是在linux環境下仍是沒有連通(可能的哦),那是由於你沒有禁用linux下的防火牆,咱們可使用iptables -F來禁用linux的防火牆或者使用:
vi /etc/selinux/config
而後把
SELINUX=enforcing 這句用」#「註釋掉
增長一句: SELINUX=disabled #增長
這樣每次啓動後linux都不會有iptables的困擾了(這是在本機環境下這麼幹哦,若是你是生產環境請自行加iptables策略以容許redis服務端口能夠被訪問)。
看到下面這個PONG即表明你的redis服務已經在網絡環境中起效了。
下面咱們要開始使用JAVA客戶端來連咱們的Redis Service了。
在此咱們須要使用spring data和jedis,下面給出相關的maven配置
<dependencies> <!-- poi start --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>${poi_version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>${poi_version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>${poi_version}</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>${poi_version}</version> </dependency> <!-- poi end --> <!-- active mq start --> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-all</artifactId> <version>5.8.0</version> </dependency> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-pool</artifactId> <version>${activemq_version}</version> </dependency> <dependency> <groupId>org.apache.xbean</groupId> <artifactId>xbean-spring</artifactId> <version>3.16</version> </dependency> <!-- active mq end --> <!-- servlet start --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>${javax.servlet-api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- servlet end --> <!-- redis start --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.2</version> </dependency> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>1.0.2</version> </dependency> <!-- redis end --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <!-- spring conf start --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> <version>${spring.session.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <!-- spring conf end --> </dependencies>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:/spring/redis.properties" /> <context:component-scan base-package="org.sky.redis"> </context:component-scan> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host.ip}" /> <property name="port" value="${redis.host.port}" /> <property name="poolConfig" ref="jedisPoolConfig" /> </bean> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.maxTotal}" /> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxWaitMillis" value="${redis.maxWait}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> <property name="testOnReturn" value="${redis.testOnReturn}" /> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> </bean> <!--將session放入redis --> <bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"> <property name="maxInactiveIntervalInSeconds" value="1800" /> </bean> <bean id="customExceptionHandler" class="sample.MyHandlerExceptionResolver" /> </beans>
redis.host.ip=192.168.0.101 redis.host.port=6379 redis.maxTotal=1000 redis.maxIdle=100 redis.maxWait=2000 redis.testOnBorrow=false redis.testOnReturn=true
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- - Location of the XML file that defines the root application context - Applied by ContextLoaderListener. --> <!-- tag::context-param[] --> <context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:/spring/redis-conf.xml </param-value> </context-param> <!-- end::context-param[] --> <!-- tag::springSessionRepositoryFilter[] --> <filter> <filter-name>springSessionRepositoryFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSessionRepositoryFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <session-config> <session-timeout>30</session-timeout> </session-config> <!-- end::springSessionRepositoryFilter[] --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/spring/spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- - Loads the root application context of this web app at startup. - The application context is then available via - WebApplicationContextUtils.getWebApplicationContext(servletContext). --> <!-- tag::listeners[] --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- end::listeners[] --> <servlet> <servlet-name>sessionServlet</servlet-name> <servlet-class>sample.SessionServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>sessionServlet</servlet-name> <url-pattern>/servlet/session</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
這邊主要是一個:
<filter> <filter-name>springSessionRepositoryFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSessionRepositoryFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <session-config> <session-timeout>30</session-timeout> </session-config>這個filter必定要寫在一切filter以前
package sample; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * Created by mk on 15/1/7. */ @Controller @EnableRedisHttpSession public class SessionController { @RequestMapping("/mySession") public String index(final Model model, final HttpServletRequest request) { if (request.getSession().getAttribute("testSession") == null) { System.out.println("session is null"); request.getSession().setAttribute("testSession", "yeah"); } else { System.out.println("not null"); } return "showSession"; } }
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>showSession</title> </head> <body> <% String sessionValue=(String)session.getAttribute("testSession"); %> <h1>Session Value From Servlet is: <%=sessionValue%></h1> </body> </html>
保證咱們的redise-server是啓動的,而後咱們啓動起這個web工程後使用:
http://localhost:8080/webpoc/mySession訪問一下這個controller
此時咱們使用redis客戶端工具連入查看spring session是否已經進入到了redis中去。
在redis客戶端工具連入後咱們能夠在redis console中使用keys *來查看存入的key,LOOK,spring的session存入了redis中去了。
再來看咱們的eclipse後臺,因爲咱們是第一次訪問這個controller,所以這個session爲空,所以它顯示以下:
咱們在IE中再次訪問該controller
因爲以前的session已經存在於redis了,所以當用戶在1800秒(30分鐘)內再次訪問controller,它會從session中獲取該session的key testSession的值,所以eclipse後臺打印爲not null。
講過了spring session+redis咱們來說使用spring data框架提供的redisTemplate來訪問redis service吧。說實話,spring這個東西真強,什麼均可以集成,cassandra, jms, jdbc...jpa...bla...bla...bla...Spring集成Barack Hussein Obama? LOL :)
不用列了,上面有了
不用列了,上面有了
也不用列了,上面也有了
package sample; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.redis.core.BoundHashOperations; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisSentinelPool; import util.CountCreater; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; /** * Created by xin on 15/1/7. */ @Controller public class SentinelController { @Autowired private StringRedisTemplate redisTemplate; @RequestMapping("/sentinelTest") public String sentinelTest(final Model model, final HttpServletRequest request, final String action) { return "sentinelTest"; } @ExceptionHandler(value = { java.lang.Exception.class }) @RequestMapping("/setValueToRedis") public String setValueToRedis(final Model model, final HttpServletRequest request, final String action) throws Exception { CountCreater.setCount(); String key = String.valueOf(CountCreater.getCount()); Map mapValue = new HashMap(); for (int i = 0; i < 1000; i++) { mapValue.put(String.valueOf(i), String.valueOf(i)); } try { BoundHashOperations<String, String, String> boundHashOperations = redisTemplate .boundHashOps(key); boundHashOperations.putAll(mapValue); System.out.println("put key into redis"); } catch (Exception e) { e.printStackTrace(); throw new Exception(e); } return "sentinelTest"; } }
觀察咱們的後臺
而後使用redis client連入後進行查看
看。。。這個值key=1的,就是咱們經過spring的redisTemplate存入進去的值,即便用下面這段代碼進行存入的值:
for (int i = 0; i < 1000; i++) { mapValue.put(String.valueOf(i), String.valueOf(i)); } try { BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps(key); boundHashOperations.putAll(mapValue);
redisTemplate.execute(new RedisCallback<Object>() { @Override public Object doInRedis(RedisConnection connection) throws DataAccessException { connection.set( redisTemplate.getStringSerializer().serialize( "test"), redisTemplate .getStringSerializer() .serialize("hello")); return null; } });是否是很方便的哈?結束第一天的教程,明天開始搭建redis集羣。