Presentation is loading. Please wait.

Presentation is loading. Please wait.

Design Patterns, Practices, and Techniques with the Azure AppFabric Service Bus Juval Lowy IDesign ©2011 IDesign Inc. All rights reserved.

Similar presentations

Presentation on theme: "Design Patterns, Practices, and Techniques with the Azure AppFabric Service Bus Juval Lowy IDesign ©2011 IDesign Inc. All rights reserved."— Presentation transcript:

1 Design Patterns, Practices, and Techniques with the Azure AppFabric Service Bus Juval Lowy IDesign ©2011 IDesign Inc. All rights reserved

2 About Juval Löwy Software architect Consults and trains on.NET architecture and technology Microsoft's Regional Director for the Silicon Valley Recent book Programming WCF Services 3 rd Edition (2010 OReilly) Participates in the.NET/WCF design reviews Publishes at MSDN and other magazines Recognized Software Legend by Microsoft Contact at

3 Agenda What is the service bus Brief Techniques Publishing to registry Discrete events Discovery Explorer Structured buffers Response service Bonus Material Time permitting

4 Azure AppFabric Service Bus While designed to address connectivity issues also provides Scalability Availability Security Lower technology entrance barrier by making advanced scenario main-stream and mundane

5 Internet connectivity is hard Firewalls Load balancers Sessions NAT Why Service Bus Service H/W Firewall Router LB NAT S/W Firewall Client Private IPs Discovery and registry Virtualization Proxy servers Security IT in general …

6 Why Service Bus Scalability throughput and availability challenges Opening your Intranet Requires DMZ Clients credentials management Commonplace solutions Cumbersome Not real-time Potentially insecure

7 Why Service Bus Solution Do not connect clients to services directly At least not initially Use a relay service Relay service in the cloud Neutral territory Only requires outbound calls to establish connection Allowed in most environments Will relay client calls to service Additional benefits of scalability, security, administration

8 Service Bus Relay Relay Service Client Service Service connects and authenticates against relay Relay figures out how to best call back to service 2. Client connects and authenticates against relay 3. Client sends message to service 4. Relay forwards message to service 3

9 Azure AppFabric Service Bus Ready-made service bus relay service DMZ in the sky Only allows authenticated authorized calls Repels attacks and hides service Relay service in cloud routing messages Microsoft massive data centers Additional features Security Access rules Service registry

10 Relay Service Address Address format [base address]/[optional URI]/.../[optional URI] Bus address format [schema]://[namespace] Schema format is sb or http or https Binding dependent

11 Services Registry Can view ATOM feed of listening services in namespace Or one of its sub URI

12 Services Registry Can control publishing to registry public enum DiscoveryType { Public, Private } public class ServiceRegistrySettings : IEndpointBehavior { public ServiceRegistrySettings(); public ServiceRegistrySettings(DiscoveryType discoveryType); public DiscoveryType DiscoveryMode {get;set;} public string DisplayName {get;set;} }

13 Services Registry Must use programmatic setting IEndpointBehavior registeryBehavior = new ServiceRegistrySettings(DiscoveryType.Public); ServiceHost host = new ServiceHost(typeof(MyService)); foreach(ServiceEndpoint endpoint in host.Description.Endpoints) { endpoint.Behaviors.Add(registeryBehavior); } host.Open();

14 Discoverable Host My DiscoverableServiceHost automates registry Used like regular host public class DiscoverableServiceHost : ServiceHost,IServiceBusProperties { public DiscoverableServiceHost(object singletonInstance,params Uri[] baseAddresses); public DiscoverableServiceHost(Type serviceType,params Uri[] baseAddresses); //More members }

15 IServiceBusProperties All my service bus helpers support my IServiceBusProperties public interface IServiceBusProperties { TransportClientEndpointBehavior Credential {get;set;} Uri[] Addresses {get;} }

16 Service Bus Explorer View with my Service Bus Explorer Can administer buffers as well

17 Service Bus Bindings The three main bindings NetTcpRelayBinding NetOnewayRelayBinding NetEventRelayBinding

18 TCP Relay Binding Binding of choice in most cases Best performance and throughput Minimum overhead for service Unlimited message size Up to configured limits Request-reply messages through relay

19 TCP Relay Binding Multiple clients / single service As with regular WCF Maintains transport session Clients gets the same instance Not interoperable Uses sb for transport

20 One-Way Relay Binding No reply messages All operations must be one-way Message goes into a buffer Messages limited to 64 KB Used sb for scheme

21 Event Relay Binding Specialization of one-way relay Allows any number of services to monitor buffer N:M communication Can safely listen concurrently on nested URIs For whatever reason Clients may still call over NetOnewayRelayBinding Services must use NetEventRelayBinding public class NetEventRelayBinding : NetOnewayRelayBinding {...}

22 Service Bus as Events Hub Events Hub Publisher Subscriber

23 Service Bus as Events Hub Light weight pub/sub system No administrative support No per-operation subscription Endpoint level only

24 Service Bus as Events Hub Subscriber still receives events it may not care about simply because it has a matching endpoint [ServiceContract] interface IMyEvents { [OperationContract(IsOneWay = true)] void OnEvent1(); [OperationContract(IsOneWay = true)] void OnEvent2(int number); [OperationContract(IsOneWay = true)] void OnEvent3(int number,string text); }

25 Service Bus as Events Hub To manage events at the operation level need to map URIs to operations not endpoints

26 Service Bus as Events Hub Have as many hosts as subscribed operations all targeting same service type At run-time must recycle hosts and programmatically add each desired endpoint to specific host Tedious repetitive code Expensive Pay for connections

27 Service Bus as Events Hub Streamline with my ServiceBusEventsHost

28 public class ServiceBusEventsHost : DiscoverableServiceHost { public ServiceBusEventsHost(Type serviceType,Uri baseAddress); public ServiceBusEventsHost(Type serviceType,Uri[] baseAddresses); /*Additional constructors */ //Can optionally specify binding public virtual NetOnewayRelayBinding RelayBinding {get;set;} public void SetBinding(string bindingConfigName); //Subscription management public void Subscribe(); public void Subscribe(Type contractType); public void Subscribe(Type contractType,string operation); public void Unsubscribe(); public void Unsubscribe(Type contractType); public void Unsubscribe(Type contractType,string operation); }

29 Service Bus as Events Hub ServiceBusEventsHost used like regular host Requires base address(es) Appends contract name to each base address Can accept binding to use Defaults for secure binding No need for config file Can look up binding from config Can subscribe or unsubscribe all operations on all contracts Can subscribe or unsubscribe all operations on contract Can subscribe or unsubscribe specific operation on contract

30 [ServiceContract] interface IMyEvents { [OperationContract(IsOneWay = true)] void OnEvent1(); [OperationContract(IsOneWay = true)] void OnEvent2(int number); [OperationContract(IsOneWay = true)] void OnEvent3(int number,string text); } class MySubscriber: IMyEvents {...} string baseAddress = "sb://"; ServiceBusEventsHost host = new ServiceBusEventsHost(typeof(MySubscriber),baseAddress); host.Open(); host.Subscribe(); host.Unsubscribe(typeof(IMyEvents),"OnEvent2"); host.Subscribe(); host.Unsubscribe(); host.Close();

31 Service Bus as Events Hub Subscriptions stored in dictionary Maps subscribed operations per contract Can add admin support Use a tool to manage subscriptions outside scope of host/service Manage subscriptions against host as needed

32 Service Bus as Events Hub ServiceBusEventsHost adds endpoint per base address per contract [base address]/[contract name] Monitors all messages to that address and below Publishers send messages to endpoint whose address contains operation name [base address]/[contract name]/[operation]

33 Service Bus as Events Hub ServiceBusEventsHost uses operation selector interceptor to rout message to subscribed operation Attached as endpoint behavior to all dispatchers public interface IDispatchOperationSelector { string SelectOperation(ref Message message); }

34 //Partial listing without error handling public class ServiceBusEventsHost : ServiceBusHost { //Managing the subscriptions Dictionary > Subscriptions {get;set;} public ServiceBusEventsHost(Type serviceType,Uri[] baseAddresses) : base(serviceType,baseAddresses) { Subscriptions = new Dictionary >(); foreach(Uri baseAddress in BaseAddresses) { Type[] contracts = GetServiceContracts(); foreach(Type contract in contracts) { AddServiceEndpoint(contract,RelayBinding, baseAddress.AbsoluteUri + contract); Subscriptions[contract.Name] = new List (); } IEndpointBehavior selector = new EventSelector(Subscriptions); foreach(ServiceEndpoint endpoint in Description.Endpoints) { endpoint.Behaviors.Add(selector); }

35 public void Subscribe(Type contractType,string operation) { if(Subscriptions[contractType.Name].Contains(operation) == false) { Subscriptions[contractType.Name].Add(operation); } public void Unsubscribe(Type contractType,string operation) { if(Subscriptions[contractType.Name].Contains(operation)) { Subscriptions[contractType.Name].Remove(operation); } //Uses reflection to get all service contracts Type[] GetServiceContracts() {...}

36 class EventSelector : IDispatchOperationSelector,IEndpointBehavior { readonly Dictionary > m_Subscriptions; public EventSelector(Dictionary > subscriptions) { m_Subscriptions = subscriptions; } public string SelectOperation(ref Message message) { string[] slashes = message.Headers.Action.Split('/'); string contract = slashes[slashes.Length-2]; string operation = slashes[slashes.Length-1]; if(m_Subscriptions[contract].Contains(operation)) return operation; else return null; } void IEndpointBehavior.ApplyDispatchBehavior( ServiceEndpoint endpoint,EndpointDispatcher endpointDispatcher) { endpointDispatcher.DispatchRuntime.OperationSelector = this; }... }

37 Service Bus as Events Hub Publisher can use plain one-way relay proxy Careful to match expected endpoints layout Automate proxy with my ServiceBusEventsClientBase Appends contract name and operation to base address No need for config file Only needs base address Always uses one way relay binding Used like regular proxy

38 public abstract class ServiceBusEventsClientBase :...ClientBase where T : class { public ServiceBusEventsClientBase(string baseAddress) : this(baseAddress,new NetOnewayRelayBinding()) {} public ServiceBusEventsClientBase(string baseAddress,NetOnewayRelayBinding binding) : base(binding,ToEventAddress(baseAddress)) {} /* More constructors */ static EndpointAddress ToEventAddress(string baseAddress) { return new EndpointAddress(baseAddress + typeof(T).Name); }

39 Service Bus as Events Hub class MyEventsProxy : ServiceBusEventsClientBase,IMyEvents { public MyEventsProxy(string baseAddress) : base(baseAddress) {} public void OnEvent1() { Channel.OnEvent1(); } public void OnEvent2(int number) { Channel.OnEvent2(number); } public void OnEvent3(int number,string text) { Channel.OnEvent3(number,text); }

40 Discovery

41 Discovery was designed for the Intranet Discovery is useful Loosely-coupled clients and services Dynamic addresses Easy deployment Service bus may support discovery in future

42 Discovery Would be nice to combine benefit of loose deployment of discovery with unhindered connectivity of service bus Can substitute events binding for UDP Discovery requests Announcements Mimic WCF discovery behavior

43 Solution Architecture Streamline with my helpers IServiceBusDiscovery for discovery requests Events relay binding Supported by discoverable services Provides reply address of client [ServiceContract] public interface IServiceBusDiscovery { [OperationContract(IsOneWay = true)] void DiscoveryRequest(string contractName,string contractNamespace, Uri[] scopesToMatch,Uri responseAddress); }

44 Solution Architecture IServiceBusDiscoveryCallback for receiving services responses Exposed by clients Over one-way relay binding [ServiceContract] public interface IServiceBusDiscoveryCallback { [OperationContract(IsOneWay = true)] void DiscoveryResponse(Uri address,string contractName,string contractNamespace, Uri[] scopes); }

45 Discovery Requests Client Service Relay Service Relay Service Relay Service IServiceBusDiscovery IServiceBusDiscoveryCallback Operation Event

46 Discoverable Host My DiscoverableServiceHost Used like regular host To enable must add discovery behavior and discovery endpoint Forward looking and compatible

47 Discoverable Host public class DiscoverableServiceHost : ServiceHost,IServiceBusProperties { public Uri DiscoveryAddress {get;set;} public NetEventRelayBinding DiscoveryRequestBinding {get;set;} public NetOnewayRelayBinding DiscoveryResponseBinding {get;set;} public DiscoverableServiceHost(object singletonInstance,params Uri[] baseAddresses); public DiscoverableServiceHost(Type serviceType,params Uri[] baseAddresses); }

48 Discoverable Host Creates internal host for private service class DiscoveryRequestService implementing IServiceBusDiscovery Monitors discovery requests Address defaults to URI " DiscoveryRequests" Configurable via DiscoveryAddress property Uses plain events binding to receive requests Configurable via DiscoveryRequestBinding property Calls back client using IServiceBusDiscoveryCallback Uses plain one way binding Configurable via DiscoveryResponseBinding property

49 Discoverable Host Uri baseAddress = new Uri("sb://..."); ServiceHost host = new DiscoverableServiceHost(typeof(MyService,baseAddress); //Address is dynamic host.AddServiceEndpoint(typeof(IMyContract),new NetTcpRelayBinding(), Guid.NewGuid().ToString()); host.Open();

50 Discovery Client For client use my ServiceBusDiscoveryClient Modeled after DiscoveryClient public class ServiceBusDiscoveryClient : ClientBase, IServiceBusProperties { protected Uri ResponseAddress {get;} public ServiceBusDiscoveryClient(string serviceNamespace,...); public ServiceBusDiscoveryClient(string endpointName); public ServiceBusDiscoveryClient(NetOnewayRelayBinding binding,EndpointAddress address); public FindResponse Find(FindCriteria criteria); }

51 Discovery Client ServiceBusDiscoveryClient is proxy for IServiceBusDiscovery Defaults address to URI " DiscoveryRequests" Can provide constructors with different address Uses plain one-way binding to fire requests and receive responses Can provide constructors with different binding Supports cardinality and timeouts Find() hosts an internal service supporting IServiceBusDiscoveryCallback Opens and closes host per call

52 Discovery Client string serviceNamespace = "..."; ServiceBusDiscoveryClient discoveryClient = new ServiceBusDiscoveryClient(serviceNamespace,...); FindCriteria criteria = new FindCriteria(typeof(IMyContract)); FindResponse discovered = discoveryClient.Find(criteria); discoveryClient.Close(); EndpointAddress address = discovered.Endpoints[0].Address; Binding binding = new NetTcpRelayBinding(); ChannelFactory factory = new ChannelFactory (binding,address); IMyContract proxy = factory.CreateChannel(); proxy.MyMethod(); (proxy as ICommunicationObject).Close();

53 public static class ServiceBusDiscoveryHelper { public static EndpointAddress DiscoverAddress ( string serviceNamespace,...,Uri scope = null); public static EndpointAddress[] DiscoverAddresses ( string serviceNamespace,...,Uri scope = null); public static Binding DiscoverBinding ( string serviceNamespace,...,Uri scope = null); } Service Bus Discovery Helper Helper class

54 Service Bus Discovery Factory public static class ServiceBusDiscoveryFactory { public static T CreateChannel (string serviceNamespace,...,Uri scope = null) where T : class; public static T[] CreateChannels (string serviceNamespace,...,Uri scope = null) where T : class; } Helper factory

55 Announcements Can use events binding to support announcements My IServiceBusAnnouncements [ServiceContract] public interface IServiceBusAnnouncements { [OperationContract(IsOneWay = true)] void OnHello(Uri address,string contractName,string contractNamespace,Uri[] scopes); [OperationContract(IsOneWay = true)] void OnBye(Uri address,string contractName,string contractNamespace,Uri[] scopes); }

56 Announcements Client Service Relay Service 1 2 IServiceBusAnnouncements Operation Event

57 Announcements Automated with DiscoverableServiceHost public class DiscoverableServiceHost : ServiceHost,IServiceBusProperties { public Uri AnnouncementsAddress {get;set;} public NetOnewayRelayBinding AnnouncementsBinding {get;set;} //More members }

58 Announcements Requires configuring announcements endpoint in discovery behavior Defaults to announcing on " AvailabilityAnnouncements" URI under service namespace Configurable via AnnouncementsAddress property Calls client using plain one way binding Configurable via AnnouncementsBinding property Fires event asynchronously

59 Announcements Client uses my ServiceBusAnnouncementSink [ServiceBehavior(UseSynchronizationContext = false, InstanceContextMode = InstanceContextMode.Single)] public class ServiceBusAnnouncementSink : AnnouncementSink,IServiceBusAnnouncements,IServiceBusProperties where T : class { public ServiceBusAnnouncementSink(string serviceNamespace,string secret); public ServiceBusAnnouncementSink(string serviceNamespace,string owner,string secret); public Uri AnnouncementsAddress {get;set;} public NetEventRelayBinding AnnouncementsBinding {get;set;} }

60 Supports IServiceBusAnnouncements Hosted as singleton published to registry Subscribes to events Defaults to " AvailabilityAnnouncements" URI Configurable via AnnouncementsAddress property Uses plain events binding Configurable via AnnouncementsBinding property Client can subscribe to events or access addresses container Announcements

61 class MyClient { AddressesContainer m_Addresses; public MyClient() { string serviceNamespace = "..."; string secret = "..."; m_Addresses = new ServiceBusAnnouncementSink (serviceNamespace,secret); m_AnnouncementSink.Open();... } void OnCallService(object sender,EventArgs e) { EndpointAddress address = m_Addresses[0]; IMyContract proxy = ChannelFactory.CreateChannel( new NetTcpRelayBinding(),address); proxy.MyMethod(); (proxy as ICommunicationObject).Close(); }...

62 MEX Explorer Revamped to use service bus discovery and announcements

63 Buffers

64 Service Bus Buffers Queued calls over the Internet Almost Every junction in the service bus can host a buffer Sender Reader

65 Service Bus Buffers Buffer does not equate queue Not durable Data loss with catastrophic crash of service bus Not transactional Not long lasting messages Max is 10 minutes Buffers are limited Up to 50 messages In between queued calls and fire-and-forget calls

66 Service Bus Buffers Aimed at Async calls Chunky calls Mostly connected applications on somewhat shaky connections One-way calls Elastic Internet wire

67 Service Bus Buffers All messages are one-way No results No errors No callbacks

68 Service Bus Buffers Can manage and create buffers with the my Explorer

69 Service Bus Buffers Can manage and create buffers with my Explorer

70 Buffered Services The service bus requires working with raw WCF messages Raw messages are Cumbersome Not object-oriented Not type safe Should convert between service calls and raw messages Requires a lot of low level advanced work

71 Buffered Services Automate with my BufferedServiceBusHost Used like a regular host Modeled after MSMQ binding public class BufferedServiceBusHost : ServiceHost,... { public BufferedServiceBusHost(params Uri[] bufferAddresses); public BufferedServiceBusHost(T singleton,params Uri[] bufferAddresses); /* Additional constructors */ } Uri buffer = new ServiceHost host = new BufferedServiceBusHost (buffer); host.Open();

72 Buffered Services For client use BufferedServiceBusClient [ServiceContract] interface IMyContract { [OperationContract(IsOneWay = true)] void MyMethod(int number); } class MyContractClient : BufferedServiceBusClient,IMyContract { public void MyMethod(int number) {... }

73 Response Service No way to get Results Errors Client can provide dedicated response buffer for service Should pass response address and method ID in headers Automate with my framework

74 Response Service Client Service Service Buffer Response Service Response Buffer

75 Bonus Material

76 Service Bus Security

77 Security Aspects Service bus authentication Message transfer security

78 Service Bus Authentication Service must authenticate to connect to service bus Client may or may not authenticate Typically should Application authentication Not user authentication

79 Service Bus Authentication Administrator uses portal to assign and create tokens

80 Service Bus Authentication Tokens both authenticate and authorize Sending messages Reading messages Manage service namespace Service and client may not use the same token

81 Service Bus Authentication Can streamline with my extension method Defaults to owner as issuer public static class ServiceBusHelper { public static void SetServiceBusCredentials(this ServiceHost host,string secret);... } ServiceHost host = new ServiceHost(typeof(MyService)); host.SetServiceBusCredentials("QV3...9M8="); host.Open();

82 public static partial class ServiceBusHelper { public static void SetServiceBusCredentials (this ClientBase proxy, string secret) where T : class; public static void SetServiceBusCredentials ( this ChannelFactory factory,string secret) where T : class;... } MyContractClient proxy = new MyContractClient(); proxy.SetServiceBusCredentials("QV3...9M8="); proxy.MyMethod(); proxy.Close(); Service Bus Authentication Client side

83 Transfer Security Securely transfer the message from client to service What degree of client identity is in the message Four modes for transfer security None Transport Message Mixed public enum EndToEndSecurityMode { None, Transport, Message, TransportWithMessageCredential //Mixed }

84 Transport Security Transfer to relay and from relay is secure TCP uses SSL WS uses HTTPS Simplest and easiest to set up and use Will never contain client's credentials All calls are anonymous

85 Transport Security Journey inside relay is insecure Client Service Secure Insecure

86 Transport Security In theory relay service can Eavesdrop on communication Tamper with messages In practice Impractical given volumes of traffic Microsoft is not the NSA Microsoft has the highest integrity

87 Message Security Transfer to relay and from relay is secure Regardless of transport May require setup steps Installing service certificates in client trusted people folder Modifying client identity address tag Modifying client config file to list certificate

88 Message Security Journey inside relay is secure Client Service Secure Insecure

89 Message Security Relay service cannot Eavesdrop on communication Tamper with messages In practice it is vital to assure customers of end-to-end privacy and integrity I recommends message security for all relayed communication Has additional benefits as well Hybrid Local security context

90 Message Security Message may contain client's credentials For service local authorization Integration with legacy is common scenario too Best practice is for relay service to authenticate and authorize Avoid burden service with unwanted traffic No need for client credentials on service And managing them I recommends message security without client credentials Anonymous towards service When possible

91 Transfer Security Streamlining host with my ServiceBusHost public class ServiceBusHost : DiscoverableServiceHost { public ServiceBusHost(object singletonInstance,params Uri[] baseAddresses); public ServiceBusHost(Type serviceType,params Uri[] baseAddresses); public void ConfigureAnonymousMessageSecurity(); public void ConfigureAnonymousMessageSecurity(string serviceCert); public void ConfigureAnonymousMessageSecurity(string serviceCert, StoreLocation location,StoreName storeName); public void ConfigureAnonymousMessageSecurity(StoreLocation location, StoreName storeName,X509FindType findType,object findValue); //More members }

92 Transfer Security No other setting in config or code Requires certificate for message security Unspecified Reads from config file If cert specified is empty string Will use service namespace for certificate name Defaults location to LocalMachine and My store Will use RM as well ServiceBusHost host = new ServiceBusHost(typeof(MyService)); host.ConfigureAnonymousMessageSecurity("MyServiceCert"); host.Open();

93 Transfer Security Can use my declarative security public enum ServiceSecurity { None, Anonymous, BusinessToBusiness, Internet, Intranet, ServiceBus } [SecurityBehavior(ServiceSecurity.ServiceBus)] class MyService : IMyContract {...} ServiceHost host = new ServiceHost(typeof(MyService)); host.Open();

94 Transfer Security Streamline client with my ServiceBusClientBase Defaults to anonymous message security with service namespace as cert Can specify username creds as well public abstract class ServiceBusClientBase : ClientBase where T : class { public ServiceBusClientBase(); public ServiceBusClientBase(string endpointName); public ServiceBusClientBase(Binding binding,EndpointAddress remoteAddress); public ServiceBusClientBase(string username,string password);... protected virtual void ConfigureForServiceBus(); protected virtual void ConfigureForServiceBus(string username,string password); }

95 Transfer Security [ServiceContract] interface IMyContract { [OperationContract] void MyMethod(); } class MyContractClient : ServiceBusClientBase,IMyContract { public MyContractClient() {} public void MyMethod() { Channel.MyMethod(); }

96 Resources Programming WCF Services 3 rd Edition Juval Löwy, O'Reilly Code library Coding standard Sample architecture report IDesign Method Architects Master Class November 2011

97 More at TechEd Discover a New WCF with Discovery Monday 3:00 PM The Architect Tuesday 8:30 AM

98 Required Slide Speakers, please list the Breakout Sessions, Interactive Discussions, Labs, Demo Stations and Certification Exam that relate to your session. Also indicate when they can find you staffing in the TLC.

99 Required Slide Track PMs will supply the content for this slide, which will be inserted during the final scrub.

100 Resources Sessions On-Demand & CommunityMicrosoft Certification & Training Resources Resources for IT ProfessionalsResources for Developers Connect. Share. Discuss.


102 Required Slide Your MS Tag will be inserted here during the final scrub.


Download ppt "Design Patterns, Practices, and Techniques with the Azure AppFabric Service Bus Juval Lowy IDesign ©2011 IDesign Inc. All rights reserved."

Similar presentations

Ads by Google